/* ═══════════════════════════════════════════════════════════ Shared modal shell + inventory modals (Modal, PasswordGate, AddPalletModal, TransferModal, Quarantine) ═══════════════════════════════════════════════════════════ */ (function () { const { useState, useEffect, useRef } = React; const { GUNS, CHARGE_BEHAVIORS, CHARGE_TYPE_NAMES, makeShellKey, makeFuzeKey, makeChargeKey, makeTypeRecord, parseKey, keyLabel, ammoQtyBadge, genId, fmtDatetime, } = window; // ── Shared shell ───────────────────────────────────────────── function Modal({ title, onClose, children, xl, icon }) { return (
{ if (e.target === e.currentTarget) onClose(); }}>
{icon && {icon}}{title}
{children}
); } function SepRow({ label, cols }) { return {label}; } // ── Password gate (server-verified) ────────────────────────── // If the user is already operator or admin (session cached), skip automatically. function PasswordGate({ onSuccess, onCancel }) { const [code, setCode] = useState(''); const [err, setErr] = useState(false); const [busy, setBusy] = useState(false); // Auto-pass if already operator or admin useEffect(() => { if (window.api?.canEdit()) { onSuccess(); } }, []); const attempt = async () => { if (!code || busy) return; setBusy(true); setErr(false); try { const d = await window.api.login(code); if (d.role === 'viewer') { // Re-logged in as viewer — not enough setErr(true); setCode(''); setTimeout(() => setErr(false), 2500); } else { onSuccess(); } } catch (e) { setErr(true); setCode(''); setTimeout(() => setErr(false), 2500); } finally { setBusy(false); } }; // If canEdit already (rendered after auto-pass fires), show nothing if (window.api?.canEdit()) return null; return (
נדרש קוד מפעיל / מנהל לביצוע עריכה
{err &&
קוד שגוי — הפעולה נחסמה ⛔
} setCode(e.target.value)} onKeyDown={e => e.key === 'Enter' && attempt()} placeholder="הקלד קוד..." autoFocus style={{ textAlign: 'center', fontSize: '1rem', letterSpacing: '.15em' }} />
); } // ── Add pallet (external intake) ───────────────────────────── function AddPalletModal({ nextId, registeredTypes, onClose, onSubmit }) { const emptyLine = () => ({ id: genId(), cat: 'shell', shellName: '', fuzeName: '', chargeType: 'M7 אחוד', series: '', qty: '' }); const [lines, setLines] = useState([emptyLine()]); const setF = (id, f, v) => setLines(p => p.map(l => l.id === id ? { ...l, [f]: v } : l)); const addLine = () => setLines(p => [...p, emptyLine()]); const rmLine = id => setLines(p => p.filter(l => l.id !== id)); function lineKey(l) { if (l.cat === 'shell') return l.shellName.trim() ? makeShellKey(l.shellName) : null; if (l.cat === 'fuze') return l.fuzeName.trim() ? makeFuzeKey(l.fuzeName) : null; if (l.cat === 'charge') return l.series.trim() ? makeChargeKey(l.chargeType, l.series) : null; return null; } const canSubmit = lines.some(l => lineKey(l) && parseInt(l.qty) > 0); const submit = () => { const ammo = {}, newTypeMap = {}; lines.forEach(l => { const key = lineKey(l); const qty = parseInt(l.qty) || 0; if (!key || !qty) return; ammo[key] = (ammo[key] || 0) + qty; if (!registeredTypes.find(r => r.key === key) && !newTypeMap[key]) newTypeMap[key] = makeTypeRecord(key); }); if (!Object.keys(ammo).length) return; onSubmit(ammo, Object.values(newTypeMap).filter(Boolean)); }; return (
הוסף שורות. כל סוג חדש יירשם אוטומטית.
{lines.map(l => (
{l.cat === 'shell' && (
setF(l.id, 'shellName', e.target.value)} />
)} {l.cat === 'fuze' && (
setF(l.id, 'fuzeName', e.target.value)} />
)} {l.cat === 'charge' && (<>
setF(l.id, 'series', e.target.value)} />
)}
setF(l.id, 'qty', e.target.value)} />
{lines.length > 1 && }
{l.cat === 'charge' && CHARGE_BEHAVIORS[l.chargeType]?.kind === 'modular' && (
M231: נספר בתתי מטענים. M231/1 = מודול אחד לפגז | M231/2 = שניים לפגז
)}
))}
); } window.Modal = Modal; window.SepRow = SepRow; window.PasswordGate = PasswordGate; window.AddPalletModal = AddPalletModal; })();