/* kanban-modal.js — card create/edit modal */ (function () { 'use strict'; var modal = document.getElementById('cardModal'); var bsModal = new bootstrap.Modal(modal); var titleEl = document.getElementById('cardModalLabel'); var cardIdEl = document.getElementById('card-id'); var colIdEl = document.getElementById('card-column-id'); var laneIdEl = document.getElementById('card-lane-id'); var jobNumEl = document.getElementById('card-job-number'); var jobNameEl = document.getElementById('card-job-name'); var errEl = document.getElementById('card-modal-error'); var btnSave = document.getElementById('btn-save-card'); var btnDelete = document.getElementById('btn-delete-card'); var custNameEl = document.getElementById('card-customer-name'); var delivDateEl = document.getElementById('card-delivery-date'); var qtyEl = document.getElementById('card-quantity'); var notesEl = document.getElementById('card-notes'); var fullNoteEl = document.getElementById('card-full-note'); var boardId = KANBAN.boardId; /* ── Helpers ─────────────────────────────────────────────── */ function post(url, data, cb) { var params = new URLSearchParams(); Object.keys(data).forEach(function (k) { params.append(k, data[k]); }); fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params.toString() }) .then(function (r) { return r.json(); }) .then(cb) .catch(function (e) { showError('Network error: ' + e); }); } function showError(msg) { errEl.textContent = msg; errEl.classList.remove('d-none'); } function clearError() { errEl.textContent = ''; errEl.classList.add('d-none'); } /* ── Open for create ──────────────────────────────────────── */ function openCreate(bId, colId, laneId) { titleEl.textContent = 'Add Card'; cardIdEl.value = ''; colIdEl.value = colId || ''; laneIdEl.value = laneId || ''; jobNumEl.value = ''; jobNameEl.value = ''; custNameEl.value = ''; delivDateEl.value = ''; qtyEl.value = ''; notesEl.value = ''; fullNoteEl.value = ''; btnDelete.classList.add('d-none'); clearError(); bsModal.show(); jobNumEl.focus(); } /* ── Open for edit ───────────────────────────────────────── */ function openEdit(id, colId, laneId, jobNum, jobName, custName, delivDate, qty, notes, fullNote) { titleEl.textContent = 'Edit Card'; cardIdEl.value = id; colIdEl.value = colId; laneIdEl.value = laneId; jobNumEl.value = jobNum || ''; jobNameEl.value = jobName || ''; custNameEl.value = custName || ''; delivDateEl.value = delivDate || ''; qtyEl.value = qty || ''; notesEl.value = notes || ''; fullNoteEl.value = fullNote || ''; btnDelete.classList.remove('d-none'); clearError(); bsModal.show(); jobNumEl.focus(); } /* ── Save ─────────────────────────────────────────────────── */ btnSave.addEventListener('click', function () { clearError(); var id = cardIdEl.value; var colId = colIdEl.value; var laneId = laneIdEl.value; var jNum = jobNumEl.value.trim(); var jName = jobNameEl.value.trim(); var cust = custNameEl.value.trim(); var dDate = delivDateEl.value; var qty = qtyEl.value.trim(); var notes = notesEl.value.trim(); var fullNote = fullNoteEl.value; if (!jNum && !jName) { showError('Enter at least a job number or job name.'); return; } if (id) { // Update existing post('/cards/' + id, { job_number: jNum, job_name: jName, customer_name: cust, delivery_date: dDate, quantity: qty, notes: notes, full_note: fullNote }, function (res) { if (res.ok) { bsModal.hide(); window.KanbanBoard.onCardUpdated(id, res); } else { showError(res.error || 'Save failed.'); } }); } else { // Create new — if no col/lane selected show column/lane picker if (!colId || !laneId) { showError('Please choose a column and swim lane first.'); return; } post('/cards', { board_id: boardId, column_id: colId, swim_lane_id: laneId, job_number: jNum, job_name: jName, customer_name: cust, delivery_date: dDate, quantity: qty, notes: notes, full_note: fullNote }, function (res) { if (res.ok) { bsModal.hide(); window.KanbanBoard.onCardCreated(res); } else { showError(res.error || 'Save failed.'); } }); } }); /* ── Delete ──────────────────────────────────────────────── */ btnDelete.addEventListener('click', function () { if (!confirm('Delete this card?')) return; var id = cardIdEl.value; post('/cards/' + id + '/delete', {}, function (res) { if (res.ok) { bsModal.hide(); window.KanbanBoard.onCardDeleted(id); } else { showError(res.error || 'Delete failed.'); } }); }); /* ── Column/Lane picker when Add Card clicked with no cell ── */ // Populated lazily from board data modal.addEventListener('shown.bs.modal', function () { if (!cardIdEl.value && (!colIdEl.value || !laneIdEl.value)) { injectPicker(); } }); function injectPicker() { if (document.getElementById('card-picker')) return; var picker = document.createElement('div'); picker.id = 'card-picker'; picker.className = 'row g-2 mb-3'; var colSel = ''; document.querySelectorAll('.kanban-col-header').forEach(function (el) { colSel += ''; }); document.querySelectorAll('.kanban-lane-header').forEach(function (el) { laneSel += ''; }); colSel += ''; laneSel += ''; picker.innerHTML = '
' + colSel + '
' + '
' + laneSel + '
'; var first = document.getElementById('card-job-number').closest('.mb-3'); modal.querySelector('.modal-body').insertBefore(picker, first); document.getElementById('pick-col').addEventListener('change', function () { colIdEl.value = this.value; }); document.getElementById('pick-lane').addEventListener('change', function () { laneIdEl.value = this.value; }); } /* ── Public API ──────────────────────────────────────────── */ window.KanbanModal = { openCreate: openCreate, openEdit: openEdit }; })();