/* @jsx React.createElement */ const { useState, useEffect, useRef, useMemo } = React; /* ============================================================ Yappari — STOK ============================================================ */ function StockView({ selectedMachine, machines, onPickMachine }) { const Y = window.YAPPARI; const mid = selectedMachine || machines[0].id; const mObj = machines.find(m => m.id === mid); const slots = Y.SLOTS[mid]; const prodMap = Object.fromEntries(Y.PRODUCTS.map(p => [p.id, p])); const [filter, setFilter] = useState('all'); const [, force] = useState(0); const [busy, setBusy] = useState(null); const canManage = !Y.CURRENT_USER || ['admin', 'operator', 'teknisi'].indexOf(Y.CURRENT_USER.role) >= 0; const doRefill = async (slotNo) => { setBusy(slotNo); try { await Y.refillSlot(mid, slotNo); force(x => x + 1); } catch (e) { alert('Gagal isi ulang: ' + (e.message || e)); } setBusy(null); }; const doRefillAll = async () => { if (!confirm('Tandai SEMUA slot ' + mObj.name + ' sudah diisi ulang ke penuh?')) return; setBusy('all'); try { await Y.refillAll(mid); force(x => x + 1); } catch (e) { alert('Gagal: ' + (e.message || e)); } setBusy(null); }; const sum = machineStockSummary(mid); const rows = slots.filter(s => !s.hidden).map(s => ({ s, p: prodMap[s.productId] })); const shown = rows.filter(r => filter === 'all' ? true : filter === 'empty' ? r.s.cur === 0 : filter === 'low' ? (r.s.cur > 0 && r.s.cur / r.s.cap <= 0.34) : true); return React.createElement('div', { className: 'view' }, selectedMachine == null && React.createElement('div', { className: 'card card-pad', style: { marginBottom: 'var(--sp-4)', display: 'flex', gap: 12, alignItems: 'center', background: 'var(--st-maint-bg)', border: 'none' } }, React.createElement(Icon, { name: 'alert', size: 18, style: { color: 'var(--st-maint)' } }), React.createElement('span', { style: { fontSize: 13.5, color: 'var(--fg-2)' } }, 'Menampilkan ', React.createElement('b', null, mObj.name), '. Pilih mesin lain dari dropdown di atas.'), ), React.createElement('div', { className: 'metric-grid m3' }, React.createElement(MetricCard, { label: 'Slot kehabisan', value: sum.empty, icon: 'packageX', bg: 'linear-gradient(135deg,#D03020,#9A1F12)', sub: 'dari ' + sum.total + ' slot' }), React.createElement(MetricCard, { label: 'Stok rendah', value: sum.low, icon: 'alert', bg: 'linear-gradient(135deg,#E0820E,#B85C00)', sub: 'perlu isi ulang' }), React.createElement(MetricCard, { label: 'Nilai stok', value: sum.value, prefix: 'Rp ', icon: 'wallet', bg: 'linear-gradient(135deg,#004080,#002E5C)', sub: 'estimasi nilai jual' }), ), React.createElement(SectionCard, { title: 'Inventaris slot — ' + mObj.name, sub: mObj.loc, motif: true, right: React.createElement('div', { className: 'row gap-2' }, React.createElement('button', { className: 'chip ' + (filter === 'all' ? 'active' : ''), onClick: () => setFilter('all') }, 'Semua ' + rows.length), React.createElement('button', { className: 'chip ' + (filter === 'low' ? 'active' : ''), onClick: () => setFilter('low') }, 'Rendah ' + sum.low), React.createElement('button', { className: 'chip ' + (filter === 'empty' ? 'active' : ''), onClick: () => setFilter('empty') }, 'Habis ' + sum.empty), canManage && React.createElement('button', { className: 'btn btn-primary btn-sm', style: { marginLeft: 4 }, disabled: busy === 'all', onClick: doRefillAll }, React.createElement(Icon, { name: 'package-plus', size: 14 }), busy === 'all' ? 'Mengisi…' : 'Isi ulang semua'), ), bodyStyle: { overflowX: 'auto', maxHeight: 560, overflowY: 'auto' }, }, React.createElement('table', { className: 'tbl' }, React.createElement('thead', { style: { position: 'sticky', top: 0, background: 'var(--bg-elev)', zIndex: 2 } }, React.createElement('tr', null, React.createElement('th', { style: { width: 70 } }, 'Slot'), React.createElement('th', null, 'Produk'), React.createElement('th', { style: { textAlign: 'right' } }, 'Stok'), React.createElement('th', { style: { textAlign: 'right' } }, 'Maks'), React.createElement('th', { style: { width: '30%' } }, 'Level'), React.createElement('th', { style: { textAlign: 'right' } }, 'Isi ulang terakhir'), canManage && React.createElement('th', { style: { textAlign: 'center', width: 90 } }, 'Aksi'), )), React.createElement('tbody', null, shown.map(({ s, p }) => { const col = stockColor(s.cur, s.cap); return React.createElement('tr', { key: s.label }, React.createElement('td', null, React.createElement('div', { className: 'row gap-1' }, React.createElement('span', { className: 'badge badge-soft mono', style: { fontWeight: 700 } }, s.no), s.span > 1 && React.createElement('span', { className: 'badge badge-warn', style: { padding: '1px 6px' }, title: 'Slot gabungan' }, '⇆×' + s.span))), React.createElement('td', null, React.createElement('div', { className: 'row gap-3' }, React.createElement(ProductGlyph, { glyph: p.glyph, color: p.color, size: 32 }), React.createElement('div', null, React.createElement('div', { className: 'strong' }, p.name), React.createElement('div', { style: { fontSize: 11.5, color: 'var(--fg-3)' } }, fmtRp(p.price))), )), React.createElement('td', { className: 'num', style: { textAlign: 'right', fontWeight: 700, color: col } }, s.cur), React.createElement('td', { className: 'num muted', style: { textAlign: 'right' } }, s.cap), React.createElement('td', null, React.createElement('div', { className: 'row gap-3' }, React.createElement(ProgressBar, { value: s.cur, max: s.cap, color: col, className: 'tall' }), React.createElement('span', { style: { minWidth: 86, fontSize: 12, fontWeight: 700, color: col } }, s.cur === 0 ? 'Habis' : s.cur / s.cap <= 0.34 ? 'Rendah' : 'Cukup'), )), React.createElement('td', { className: 'num muted', style: { textAlign: 'right' } }, s.lastRefill === 0 ? 'Hari ini' : s.lastRefill + ' hari lalu'), canManage && React.createElement('td', { style: { textAlign: 'center' } }, s.cur >= s.cap ? React.createElement('span', { style: { fontSize: 11.5, color: 'var(--st-online)', fontWeight: 700 } }, 'Penuh') : React.createElement('button', { className: 'btn btn-ghost btn-sm', disabled: busy === s.no, title: 'Tandai sudah diisi ulang ke penuh', onClick: () => doRefill(s.no) }, busy === s.no ? '…' : React.createElement(Icon, { name: 'package-plus', size: 14 }))), ); }), ), ), ), ); } Object.assign(window, { StockView });