feat(manual-batch): require plate number at manual mode start
ci / smoke (push) Canceled after 0s

Legacy manual batch start locked until plate entered:
- POST /api/batch/start manual branch returns 400 missing_plate when
  plate empty (strip + uppercase, no format regex)
- operator + monitoring start modals gain required plate input,
  confirm button disabled until filled
- operator plate tile also shows for manual batches (was do_manual only)
- do_manual unchanged (plate from DOs)
This commit is contained in:
andrew committed 2026-10-02 15:10:13 +07:00
1 parent f621ae86fb
commit 7ad995d8d1
6 files changed
+118 -6

No files matched your search

+30 -2
View File
@@ -118,6 +118,7 @@
.btn-disabled {
opacity: 0.6;
cursor: not-allowed;
pointer-events: none;
}
/* Simple Confirmation Modal */
@@ -425,10 +426,16 @@
<div class="modal-box">
<h3 class="modal-title"><i class="fa-solid fa-play" style="color: var(--accent-green);"></i> Mulai Batch Baru?</h3>
<p class="modal-desc" id="startModalDesc">Pastikan truk sudah siap di posisi pemuatan karung.</p>
<div id="startPlateRow" style="display:none;margin:8px 0;">
<label for="startPlateInput" style="display:block;font-size:12px;color:var(--text-secondary);margin-bottom:4px;">Plat Nomor (wajib)</label>
<input type="text" id="startPlateInput" placeholder="B 1234 XYZ" autocomplete="off"
style="width:100%;padding:8px 10px;border-radius:var(--radius-md);border:1px solid var(--border-color);background:var(--bg-card);color:var(--text-primary);font-size:14px;text-transform:uppercase;box-sizing:border-box;"
oninput="onStartPlateInput()">
</div>
<div id="startGateList" class="modal-desc" style="display:none;color:var(--accent-red);"></div>
<div class="modal-actions">
<button class="btn btn-secondary" onclick="closeModal('modalStart')">Batal</button>
<button class="btn btn-primary" style="background-color: var(--accent-green);" onclick="executeStartBatch()">Ya, Mulai</button>
<button id="btnStartConfirm" class="btn btn-primary" style="background-color: var(--accent-green);" onclick="executeStartBatch()">Ya, Mulai</button>
</div>
</div>
</div>
@@ -687,10 +694,19 @@
return (data && data.items) || [];
}
function onStartPlateInput() {
const plate = document.getElementById('startPlateInput').value.trim();
const btn = document.getElementById('btnStartConfirm');
btn.classList.toggle('btn-disabled', plate.length === 0);
}
function confirmStartBatch() {
const gate = document.getElementById('startGateList');
const desc = document.getElementById('startModalDesc');
const plateRow = document.getElementById('startPlateRow');
if (currentMode === 'do_manual') {
plateRow.style.display = 'none';
document.getElementById('btnStartConfirm').classList.remove('btn-disabled');
fetchStagedForStart().then(items => {
stagedDos = items;
const problems = [];
@@ -717,6 +733,9 @@
}
gate.style.display = 'none';
desc.textContent = 'Pastikan truk sudah siap di posisi pemuatan karung.';
document.getElementById('startPlateInput').value = '';
plateRow.style.display = 'block';
onStartPlateInput();
document.getElementById('modalStart').style.display = 'flex';
}
@@ -744,6 +763,14 @@
if (currentMode === 'do_manual') {
const items = await fetchStagedForStart();
body = JSON.stringify({ do_ids: items.map(d => d.id) });
} else if (currentMode === 'manual') {
const plate = document.getElementById('startPlateInput').value.trim().toUpperCase();
if (!plate) {
closeModal('modalStart');
alert('Plat nomor wajib diisi sebelum batch dimulai.');
return;
}
body = JSON.stringify({ plate: plate });
}
const res = await fetch('/api/batch/start', {
method: 'POST',
@@ -817,7 +844,8 @@
const plateItem = document.getElementById('opPlateItem');
const plateDos = document.getElementById('opPlateDos');
const batchActive = !!(data.success && data.batch_number);
const showPlate = currentMode === 'do_manual' && batchActive;
const showPlate = batchActive &&
(currentMode === 'do_manual' || !!(data.plate && data.plate.trim()));
if (doSack) doSack.textContent = data.expected_sack || 0;
if (doBox) doBox.textContent = data.expected_box || 0;
if (plateItem) plateItem.style.display = showPlate ? 'block' : 'none';