Added SortableJS Library, and updated Invoice, Quote and Recurring to use it. Added Grab Bar Icons next to action buttons. Will now sort in Mobile much more efficiently, update ajax vars for recurring invoice
This commit is contained in:
4
ajax.php
4
ajax.php
@@ -586,13 +586,13 @@ if (isset($_POST['update_recurring_invoice_items_order'])) {
|
||||
enforceUserPermission('module_sales', 2);
|
||||
|
||||
$positions = $_POST['positions'];
|
||||
$recurring_id = intval($_POST['recurring_id']);
|
||||
$recurring_invoice_id = intval($_POST['recurring_invoice_id']);
|
||||
|
||||
foreach ($positions as $position) {
|
||||
$id = intval($position['id']);
|
||||
$order = intval($position['order']);
|
||||
|
||||
mysqli_query($mysqli, "UPDATE invoice_items SET item_order = $order WHERE item_recurring_id = $recurring_id AND item_id = $id");
|
||||
mysqli_query($mysqli, "UPDATE invoice_items SET item_order = $order WHERE item_recurring_invoice_id = $recurring_invoice_id AND item_id = $id");
|
||||
}
|
||||
|
||||
// return a response
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.grab-cursor {
|
||||
cursor: grab;
|
||||
button.drag-handle {
|
||||
cursor: grab !important;
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.grab-cursor:active {
|
||||
cursor: grabbing;
|
||||
button.drag-handle:active {
|
||||
cursor: grabbing !important;
|
||||
}
|
||||
50
invoice.php
50
invoice.php
@@ -165,6 +165,7 @@ if (isset($_GET['invoice_id'])) {
|
||||
|
||||
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" href="plugins/dragula/dragula.min.css">
|
||||
|
||||
<ol class="breadcrumb d-print-none">
|
||||
@@ -381,6 +382,13 @@ if (isset($_GET['invoice_id'])) {
|
||||
<tr data-item-id="<?php echo $item_id; ?>">
|
||||
<td class="d-print-none">
|
||||
<?php if ($invoice_status !== "Paid" && $invoice_status !== "Cancelled") { ?>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-light drag-handle">
|
||||
<i class="fas fa-bars text-muted"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-light" type="button" data-toggle="dropdown">
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
@@ -397,10 +405,11 @@ if (isset($_GET['invoice_id'])) {
|
||||
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_invoice_item=<?php echo $item_id; ?>"><i class="fa fa-fw fa-trash mr-2"></i>Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td class="grab-cursor"><?php echo $item_name; ?></td>
|
||||
<td><?php echo $item_name; ?></td>
|
||||
<td><?php echo nl2br($item_description); ?></td>
|
||||
<td class="text-center"><?php echo number_format($item_quantity, 2); ?></td>
|
||||
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $item_price, $invoice_currency_code); ?></td>
|
||||
@@ -1178,38 +1187,23 @@ require_once "includes/footer.php";
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="plugins/dragula/dragula.min.js"></script>
|
||||
<script src="plugins/SortableJS/Sortable.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var container = $('table#items tbody')[0];
|
||||
|
||||
dragula([container])
|
||||
.on('drop', function (el, target, source, sibling) {
|
||||
// Handle the drop event to update the order in the database
|
||||
var rows = $(container).children();
|
||||
var positions = rows.map(function(index, row) {
|
||||
return {
|
||||
id: $(row).data('itemId'),
|
||||
new Sortable(document.querySelector('table#items tbody'), {
|
||||
handle: '.drag-handle',
|
||||
animation: 150,
|
||||
onEnd: function (evt) {
|
||||
const rows = document.querySelectorAll('table#items tbody tr');
|
||||
const positions = Array.from(rows).map((row, index) => ({
|
||||
id: row.dataset.itemId,
|
||||
order: index
|
||||
};
|
||||
}).get();
|
||||
}));
|
||||
|
||||
// Send the new order to the server
|
||||
$.ajax({
|
||||
url: 'ajax.php',
|
||||
method: 'POST',
|
||||
data: {
|
||||
$.post('ajax.php', {
|
||||
update_invoice_items_order: true,
|
||||
invoice_id: <?php echo $invoice_id; ?>,
|
||||
positions: positions
|
||||
},
|
||||
success: function(data) {
|
||||
// Handle success
|
||||
},
|
||||
error: function(error) {
|
||||
console.error('Error updating order:', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
2
plugins/SortableJS/Sortable.min.js
vendored
Normal file
2
plugins/SortableJS/Sortable.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
49
quote.php
49
quote.php
@@ -326,6 +326,14 @@ if (isset($_GET['quote_id'])) {
|
||||
<tr data-item-id="<?php echo $item_id; ?>">
|
||||
<td class="d-print-none">
|
||||
<?php if ($quote_status !== "Invoiced" && $quote_status !== "Accepted" && $quote_status !== "Declined" && lookupUserPermission("module_sales") >= 2) { ?>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-light drag-handle">
|
||||
<i class="fas fa-bars text-muted"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-light" type="button" data-toggle="dropdown">
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
@@ -344,9 +352,11 @@ if (isset($_GET['quote_id'])) {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td class="grab-cursor"><?php echo $item_name; ?></td>
|
||||
<td><?php echo $item_name; ?></td>
|
||||
<td><?php echo nl2br($item_description); ?></td>
|
||||
<td class="text-center"><?php echo number_format($item_quantity, 2); ?></td>
|
||||
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $item_price, $quote_currency_code); ?></td>
|
||||
@@ -992,38 +1002,23 @@ require_once "includes/footer.php";
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="plugins/dragula/dragula.min.js"></script>
|
||||
<script src="plugins/SortableJS/Sortable.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var container = $('table#items tbody')[0];
|
||||
|
||||
dragula([container])
|
||||
.on('drop', function (el, target, source, sibling) {
|
||||
// Handle the drop event to update the order in the database
|
||||
var rows = $(container).children();
|
||||
var positions = rows.map(function(index, row) {
|
||||
return {
|
||||
id: $(row).data('itemId'),
|
||||
new Sortable(document.querySelector('table#items tbody'), {
|
||||
handle: '.drag-handle',
|
||||
animation: 150,
|
||||
onEnd: function (evt) {
|
||||
const rows = document.querySelectorAll('table#items tbody tr');
|
||||
const positions = Array.from(rows).map((row, index) => ({
|
||||
id: row.dataset.itemId,
|
||||
order: index
|
||||
};
|
||||
}).get();
|
||||
}));
|
||||
|
||||
// Send the new order to the server
|
||||
$.ajax({
|
||||
url: 'ajax.php',
|
||||
method: 'POST',
|
||||
data: {
|
||||
$.post('ajax.php', {
|
||||
update_quote_items_order: true,
|
||||
quote_id: <?php echo $quote_id; ?>,
|
||||
positions: positions
|
||||
},
|
||||
success: function(data) {
|
||||
// Handle success
|
||||
},
|
||||
error: function(error) {
|
||||
console.error('Error updating order:', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -272,6 +272,14 @@ if (isset($_GET['recurring_invoice_id'])) {
|
||||
|
||||
<tr data-item-id="<?php echo $item_id; ?>">
|
||||
<td class="d-print-none">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-light drag-handle">
|
||||
<i class="fas fa-bars text-muted"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-light" type="button" data-toggle="dropdown">
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
@@ -286,12 +294,12 @@ if (isset($_GET['recurring_invoice_id'])) {
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_recurring_invoice_item=<?php echo $item_id; ?>"><i class="fa fa-fw fa-trash mr-2"></i>Delete</a>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="grab-cursor"><?php echo $item_name; ?></td>
|
||||
<td><?php echo $item_name; ?></td>
|
||||
<td><?php echo nl2br($item_description); ?></td>
|
||||
<td class="text-center"><?php echo $item_quantity; ?></td>
|
||||
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $item_price, $recurring_invoice_currency_code); ?></td>
|
||||
@@ -483,39 +491,23 @@ require_once "includes/footer.php";
|
||||
});
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="plugins/dragula/dragula.min.css">
|
||||
<script src="plugins/dragula/dragula.min.js"></script>
|
||||
<script src="plugins/SortableJS/Sortable.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var container = $('table#items tbody')[0];
|
||||
|
||||
dragula([container])
|
||||
.on('drop', function (el, target, source, sibling) {
|
||||
// Handle the drop event to update the order in the database
|
||||
var rows = $(container).children();
|
||||
var positions = rows.map(function(index, row) {
|
||||
return {
|
||||
id: $(row).data('itemId'),
|
||||
new Sortable(document.querySelector('table#items tbody'), {
|
||||
handle: '.drag-handle',
|
||||
animation: 150,
|
||||
onEnd: function (evt) {
|
||||
const rows = document.querySelectorAll('table#items tbody tr');
|
||||
const positions = Array.from(rows).map((row, index) => ({
|
||||
id: row.dataset.itemId,
|
||||
order: index
|
||||
};
|
||||
}).get();
|
||||
}));
|
||||
|
||||
// Send the new order to the server
|
||||
$.ajax({
|
||||
url: 'ajax.php',
|
||||
method: 'POST',
|
||||
data: {
|
||||
$.post('ajax.php', {
|
||||
update_recurring_invoice_items_order: true,
|
||||
recurring_invoice_id: <?php echo $recurring_invoice_id; ?>,
|
||||
positions: positions
|
||||
},
|
||||
success: function(data) {
|
||||
// Handle success
|
||||
},
|
||||
error: function(error) {
|
||||
console.error('Error updating order:', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user