// ============================================================ // Elegant Work — UI Utilities // Toast, Modal, Confirm, Format helpers // ============================================================ // ── Toast ──────────────────────────────────────────────── const Toast = (() => { const ICONS = { success: ``, error: ``, warning: ``, info: ``, }; function show(message, type = 'success', title = null, duration = 4000) { const container = document.getElementById('toast-container'); if (!container) return; const toast = document.createElement('div'); toast.className = `toast ${type}`; toast.innerHTML = `
${message}
`, footer: ` ` }); window._confirmResolve = resolve; }); } return { open, close, confirm }; })(); // ── Format Helpers ─────────────────────────────────────── const Fmt = (() => { function currency(amount, currency = 'ZAR') { if (amount === null || amount === undefined || amount === '') return '—'; return new Intl.NumberFormat('en-ZA', { style: 'currency', currency }).format(amount); } function date(val, opts = {}) { if (!val) return '—'; const d = new Date(val); if (isNaN(d)) return val; return d.toLocaleDateString('en-ZA', { day: '2-digit', month: 'short', year: 'numeric', ...opts }); } function datetime(val) { if (!val) return '—'; const d = new Date(val); if (isNaN(d)) return val; return d.toLocaleDateString('en-ZA', { day: '2-digit', month: 'short', year: 'numeric' }) + ' ' + d.toLocaleTimeString('en-ZA', { hour: '2-digit', minute: '2-digit' }); } function ago(val) { if (!val) return '—'; const d = new Date(val); const diff = Date.now() - d.getTime(); const mins = Math.floor(diff / 60000); if (mins < 1) return 'just now'; if (mins < 60) return `${mins}m ago`; const hrs = Math.floor(mins / 60); if (hrs < 24) return `${hrs}h ago`; const days = Math.floor(hrs / 24); if (days < 30) return `${days}d ago`; return date(val); } function capitalize(s) { if (!s) return ''; return s.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); } function initials(name) { if (!name) return '?'; return name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2); } function statusBadge(status, extraClass = '') { const s = (status || '').toLowerCase().replace(/ /g, '_'); return `${capitalize(status)}`; } function priorityBadge(priority) { const map = { low: 'badge-muted', medium: 'badge-info', high: 'badge-warning', critical: 'badge-danger', urgent: 'badge-danger' }; const cls = map[(priority || '').toLowerCase()] || 'badge-muted'; return `${capitalize(priority || '')}`; } function severityBadge(sev) { return `${capitalize(sev || '')}`; } return { currency, date, datetime, ago, capitalize, initials, statusBadge, priorityBadge, severityBadge }; })(); // ── Pagination Renderer ────────────────────────────────── function renderPagination(containerId, pagination, onPageChange) { const el = document.getElementById(containerId); if (!el || !pagination) return; const { total, page, limit, pages } = pagination; const start = total === 0 ? 0 : (page - 1) * limit + 1; const end = Math.min(page * limit, total); let btns = ''; btns += ``; for (let p = Math.max(1, page - 2); p <= Math.min(pages, page + 2); p++) { btns += ``; } btns += ``; el.innerHTML = `