- Fixed 30 EJS views: changed ../partials/ to ../../partials/ for views in subdirectories
(pages/loads/, pages/shippers/, pages/portal/, pages/marketplace/, pages/payments/, etc.)
- Fixed layouts/main.ejs: corrected malformed EJS tags on lines 11 and 66
(<% ... { <% → <% ... { %>)
234 lines
9.8 KiB
Text
234 lines
9.8 KiB
Text
<%- include('../../partials/header', { activeMenu: 'loads' }) %>
|
|
|
|
<div class="page-header">
|
|
<div>
|
|
<h1 class="page-title"><%= isEdit ? 'Edit Load' : '+ New Load' %></h1>
|
|
<p class="page-subtitle"><%= isEdit ? 'Update load details' : 'Add a new freight load' %></p>
|
|
</div>
|
|
<a href="/loads" class="btn btn-outline">← Back to Loads</a>
|
|
</div>
|
|
|
|
<% if (typeof error !== 'undefined' && error) { %>
|
|
<div class="alert alert-error"><%= error %></div>
|
|
<% } %>
|
|
|
|
<div class="grid-2">
|
|
<!-- Form -->
|
|
<div class="card">
|
|
<div class="card-header"><h3 class="card-title">Load Details</h3></div>
|
|
<div class="card-body">
|
|
<form method="POST" action="<%= isEdit ? '/loads/' + encodeURIComponent(load.id) : '/loads' %>" id="loadForm">
|
|
<input type="hidden" name="_csrf" value="<%= _csrf %>">
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label class="form-label">Date</label>
|
|
<input type="date" name="date" class="form-input" value="<%= load.date || '' %>">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Status</label>
|
|
<select name="status" class="form-input">
|
|
<% for (const s of LOAD_STATUSES) { %>
|
|
<option value="<%= s %>" <%= load.status === s ? 'selected' : '' %>><%= s %></option>
|
|
<% } %>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label class="form-label">Shipper</label>
|
|
<select name="shipper_id" class="form-input">
|
|
<option value="">— Select —</option>
|
|
<% for (const s of shippers) { %>
|
|
<option value="<%= s.id %>" <%= load.shipper_id === s.id ? 'selected' : '' %>><%= s.name %></option>
|
|
<% } %>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Vehicle</label>
|
|
<select name="vehicle_id" class="form-input">
|
|
<option value="">— Select —</option>
|
|
<% for (const v of vehicles) { %>
|
|
<option value="<%= v.id %>" <%= load.vehicle_id === v.id ? 'selected' : '' %>><%= v.number %></option>
|
|
<% } %>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label class="form-label">From City</label>
|
|
<input type="text" name="from_city" class="form-input" list="cities" value="<%= load.from_city || '' %>" placeholder="Origin">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Via</label>
|
|
<input type="text" name="via" class="form-input" value="<%= load.via || '' %>" placeholder="Via (optional)">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">To City</label>
|
|
<input type="text" name="to_city" class="form-input" list="cities" value="<%= load.to_city || '' %>" placeholder="Destination">
|
|
</div>
|
|
</div>
|
|
|
|
<datalist id="cities">
|
|
<% for (const c of CITIES) { %><option value="<%= c %>"><% } %>
|
|
</datalist>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label class="form-label">Load Type</label>
|
|
<select name="load_type" class="form-input">
|
|
<option value="">— Select —</option>
|
|
<% for (const t of LOAD_TYPES) { %>
|
|
<option value="<%= t %>" <%= load.load_type === t ? 'selected' : '' %>><%= t %></option>
|
|
<% } %>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Item</label>
|
|
<input type="text" name="item" class="form-input" value="<%= load.item || '' %>" placeholder="Goods description">
|
|
</div>
|
|
</div>
|
|
|
|
<h4 class="section-title">Financials</h4>
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label class="form-label">Freight Charged (₹)</label>
|
|
<input type="number" name="freight_charged" class="form-input" value="<%= load.freight_charged || '' %>" placeholder="0" id="freight_charged">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Advance Received (₹)</label>
|
|
<input type="number" name="advance_received" class="form-input" value="<%= load.advance_received || '' %>" placeholder="0" id="advance_received">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label class="form-label">Paid to Driver (₹)</label>
|
|
<input type="number" name="paid_to_driver" class="form-input" value="<%= load.paid_to_driver || '' %>" placeholder="0" id="paid_to_driver">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Driver Freight (₹)</label>
|
|
<input type="number" name="driver_freight" class="form-input" value="<%= load.driver_freight || '' %>" placeholder="0" id="driver_freight">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label class="form-label">Commission (₹)</label>
|
|
<input type="number" name="commission" class="form-input" value="<%= load.commission || '' %>" placeholder="Auto-calculated" id="commission">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Pending from Shipper (₹)</label>
|
|
<input type="number" name="pending_from_shipper" class="form-input" value="<%= load.pending_from_shipper || '' %>" placeholder="Auto-calculated" id="pending_from_shipper">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Notes</label>
|
|
<textarea name="notes" class="form-input" rows="3" placeholder="Additional notes..."><%= load.notes || '' %></textarea>
|
|
</div>
|
|
|
|
<div class="form-actions">
|
|
<button type="submit" class="btn btn-primary"><%= isEdit ? 'Update Load' : 'Save Load' %></button>
|
|
<a href="/loads" class="btn btn-outline">Cancel</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- WhatsApp Parser -->
|
|
<div class="card">
|
|
<div class="card-header"><h3 class="card-title">📱 WhatsApp Parser</h3></div>
|
|
<div class="card-body">
|
|
<p class="text-muted">Paste a WhatsApp message to auto-fill the form.</p>
|
|
<div class="form-group">
|
|
<textarea id="whatsappInput" class="form-input" rows="4" placeholder='e.g. "Agarwal Bangalore TN39DV8142 loaded 19000 freight driver advance 15900"'></textarea>
|
|
</div>
|
|
<button type="button" class="btn btn-secondary" onclick="parseWhatsApp()">Parse Message</button>
|
|
|
|
<div id="parseResult" class="mt-3" style="display:none;">
|
|
<div class="parse-result">
|
|
<h4>Parsed Fields <span id="parseConfidence" class="badge"></span></h4>
|
|
<div id="parseFields"></div>
|
|
<button type="button" class="btn btn-primary mt-2" onclick="applyParsed()">Apply to Form</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<% if (isEdit) { %>
|
|
<div class="mt-4">
|
|
<form method="POST" action="/loads/<%= encodeURIComponent(load.id) %>/delete" onsubmit="return confirm('Delete this load?')">
|
|
<input type="hidden" name="_csrf" value="<%= _csrf %>">
|
|
<button type="submit" class="btn btn-danger">Delete Load</button>
|
|
</form>
|
|
</div>
|
|
<% } %>
|
|
|
|
<script>
|
|
let parsedData = null;
|
|
|
|
async function parseWhatsApp() {
|
|
const msg = document.getElementById('whatsappInput').value;
|
|
if (!msg.trim()) return;
|
|
|
|
const res = await fetch('/api/parse-whatsapp', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ message: msg })
|
|
});
|
|
parsedData = await res.json();
|
|
|
|
const resultDiv = document.getElementById('parseResult');
|
|
const fieldsDiv = document.getElementById('parseFields');
|
|
const confidenceSpan = document.getElementById('parseConfidence');
|
|
|
|
resultDiv.style.display = 'block';
|
|
confidenceSpan.textContent = parsedData.confidence + ' confidence';
|
|
confidenceSpan.className = 'badge badge-' + (parsedData.confidence === 'high' ? 'success' : parsedData.confidence === 'medium' ? 'warning' : 'gray');
|
|
|
|
const fieldLabels = {
|
|
shipper: 'Shipper', vehicle: 'Vehicle', from_city: 'From', to_city: 'To',
|
|
via: 'Via', status: 'Status', freight_charged: 'Freight', advance_received: 'Advance',
|
|
paid_to_driver: 'Paid to Driver', commission: 'Commission', driver_freight: 'Driver Freight',
|
|
pending_from_shipper: 'Pending (Shipper)', pending_to_driver: 'Pending (Driver)'
|
|
};
|
|
|
|
let html = '<div class="parse-fields">';
|
|
for (const [key, value] of Object.entries(parsedData)) {
|
|
if (key === 'confidence' || key === 'parsed_fields' || key === 'notes' || value === null || value === undefined) continue;
|
|
html += '<div class="parse-field"><span class="parse-key">' + (fieldLabels[key] || key) + ':</span> <span class="parse-val">' + value + '</span></div>';
|
|
}
|
|
html += '</div>';
|
|
fieldsDiv.innerHTML = html;
|
|
}
|
|
|
|
function applyParsed() {
|
|
if (!parsedData) return;
|
|
const map = {
|
|
shipper_id: parsedData.shipper,
|
|
vehicle_id: parsedData.vehicle,
|
|
from_city: parsedData.from_city,
|
|
to_city: parsedData.to_city,
|
|
via: parsedData.via,
|
|
status: parsedData.status,
|
|
freight_charged: parsedData.freight_charged,
|
|
advance_received: parsedData.advance_received,
|
|
paid_to_driver: parsedData.paid_to_driver,
|
|
commission: parsedData.commission,
|
|
driver_freight: parsedData.driver_freight,
|
|
pending_from_shipper: parsedData.pending_from_shipper,
|
|
pending_to_driver: parsedData.pending_to_driver,
|
|
};
|
|
for (const [field, value] of Object.entries(map)) {
|
|
if (value === null || value === undefined) continue;
|
|
const el = document.querySelector('[name="' + field + '"]');
|
|
if (el) el.value = value;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<%- include('../../partials/footer', { extraJs: [] }) %>
|