moving items

This commit is contained in:
Andreas Knuth 2026-02-02 18:00:03 -06:00
parent eef316402c
commit 6ca98dabd2
1 changed files with 97 additions and 27 deletions

View File

@ -411,18 +411,39 @@ function addQuoteItem(item = null) {
itemDiv.innerHTML = ` itemDiv.innerHTML = `
<!-- Accordion Header --> <!-- Accordion Header -->
<div @click="open = !open" class="flex items-center justify-between p-4 cursor-pointer hover:bg-gray-50"> <div class="flex items-center p-4">
<div class="flex items-center space-x-4 flex-1"> <!-- Move Buttons (Left) - Outside accordion click area -->
<svg x-show="!open" class="w-5 h-5 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <div class="flex flex-col mr-3" onclick="event.stopPropagation()">
<button type="button" onclick="moveQuoteItemUp(${itemId})"
class="text-blue-600 hover:text-blue-800 text-lg leading-none mb-1"
title="Move Up">
</button>
<button type="button" onclick="moveQuoteItemDown(${itemId})"
class="text-blue-600 hover:text-blue-800 text-lg leading-none"
title="Move Down">
</button>
</div>
<!-- Accordion Toggle & Content (Center) -->
<div @click="open = !open" class="flex items-center flex-1 cursor-pointer hover:bg-gray-50 rounded px-3 py-2">
<svg x-show="!open" class="w-5 h-5 text-gray-500 mr-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg> </svg>
<svg x-show="open" class="w-5 h-5 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg x-show="open" class="w-5 h-5 text-gray-500 mr-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" />
</svg> </svg>
<span class="text-sm font-medium">Qty: <span class="item-qty-preview">${previewQty}</span></span> <span class="text-sm font-medium">Qty: <span class="item-qty-preview">${previewQty}</span></span>
<span class="text-sm text-gray-600 flex-1 truncate item-desc-preview">${previewDesc}</span> <span class="text-sm text-gray-600 flex-1 truncate mx-4 item-desc-preview">${previewDesc}</span>
<span class="text-sm font-semibold item-amount-preview">${previewAmount}</span> <span class="text-sm font-semibold item-amount-preview">${previewAmount}</span>
</div> </div>
<!-- Delete Button (Right) - Outside accordion click area -->
<button type="button" onclick="removeQuoteItem(${itemId}); event.stopPropagation();"
class="ml-3 px-3 py-2 bg-red-500 hover:bg-red-600 text-white rounded-md text-sm">
×
</button>
</div> </div>
<!-- Accordion Content --> <!-- Accordion Content -->
@ -434,7 +455,7 @@ function addQuoteItem(item = null) {
value="${item ? item.quantity : ''}" value="${item ? item.quantity : ''}"
class="quote-item-input w-full px-2 py-2 border border-gray-300 rounded-md text-sm"> class="quote-item-input w-full px-2 py-2 border border-gray-300 rounded-md text-sm">
</div> </div>
<div class="col-span-5"> <div class="col-span-6">
<label class="block text-xs font-medium text-gray-700 mb-1">Description</label> <label class="block text-xs font-medium text-gray-700 mb-1">Description</label>
<div data-item="${itemId}" data-field="description" <div data-item="${itemId}" data-field="description"
class="quote-item-description-editor border border-gray-300 rounded-md bg-white" class="quote-item-description-editor border border-gray-300 rounded-md bg-white"
@ -447,18 +468,12 @@ function addQuoteItem(item = null) {
value="${item ? item.rate : ''}" value="${item ? item.rate : ''}"
class="quote-item-input w-full px-2 py-2 border border-gray-300 rounded-md text-sm"> class="quote-item-input w-full px-2 py-2 border border-gray-300 rounded-md text-sm">
</div> </div>
<div class="col-span-2"> <div class="col-span-3">
<label class="block text-xs font-medium text-gray-700 mb-1">Amount</label> <label class="block text-xs font-medium text-gray-700 mb-1">Amount</label>
<input type="text" data-item="${itemId}" data-field="amount" <input type="text" data-item="${itemId}" data-field="amount"
value="${item ? item.amount : ''}" value="${item ? item.amount : ''}"
class="quote-item-amount w-full px-2 py-2 border border-gray-300 rounded-md text-sm"> class="quote-item-amount w-full px-2 py-2 border border-gray-300 rounded-md text-sm">
</div> </div>
<div class="col-span-1 flex items-end">
<button type="button" onclick="removeQuoteItem(${itemId})"
class="w-full px-2 py-2 bg-red-500 hover:bg-red-600 text-white rounded-md text-sm">
×
</button>
</div>
</div> </div>
</div> </div>
`; `;
@ -539,6 +554,26 @@ function removeQuoteItem(itemId) {
updateQuoteTotals(); updateQuoteTotals();
} }
function moveQuoteItemUp(itemId) {
const item = document.getElementById(`quote-item-${itemId}`);
const prevItem = item.previousElementSibling;
if (prevItem) {
item.parentNode.insertBefore(item, prevItem);
updateQuoteTotals();
}
}
function moveQuoteItemDown(itemId) {
const item = document.getElementById(`quote-item-${itemId}`);
const nextItem = item.nextElementSibling;
if (nextItem) {
item.parentNode.insertBefore(nextItem, item);
updateQuoteTotals();
}
}
function updateQuoteTotals() { function updateQuoteTotals() {
const items = getQuoteItems(); const items = getQuoteItems();
const taxExempt = document.getElementById('quote-tax-exempt').checked; const taxExempt = document.getElementById('quote-tax-exempt').checked;
@ -786,18 +821,39 @@ function addInvoiceItem(item = null) {
itemDiv.innerHTML = ` itemDiv.innerHTML = `
<!-- Accordion Header --> <!-- Accordion Header -->
<div @click="open = !open" class="flex items-center justify-between p-4 cursor-pointer hover:bg-gray-50"> <div class="flex items-center p-4">
<div class="flex items-center space-x-4 flex-1"> <!-- Move Buttons (Left) - Outside accordion click area -->
<svg x-show="!open" class="w-5 h-5 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <div class="flex flex-col mr-3" onclick="event.stopPropagation()">
<button type="button" onclick="moveInvoiceItemUp(${itemId})"
class="text-blue-600 hover:text-blue-800 text-lg leading-none mb-1"
title="Move Up">
</button>
<button type="button" onclick="moveInvoiceItemDown(${itemId})"
class="text-blue-600 hover:text-blue-800 text-lg leading-none"
title="Move Down">
</button>
</div>
<!-- Accordion Toggle & Content (Center) -->
<div @click="open = !open" class="flex items-center flex-1 cursor-pointer hover:bg-gray-50 rounded px-3 py-2">
<svg x-show="!open" class="w-5 h-5 text-gray-500 mr-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg> </svg>
<svg x-show="open" class="w-5 h-5 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg x-show="open" class="w-5 h-5 text-gray-500 mr-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" />
</svg> </svg>
<span class="text-sm font-medium">Qty: <span class="item-qty-preview">${previewQty}</span></span> <span class="text-sm font-medium">Qty: <span class="item-qty-preview">${previewQty}</span></span>
<span class="text-sm text-gray-600 flex-1 truncate item-desc-preview">${previewDesc}</span> <span class="text-sm text-gray-600 flex-1 truncate mx-4 item-desc-preview">${previewDesc}</span>
<span class="text-sm font-semibold item-amount-preview">${previewAmount}</span> <span class="text-sm font-semibold item-amount-preview">${previewAmount}</span>
</div> </div>
<!-- Delete Button (Right) - Outside accordion click area -->
<button type="button" onclick="removeInvoiceItem(${itemId}); event.stopPropagation();"
class="ml-3 px-3 py-2 bg-red-500 hover:bg-red-600 text-white rounded-md text-sm">
×
</button>
</div> </div>
<!-- Accordion Content --> <!-- Accordion Content -->
@ -809,7 +865,7 @@ function addInvoiceItem(item = null) {
value="${item ? item.quantity : ''}" value="${item ? item.quantity : ''}"
class="invoice-item-input w-full px-2 py-2 border border-gray-300 rounded-md text-sm"> class="invoice-item-input w-full px-2 py-2 border border-gray-300 rounded-md text-sm">
</div> </div>
<div class="col-span-5"> <div class="col-span-6">
<label class="block text-xs font-medium text-gray-700 mb-1">Description</label> <label class="block text-xs font-medium text-gray-700 mb-1">Description</label>
<div data-item="${itemId}" data-field="description" <div data-item="${itemId}" data-field="description"
class="invoice-item-description-editor border border-gray-300 rounded-md bg-white" class="invoice-item-description-editor border border-gray-300 rounded-md bg-white"
@ -822,18 +878,12 @@ function addInvoiceItem(item = null) {
value="${item ? item.rate : ''}" value="${item ? item.rate : ''}"
class="invoice-item-input w-full px-2 py-2 border border-gray-300 rounded-md text-sm"> class="invoice-item-input w-full px-2 py-2 border border-gray-300 rounded-md text-sm">
</div> </div>
<div class="col-span-2"> <div class="col-span-3">
<label class="block text-xs font-medium text-gray-700 mb-1">Amount</label> <label class="block text-xs font-medium text-gray-700 mb-1">Amount</label>
<input type="text" data-item="${itemId}" data-field="amount" <input type="text" data-item="${itemId}" data-field="amount"
value="${item ? item.amount : ''}" value="${item ? item.amount : ''}"
class="invoice-item-amount w-full px-2 py-2 border border-gray-300 rounded-md text-sm"> class="invoice-item-amount w-full px-2 py-2 border border-gray-300 rounded-md text-sm">
</div> </div>
<div class="col-span-1 flex items-end">
<button type="button" onclick="removeInvoiceItem(${itemId})"
class="w-full px-2 py-2 bg-red-500 hover:bg-red-600 text-white rounded-md text-sm">
×
</button>
</div>
</div> </div>
</div> </div>
`; `;
@ -914,6 +964,26 @@ function removeInvoiceItem(itemId) {
updateInvoiceTotals(); updateInvoiceTotals();
} }
function moveInvoiceItemUp(itemId) {
const item = document.getElementById(`invoice-item-${itemId}`);
const prevItem = item.previousElementSibling;
if (prevItem) {
item.parentNode.insertBefore(item, prevItem);
updateInvoiceTotals();
}
}
function moveInvoiceItemDown(itemId) {
const item = document.getElementById(`invoice-item-${itemId}`);
const nextItem = item.nextElementSibling;
if (nextItem) {
item.parentNode.insertBefore(nextItem, item);
updateInvoiceTotals();
}
}
function updateInvoiceTotals() { function updateInvoiceTotals() {
const items = getInvoiceItems(); const items = getInvoiceItems();
const taxExempt = document.getElementById('invoice-tax-exempt').checked; const taxExempt = document.getElementById('invoice-tax-exempt').checked;