Frontend Changes

This commit is contained in:
Utkarsh Khedkar
2026-02-28 11:00:48 +05:30
parent 599023166a
commit c11467068c
6 changed files with 321 additions and 37 deletions

View File

@@ -1683,6 +1683,11 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
});
</script>
@endsection

View File

@@ -875,5 +875,29 @@ document.addEventListener("DOMContentLoaded", function () {
});
});
});
document.addEventListener('DOMContentLoaded', function() {
const invoiceDateInput = document.querySelector('input[name="invoice_date"]');
const dueDateInput = document.querySelector('input[name="due_date"]');
if (invoiceDateInput && dueDateInput) {
invoiceDateInput.addEventListener('change', function() {
const selectedDate = new Date(this.value);
if (!isNaN(selectedDate.getTime())) {
// १० दिवस पुढे नेण्यासाठी logic
selectedDate.setDate(selectedDate.getDate() + 10);
// तारीख YYYY-MM-DD format मध्ये करण्यासाठी
const year = selectedDate.getFullYear();
const month = String(selectedDate.getMonth() + 1).padStart(2, '0');
const day = String(selectedDate.getDate()).padStart(2, '0');
dueDateInput.value = `${year}-${month}-${day}`;
}
});
}
});
</script>
@endsection

View File

@@ -1313,40 +1313,232 @@ document.addEventListener('DOMContentLoaded', function () {
}
if (cgForm) {
cgForm.addEventListener('submit', function (e) {
const selectedIds = [];
itemCheckboxes.forEach(cb => { if (cb.checked && !cb.disabled) selectedIds.push(cb.value); });
if (selectedIds.length === 0) {
e.preventDefault();
alert('Please select at least one item for this charge group.');
return;
cgForm.addEventListener('submit', function (e) {
// Stop normal form submit (no page reload)
e.preventDefault();
// 1) Collect selected item IDs
const selectedIds = [];
itemCheckboxes.forEach(cb => {
if (cb.checked && !cb.disabled) {
selectedIds.push(cb.value);
}
if (!cgBasisSelect || !cgBasisSelect.value) {
e.preventDefault();
alert('Please select a basis for this charge group.');
return;
}
if (!cgTotalChargeInput || !cgTotalChargeInput.value || parseFloat(cgTotalChargeInput.value) <= 0) {
e.preventDefault();
alert('Please enter total charges for this group.');
return;
}
const oldHidden = cgForm.querySelectorAll('input[name="item_ids[]"]');
oldHidden.forEach(el => el.remove());
selectedIds.forEach(id => {
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'item_ids[]';
input.value = id;
cgForm.appendChild(input);
});
if (chargeGroupBox) chargeGroupBox.classList.add('d-none');
itemCheckboxes.forEach(cb => { if (!cb.disabled) cb.checked = false; });
if (selectAll) { selectAll.checked = false; selectAll.indeterminate = false; }
updateSelectionState();
});
// 2) Frontend validations (same as before)
if (selectedIds.length === 0) {
alert('Please select at least one item for this charge group.');
return;
}
if (!cgBasisSelect || !cgBasisSelect.value) {
alert('Please select a basis for this charge group.');
return;
}
if (
!cgTotalChargeInput ||
!cgTotalChargeInput.value ||
parseFloat(cgTotalChargeInput.value) <= 0
) {
alert('Please enter total charges for this group.');
return;
}
// 3) Remove previously added hidden item_ids[]
const oldHidden = cgForm.querySelectorAll('input[name="item_ids[]"]');
oldHidden.forEach(el => el.remove());
// 4) Add fresh hidden item_ids[] for current selection
selectedIds.forEach(id => {
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'item_ids[]';
input.value = id;
cgForm.appendChild(input);
});
// 5) Build AJAX request
const url = cgForm.action;
const formData = new FormData(cgForm);
// Optional: disable save button while processing
if (cgSaveBtn) {
cgSaveBtn.disabled = true;
cgSaveBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Saving...';
}
fetch(url, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(res => {
if (!res.ok) {
throw new Error('Request failed with status ' + res.status);
}
return res.json();
})
.then(data => {
if (!data.success) {
throw new Error(data.message || 'Failed to create charge group.');
}
const group = data.group;
// 6) Append new group main row + hidden items row
const groupsTbody = document.querySelector(
'.cg-groups-panel table.invoice-table tbody'
);
if (groupsTbody && group) {
const currentMainRows = groupsTbody.querySelectorAll(
'tr:not(.cg-items-row)'
).length;
const index = currentMainRows + 1;
// Main summary row (same structure as Blade)
const mainRow = document.createElement('tr');
mainRow.innerHTML = `
<td>${index}</td>
<td style="font-weight:600;">
${group.group_name ? group.group_name : 'Group #' + group.id}
</td>
<td>
<span style="text-transform:uppercase;font-size:0.75rem;font-weight:700;color:var(--text-muted);">
${group.basis_type}
</span>
</td>
<td class="text-end" style="font-family:'JetBrains Mono',monospace;font-size:0.82rem;">
${Number(group.basis_value).toFixed(3)}
</td>
<td class="text-end" style="font-family:'JetBrains Mono',monospace;font-size:0.82rem;">
${Number(group.rate).toFixed(2)}
</td>
<td class="text-end price-blue">
${Number(group.total_charge).toFixed(2)}
</td>
<td class="text-center">
<button type="button"
class="cg-toggle-btn cg-toggle-items"
data-group-id="${group.id}">
<i class="fas fa-eye"></i> View
</button>
</td>
`;
// Hidden items row (same idea as Blade .cg-items-row)
const itemsRow = document.createElement('tr');
itemsRow.className = 'cg-items-row d-none';
itemsRow.setAttribute('data-group-id', group.id);
let itemsTableHtml = `
<div style="padding:1rem;background:#f8faff;border-radius:8px;margin:0.25rem 0;">
<div style="font-weight:700;font-size:0.8rem;margin-bottom:0.6rem;color:var(--primary);">
Items in this group
</div>
`;
if (!group.items || group.items.length === 0) {
itemsTableHtml += `
<div style="color:var(--text-muted);font-size:0.82rem;">
No items linked.
</div>
`;
} else {
itemsTableHtml += `
<div class="table-responsive">
<table class="invoice-table">
<thead>
<tr>
<th>#</th>
<th>Description</th>
<th class="text-center">QTY</th>
<th class="text-center">TTL QTY</th>
<th class="text-center">CBM</th>
<th class="text-center">TTL CBM</th>
<th class="text-center">KG</th>
<th class="text-center">TTL KG</th>
<th class="text-end">TTL Amount</th>
</tr>
</thead>
<tbody>
`;
group.items.forEach((it, idx) => {
itemsTableHtml += `
<tr>
<td>${idx + 1}</td>
<td>${it.description ?? ''}</td>
<td class="text-center">${it.qty ?? ''}</td>
<td class="text-center">${it.ttlqty ?? ''}</td>
<td class="text-center">${it.cbm ?? ''}</td>
<td class="text-center">${it.ttlcbm ?? ''}</td>
<td class="text-center">${it.kg ?? ''}</td>
<td class="text-center">${it.ttlkg ?? ''}</td>
<td class="text-end">${Number(it.amount ?? 0).toFixed(2)}</td>
</tr>
`;
});
itemsTableHtml += `
</tbody>
</table>
</div>
`;
}
itemsTableHtml += `</div>`;
itemsRow.innerHTML = `
<td colspan="7">
${itemsTableHtml}
</td>
`;
// Append main row + items row in order
groupsTbody.appendChild(mainRow);
groupsTbody.appendChild(itemsRow);
}
// 7) Reset Charge Group UI (hide panel, uncheck items)
if (chargeGroupBox) {
chargeGroupBox.classList.add('d-none');
}
itemCheckboxes.forEach(cb => {
if (!cb.disabled) cb.checked = false;
});
if (selectAll) {
selectAll.checked = false;
selectAll.indeterminate = false;
}
updateSelectionState();
// Optional: clear form
if (cgGroupName) cgGroupName.value = '';
if (cgBasisSelect) cgBasisSelect.value = '';
if (cgRateInput) cgRateInput.value = '';
if (cgBasisValueSpan) cgBasisValueSpan.textContent = '0';
if (cgBasisLabelSpan) cgBasisLabelSpan.textContent = '';
if (cgSuggestedTotalSpan) cgSuggestedTotalSpan.textContent = '0';
if (cgTotalChargeInput) cgTotalChargeInput.value = '';
})
.catch(err => {
console.error(err);
alert('Error creating charge group. Please try again.');
})
.finally(() => {
if (cgSaveBtn) {
cgSaveBtn.disabled = false;
cgSaveBtn.innerHTML = '<i class="fas fa-save"></i> Save Charge Group';
}
});
});
}
updateSelectionState();
});