Added more functionality
This commit is contained in:
+19
-4
@@ -1,4 +1,4 @@
|
||||
const state = { orders: [], users: [], vehicles: [] };
|
||||
const state = { orders: [], users: [], vehicles: [], recordItems: [] };
|
||||
const $ = (selector) => document.querySelector(selector);
|
||||
|
||||
async function request(url, options) {
|
||||
@@ -53,7 +53,7 @@ function renderOrders() {
|
||||
const serviceDate = String(order.service_date || '').slice(0, 10);
|
||||
return (!vehicleFilter || vehicleText.includes(vehicleFilter)) && (!customerFilter || customerText.includes(customerFilter)) && (!technicianFilter || technicianText.includes(technicianFilter)) && (!filters.dateFrom || serviceDate >= filters.dateFrom) && (!filters.dateTo || serviceDate <= filters.dateTo) && (!filters.status || order.status === filters.status);
|
||||
});
|
||||
$('#orders-table').innerHTML = visibleOrders.length ? visibleOrders.map((order) => `<tr><td>${escapeHtml(order.service_date)}</td><td>${escapeHtml(order.vin || '—')}</td><td><strong>${escapeHtml(order.license_plate)}</strong></td><td>${escapeHtml(`${order.make || ''} ${order.model || ''}`.trim())}</td><td>${Number(order.mileage).toLocaleString()} km</td><td>${escapeHtml(order.customer_name)}</td><td>${escapeHtml(order.technician)}</td><td>${escapeHtml(order.complaint)}</td><td><select class="status-select" data-order-id="${order.service_order_id}"><option value="${order.status}" selected>${titleCase(order.status)}</option><option value="open">Open</option><option value="in_progress">In progress</option><option value="waiting_for_parts">Waiting for parts</option><option value="ready">Ready</option><option value="closed">Closed</option></select></td><td><button class="edit-button" data-record-id="${order.service_order_id}">Edit</button></td></tr>`).join('') : `<tr><td colspan="10">${emptyMessage(state.orders.length ? 'No service records match these filters.' : 'No service records yet.')}</td></tr>`;
|
||||
$('#orders-table').innerHTML = visibleOrders.length ? visibleOrders.map((order) => `<tr><td>${escapeHtml(order.service_date)}</td><td>${escapeHtml(order.vin || '—')}</td><td><strong>${escapeHtml(order.license_plate)}</strong></td><td>${escapeHtml(`${order.make || ''} ${order.model || ''}`.trim())}</td><td>${Number(order.mileage).toLocaleString()} km</td><td>${escapeHtml(order.customer_name)}</td><td>${escapeHtml(order.technician)}</td><td>${escapeHtml(order.complaint)}</td><td>€${Number(order.total || 0).toFixed(2)}</td><td><select class="status-select" data-order-id="${order.service_order_id}"><option value="${order.status}" selected>${titleCase(order.status)}</option><option value="open">Open</option><option value="in_progress">In progress</option><option value="waiting_for_parts">Waiting for parts</option><option value="ready">Ready</option><option value="closed">Closed</option></select></td><td><button class="edit-button" data-record-id="${order.service_order_id}">Edit</button></td></tr>`).join('') : `<tr><td colspan="11">${emptyMessage(state.orders.length ? 'No service records match these filters.' : 'No service records yet.')}</td></tr>`;
|
||||
document.querySelectorAll('.status-select').forEach((select) => select.addEventListener('change', updateOrderStatus));
|
||||
document.querySelectorAll('.edit-button[data-record-id]').forEach((button) => button.addEventListener('click', () => editRecord(state.orders.find((order) => order.service_order_id === button.dataset.recordId))));
|
||||
}
|
||||
@@ -85,9 +85,21 @@ function editUser(user) {
|
||||
function editRecord(record) {
|
||||
const form = $('#record-form'); form.dataset.editId = record.service_order_id;
|
||||
for (const name of ['serviceDate', 'vin', 'licensePlate', 'make', 'model', 'modelYear', 'engine', 'transmission', 'fuelType', 'color', 'customerName', 'customerEmail', 'customerPhone', 'mileage', 'technicianName', 'complaint']) form.elements[name].value = record[name === 'licensePlate' ? 'license_plate' : name === 'modelYear' ? 'model_year' : name === 'customerName' ? 'customer_name' : name === 'customerEmail' ? 'customer_email' : name === 'customerPhone' ? 'customer_phone' : name === 'technicianName' ? 'technician' : name] || '';
|
||||
state.recordItems = (record.items || []).map((item) => ({ itemType: item.item_type, description: item.description, partNumber: item.part_number || '', usedTimeHours: item.labor_time_minutes ? Number(item.labor_time_minutes) / 60 : '', quantity: item.quantity || 1, unitPrice: item.unit_price || 0 }));
|
||||
renderServiceItems();
|
||||
$('#record-dialog-title').textContent = 'Edit service record'; $('#record-submit-button').textContent = 'Save changes'; $('#record-dialog').showModal();
|
||||
}
|
||||
|
||||
function renderServiceItems() {
|
||||
$('#service-items').innerHTML = state.recordItems.map((item, index) => `<div class="service-item" data-item-index="${index}"><div class="item-row-heading"><strong>${item.itemType === 'part' ? 'Part' : 'Labor'}</strong><button class="remove-item-button" type="button" data-item-index="${index}">Remove</button></div><label>Description<input data-item-field="description" value="${escapeHtml(item.description)}" /></label>${item.itemType === 'part' ? `<label>Part number<input data-item-field="partNumber" value="${escapeHtml(item.partNumber)}" /></label><label>Quantity<input data-item-field="quantity" type="number" min="0.01" step="0.01" value="${item.quantity}" /></label>` : `<label>Used time (hours)<input data-item-field="usedTimeHours" type="number" min="0.01" step="0.25" value="${item.usedTimeHours}" /></label>`}<label>${item.itemType === 'part' ? 'Price each' : 'Labor price per hour'}<input data-item-field="unitPrice" type="number" min="0" step="0.01" value="${item.unitPrice}" /></label><span class="item-line-total">Line total: €${calculateItemTotal(item).toFixed(2)}</span></div>`).join('');
|
||||
$('#service-items-total').textContent = `€${state.recordItems.reduce((total, item) => total + calculateItemTotal(item), 0).toFixed(2)}`;
|
||||
document.querySelectorAll('.service-item input').forEach((input) => input.addEventListener('input', (event) => { const row = event.target.closest('.service-item'); state.recordItems[row.dataset.itemIndex][event.target.dataset.itemField] = event.target.value; updateServiceItemTotals(); }));
|
||||
document.querySelectorAll('.remove-item-button').forEach((button) => button.addEventListener('click', () => { state.recordItems.splice(Number(button.dataset.itemIndex), 1); renderServiceItems(); }));
|
||||
}
|
||||
|
||||
function calculateItemTotal(item) { return item.itemType === 'labor' ? (Number(item.usedTimeHours) || 0) * (Number(item.unitPrice) || 0) : (Number(item.quantity) || 0) * (Number(item.unitPrice) || 0); }
|
||||
function updateServiceItemTotals() { document.querySelectorAll('.item-line-total').forEach((total, index) => { total.textContent = `Line total: €${calculateItemTotal(state.recordItems[index]).toFixed(2)}`; }); $('#service-items-total').textContent = `€${state.recordItems.reduce((total, item) => total + calculateItemTotal(item), 0).toFixed(2)}`; }
|
||||
|
||||
async function deleteUser(event) {
|
||||
if (!window.confirm(`Delete ${event.target.dataset.userName}?`)) return;
|
||||
try { await request(`/api/users/${event.target.dataset.userId}`, { method: 'DELETE' }); await loadUsers(); } catch (error) { showError(error); }
|
||||
@@ -115,7 +127,9 @@ $('#close-customer-button').addEventListener('click', () => $('#customer-dialog'
|
||||
$('#new-user-button').addEventListener('click', () => { const form = $('#user-form'); delete form.dataset.editId; form.reset(); form.elements.username.disabled = false; $('#user-dialog-title').textContent = 'Add user'; $('#user-submit-button').textContent = 'Create user'; $('#user-dialog').showModal(); });
|
||||
$('#cancel-user-button').addEventListener('click', () => $('#user-dialog').close());
|
||||
$('#close-user-button').addEventListener('click', () => $('#user-dialog').close());
|
||||
$('#new-record-button').addEventListener('click', () => { const form = $('#record-form'); delete form.dataset.editId; form.reset(); $('#record-dialog-title').textContent = 'Add service record'; $('#record-submit-button').textContent = 'Create service record'; $('#record-dialog').showModal(); });
|
||||
$('#new-record-button').addEventListener('click', () => { const form = $('#record-form'); delete form.dataset.editId; form.reset(); state.recordItems = []; renderServiceItems(); $('#record-dialog-title').textContent = 'Add service record'; $('#record-submit-button').textContent = 'Create service record'; $('#record-dialog').showModal(); });
|
||||
$('#add-part-button').addEventListener('click', () => { state.recordItems.push({ itemType: 'part', description: '', partNumber: '', quantity: 1, unitPrice: 0 }); renderServiceItems(); });
|
||||
$('#add-labor-button').addEventListener('click', () => { state.recordItems.push({ itemType: 'labor', description: '', usedTimeHours: 1, unitPrice: 0 }); renderServiceItems(); });
|
||||
$('#new-vehicle-button').addEventListener('click', () => $('#vehicle-dialog').showModal());
|
||||
$('#cancel-vehicle-button').addEventListener('click', () => $('#vehicle-dialog').close());
|
||||
$('#close-vehicle-button').addEventListener('click', () => $('#vehicle-dialog').close());
|
||||
@@ -173,9 +187,10 @@ $('#record-form').addEventListener('submit', async (event) => {
|
||||
event.preventDefault();
|
||||
try {
|
||||
const form = Object.fromEntries(new FormData(event.target));
|
||||
form.items = state.recordItems;
|
||||
const editId = event.target.dataset.editId;
|
||||
await request(editId ? `/api/service-records/${editId}` : '/api/service-records', { method: editId ? 'PATCH' : 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form) });
|
||||
event.target.reset(); delete event.target.dataset.editId; $('#record-dialog-title').textContent = 'Add service record'; $('#record-submit-button').textContent = 'Create service record'; $('#record-dialog').close(); await loadOrders(); await loadOverview();
|
||||
event.target.reset(); state.recordItems = []; delete event.target.dataset.editId; $('#record-dialog-title').textContent = 'Add service record'; $('#record-submit-button').textContent = 'Create service record'; $('#record-dialog').close(); await loadOrders(); await loadOverview();
|
||||
} catch (error) { showError(error); }
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user