/* ═══════════════════════════════════════════════════════════ TransferModal (internal movements) + QuarantineSection ═══════════════════════════════════════════════════════════ */ (function () { const { useState: useStateT } = React; const { GUNS: GUNS_T, parseKey: parseKeyT, keyLabel: keyLabelT, ammoQtyBadge: badgeT, genId: genIdT, fmtDatetime: fmtT, Modal: ModalT, PasswordGate: PasswordGateT, } = window; function TransferModal({ state, dispatch, onClose }) { const [mode, setMode] = useStateT('p2g'); const regs = state.registeredTypes; function P2GForm() { const [palletId, setPalletId] = useStateT(''); const [gunSel, setGunSel] = useStateT({}); const [qtys, setQtys] = useStateT({}); const pallet = state.bunker.find(p => p.id === Number(palletId)); const palletRegs = regs.filter(r => (pallet?.ammo[r.key] || 0) > 0); const selGuns = GUNS_T.filter(g => gunSel[g]); const setQty = (gun, key, v) => setQtys(p => ({ ...p, [gun + '::' + key]: Math.max(0, parseInt(v) || 0) })); const getQty = (gun, key) => qtys[gun + '::' + key] || 0; const sumForKey = key => selGuns.reduce((s, g) => s + getQty(g, key), 0); const keyValid = key => !pallet || sumForKey(key) <= (pallet.ammo[key] || 0); const canSub = selGuns.length > 0 && pallet && palletRegs.length > 0 && palletRegs.every(r => keyValid(r.key)); const submit = () => { selGuns.forEach(gun => { const items = palletRegs.map(r => ({ key: r.key, qty: getQty(gun, r.key) })).filter(i => i.qty > 0); if (items.length) dispatch({ type: 'TRANSFER_PALLET_TO_GUN', palletId: Number(palletId), gun, items }); }); onClose(); }; return (
{pallet && <>
בחר צוותים מקבלים:
{GUNS_T.map(g => ( ))}
{selGuns.length > 0 && palletRegs.length > 0 && (
{selGuns.map(g => )} {palletRegs.map(r => { const avail = pallet.ammo[r.key] || 0; const sum = sumForKey(r.key); const over = sum > avail; return ( {selGuns.map(g => ( ))} ); })}
תחמושתבמשטחצוות {g}סה"כ חוסר
{r.label} {badgeT(avail)} setQty(g, r.key, e.target.value)} style={{ width: '70px', textAlign: 'center', borderColor: over ? 'var(--danger)' : '' }} /> {sum}{over ? ' ⚠' : ''}
)} {selGuns.length === 0 &&
בחר לפחות צוות אחד ↑
} }
); } function G2PForm() { const [palletId, setPalletId] = useStateT(''); const [gunSel, setGunSel] = useStateT({}); const [qtys, setQtys] = useStateT({}); const selGuns = GUNS_T.filter(g => gunSel[g]); const setQty = (gun, key, v) => setQtys(p => ({ ...p, [gun + '::' + key]: Math.max(0, parseInt(v) || 0) })); const getQty = (gun, key) => qtys[gun + '::' + key] || 0; const availKeys = regs.filter(r => selGuns.some(g => (state.guns[g]?.[r.key] || 0) > 0)); const gunValid = (gun, key) => getQty(gun, key) <= (state.guns[gun]?.[key] || 0); const canSub = palletId && selGuns.length > 0 && availKeys.length > 0 && selGuns.every(g => availKeys.every(r => gunValid(g, r.key))) && selGuns.some(g => availKeys.some(r => getQty(g, r.key) > 0)); const submit = () => { selGuns.forEach(gun => { const items = availKeys.map(r => ({ key: r.key, qty: getQty(gun, r.key) })).filter(i => i.qty > 0); if (items.length) dispatch({ type: 'TRANSFER_GUN_TO_PALLET', gun, palletId: Number(palletId), items }); }); onClose(); }; return (
בחר צוותים מעבירים:
{GUNS_T.map(g => ( ))}
{selGuns.length > 0 && availKeys.length > 0 && (
{selGuns.map(g => )}{availKeys.map(r => ( {selGuns.map(g => { const avail = state.guns[g]?.[r.key] || 0; const over = getQty(g, r.key) > avail; return ( ); })} ))}
תחמושתצוות {g} (זמין)
{r.label}
({avail}) setQty(g, r.key, e.target.value)} style={{ width: '64px', textAlign: 'center', borderColor: over ? 'var(--danger)' : '' }} />
)} {selGuns.length === 0 &&
בחר לפחות צוות אחד ↑
}
); } function G2GForm() { const [src, setSrc] = useStateT(''); const [dst, setDst] = useStateT(''); const [qtys, setQtys] = useStateT({}); const srcAmmo = src ? state.guns[src] || {} : {}; const srcKeys = regs.filter(r => (srcAmmo[r.key] || 0) > 0); const setQty = (key, v) => setQtys(p => ({ ...p, [key]: Math.max(0, Math.min(srcAmmo[key] || 0, parseInt(v) || 0)) })); const items = srcKeys.map(r => ({ key: r.key, qty: qtys[r.key] || 0 })).filter(i => i.qty > 0); const canSub = src && dst && src !== dst && items.length > 0; const submit = () => { dispatch({ type: 'TRANSFER_GUN_TO_GUN', srcGun: src, dstGun: dst, items }); onClose(); }; return (
{src && srcKeys.length === 0 &&
אין מלאי לצוות {src}
} {src && srcKeys.length > 0 && (
{srcKeys.map(r => (
{r.label} זמין: {srcAmmo[r.key]} {r.unit} setQty(r.key, e.target.value)} style={{ width: '68px', textAlign: 'center' }} />
))}
)}
); } function QuarantineForm({ srcType }) { const [sel, setSel] = useStateT(''); const [qtys, setQtys] = useStateT({}); const [reason, setReason] = useStateT(''); const [approver, setApprover] = useStateT(''); const [imgB64, setImgB64] = useStateT(''); const isGun = srcType === 'gun'; const container = isGun ? (sel ? state.guns[sel] || {} : {}) : (state.bunker.find(p => p.id === Number(sel))?.ammo || {}); const srcKeys = regs.filter(r => (container[r.key] || 0) > 0); const setQty = (key, v) => setQtys(p => ({ ...p, [key]: Math.max(0, Math.min(container[key] || 0, parseInt(v) || 0)) })); const items = srcKeys.map(r => ({ key: r.key, qty: qtys[r.key] || 0 })).filter(i => i.qty > 0); const canSub = sel && items.length > 0 && reason.trim() && approver.trim(); const handleImg = e => { const f = e.target.files[0]; if (!f) return; const rd = new FileReader(); rd.onload = ev => setImgB64(ev.target.result); rd.readAsDataURL(f); }; const submit = () => { dispatch(isGun ? { type: 'ADD_TO_QUARANTINE', srcType: 'gun', gunId: sel, items, reason: reason.trim(), approver: approver.trim(), imageB64: imgB64 } : { type: 'ADD_TO_QUARANTINE', srcType: 'pallet', palletId: Number(sel), items, reason: reason.trim(), approver: approver.trim(), imageB64: imgB64 }); onClose(); }; return (
{sel && srcKeys.length === 0 &&
{isGun ? 'אין מלאי' : 'משטח ריק'}
} {sel && srcKeys.length > 0 && (
{srcKeys.map(r => (
{r.label} זמין: {container[r.key]} {r.unit} setQty(r.key, e.target.value)} style={{ width: '68px', textAlign: 'center' }} />
))}
)} {sel && srcKeys.length > 0 && <>
setReason(e.target.value)} />
setApprover(e.target.value)} />
}
); } const modes = [ { id: 'p2g', label: 'מרמסע לצוותים' }, { id: 'g2p', label: 'צוותים לרמסע' }, { id: 'g2g', label: 'צוות לצוות' }, { id: 'g2q', label: 'מצוות לפינת פסולים' }, { id: 'p2q', label: 'מרמסע לפינת פסולים' }, ]; return (
{modes.map(mo => ( ))}
{mode === 'p2g' && } {mode === 'g2p' && } {mode === 'g2g' && } {mode === 'g2q' && } {mode === 'p2q' && }
); } // ── Quarantine section (full panel) ────────────────────────── function QuarantineSection({ state, regs, dispatch }) { const [viewImg, setViewImg] = useStateT(null); const [authPending, setAuthPending] = useStateT(null); const [actionPending, setActionPending] = useStateT(null); const [dstGun, setDstGun] = useStateT(''); const log = state.quarantineLog || []; function confirmAction() { if (!actionPending) return; if (actionPending.type === 'return') { if (!dstGun) return; dispatch({ type: 'RETURN_FROM_QUARANTINE', entryId: actionPending.entry.id, dstGun }); } else { dispatch({ type: 'SCRAP_QUARANTINE', entryId: actionPending.entry.id }); } setActionPending(null); setDstGun(''); } return (
⛔ פינת פסולים רשומות: {log.length}
{log.length === 0 ? (
אין תחמושת פסולה
) : ( {[...log].reverse().map(r => ( ))}
תאריך ושעהמקורתחמושתסיבת פסילהגורם מאשרתמונהפעולות בוחן
{fmtT(r.datetime)} {r.src} {(r.items || []).map((it, j) => (
{keyLabelT(it.key, regs)} ×{it.qty}
))}
{r.reason} {r.approver} {r.imageB64 ? : }
)}
{authPending && ( { setActionPending(authPending); setAuthPending(null); setDstGun(''); }} onCancel={() => setAuthPending(null)} /> )} {actionPending && ( { setActionPending(null); setDstGun(''); }}>
תחמושת מהרשומה:
{(actionPending.entry.items || []).map((it, j) => (
{keyLabelT(it.key, regs)} ×{it.qty}
))}
מקור מקורי: {actionPending.entry.src}
{actionPending.type === 'return' && (
)} {actionPending.type === 'scrap' && (
⚠ התחמושת תסולק לצמיתות מהמערכת.
)}
)} {viewImg && (
setViewImg(null)}>
e.stopPropagation()}> תמונה
)}
); } window.TransferModal = TransferModal; window.QuarantineSection = QuarantineSection; })();