import { api } from '../../lib/api.mjs'; const COLUMNS = [ { key: 'draft', label: 'Draft', color: 'var(--status-draft)' }, { key: 'assigned', label: 'Assigned', color: 'var(--status-assigned)' }, { key: 'scheduled', label: 'Scheduled', color: 'var(--status-scheduled)' }, { key: 'in_progress', label: 'In Progress', color: 'var(--status-in_progress)' }, { key: 'pending_review', label: 'Pending Review', color: 'var(--status-pending_review)' }, { key: 'closed', label: 'Closed', color: 'var(--status-closed)' }, ]; const PRI_COLOR = { low:'var(--priority-low)', normal:'var(--priority-normal)', high:'var(--priority-high)', urgent:'var(--priority-urgent)' }; class WoKanban extends HTMLElement { #data = []; #dragging = null; connectedCallback() { this.attachShadow({ mode: 'open' }); this.#load(); } async #load() { try { this.#data = await api.get('/work-orders') ?? []; } catch { this.#data = []; } this.#render(); } #render() { const s = this.shadowRoot; const byStatus = Object.fromEntries(COLUMNS.map(c => [c.key, this.#data.filter(w => w.status === c.key)])); s.innerHTML = `
${COLUMNS.map(col => `
${col.label} ${byStatus[col.key].length}
${byStatus[col.key].map(wo => `
${wo.wo_number}
${this.#esc(wo.title)}
${wo.site_name ? `
${this.#esc(wo.site_name)}
` : ''}
`).join('')}
`).join('')}
`; this.#bindDragDrop(); this.#bindClicks(); } #bindClicks() { this.shadowRoot.querySelectorAll('.wo-card').forEach(card => { card.addEventListener('click', () => window.dispatchEvent(new CustomEvent('wo:navigate', { detail: { path: `/work-orders/${card.dataset.id}` } }))); }); } #bindDragDrop() { const s = this.shadowRoot; s.querySelectorAll('.wo-card').forEach(card => { card.addEventListener('dragstart', e => { this.#dragging = card; card.classList.add('dragging'); e.dataTransfer.effectAllowed = 'move'; }); card.addEventListener('dragend', () => { card.classList.remove('dragging'); this.#dragging = null; }); }); s.querySelectorAll('.col-body').forEach(zone => { zone.addEventListener('dragover', e => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; zone.classList.add('drop-zone'); }); zone.addEventListener('dragleave', () => zone.classList.remove('drop-zone')); zone.addEventListener('drop', async e => { e.preventDefault(); zone.classList.remove('drop-zone'); if (!this.#dragging) return; const newStatus = zone.dataset.status; const id = this.#dragging.dataset.id; if (this.#dragging.dataset.status === newStatus) return; try { await api.put(`/work-orders/${id}/status`, { status: newStatus }); await this.#load(); } catch (err) { window.dispatchEvent(new CustomEvent('wo:toast', { detail: { message: err.message, type: 'error' } })); } }); }); } #esc(s) { return (s || '').replace(/&/g,'&').replace(//g,'>'); } } customElements.define('wo-kanban', WoKanban);