{!isEdit && (
{tabs.map((t, i) => (
{tabs.length > 1 && (
)}
))}
{tabs.length > 1 &&
{tabs.filter(canSubmitTab).length}/{tabs.length} מוכנות}
)}
{isEdit && (
⏱ עריכת בדיעבד:
שנה תאריך ושעה כדי לעדכן את מיקום הרשומה בציר הזמן. המיון מתבצע אוטומטית עם השמירה.
)}
{!isEdit && <>
בחר צוותים מתנערים:
{GUNS_F.map(g => )}
>}
{state.registeredTypes.length > 0 && (
📋 מלאי צוותים — חי (מתעדכן בעת השאלה)
| תחמושת |
{GUNS_F.map(g => צוות {g}{m.selGuns.includes(g) ? ' ✓' : ''} | )}
{[...state.registeredTypes.filter(r => r.category === 'shell'), ...state.registeredTypes.filter(r => r.category === 'charge'), ...state.registeredTypes.filter(r => r.category === 'fuze')].map(r => (
| {r.label} | {GUNS_F.map(g => {badgeF(m.localGuns[g]?.[r.key] || 0)} | )}
))}
)}
{m.selGuns.map(g => {
const combos = m.gunCombos[g] || [];
const gShells = state.registeredTypes.filter(r => r.category === 'shell' && (m.localGuns[g]?.[r.key] || 0) > 0);
const gCharges = state.registeredTypes.filter(r => r.category === 'charge' && (m.localGuns[g]?.[r.key] || 0) > 0);
const gFuzes = state.registeredTypes.filter(r => r.category === 'fuze' && (m.localGuns[g]?.[r.key] || 0) > 0);
return (
צוות {g} — תצורות ירי
{['פגז', 'חנ"ה', 'מטען', 'מרעום', 'כמות', ''].map((h, i) =>
{h}
)}
{combos.map(c => {
const qty = parseInt(c.shellQty) || 0;
const beh = comboChargeBeh(c);
const needSub = beh && (beh.kind === 'separate' || beh.kind === 'modular');
const ded = comboChargeInvDed(c);
const maxQ = comboMaxQty(m, g, c);
const shellAv = c.shellKey ? avail(m, g, c.shellKey, c.id) : 0;
const fuzeAv = c.fuzeKey ? avail(m, g, c.fuzeKey, c.id) : 0;
const chargeAv = c.chargeKey ? avail(m, g, c.chargeKey, c.id) : 0;
const shellOk = !c.shellKey || qty <= shellAv;
const fuzeOk = !c.fuzeKey || qty <= fuzeAv;
const chargeOk = !c.chargeKey || ded <= chargeAv;
const allOk = shellOk && fuzeOk && chargeOk;
const isValid = comboIsValid(m, g, c);
return (
{needSub ? (
) :
—
}
setC(g, c.id, 'shellQty', e.target.value)} style={{ textAlign: 'center' }} disabled={needSub && !c.chargeSubOpt} />
{combos.length > 1 ?
:
}
{qty > 0 && c.shellKey && c.chargeKey && c.fuzeKey && (
🔵 פגז ×{qty} (זמין:{shellAv})
🟡 מרעום ×{qty} (זמין:{fuzeAv})
⚡ חנ"ה {beh?.kind === 'modular' ? `${ded} מודולים (${c.chargeSubOpt || '?'} × ${qty})` : `×${ded}`} (זמין:{chargeAv})
)}
{qty > 0 && (!allOk || (!isValid && (c.shellKey || c.chargeKey || c.fuzeKey))) && (
⚠{!shellOk ? ` פגז חסר ${qty - shellAv}` : ''}{!fuzeOk ? ` | מרעום חסר ${qty - fuzeAv}` : ''}{!chargeOk ? ` | חנ"ה חסר ${ded - chargeAv}` : ''}{needSub && !c.chargeSubOpt ? ' | נדרש לבחור אזור חנ"ה' : ''}
)}
);
})}
);
})}
{!isEdit && m.selGuns.length > 0 && (
↕ משוך חוסר מצוות אחר (השאלה)
{m.borrowSrc && borrowAvailRegs.length > 0 && (
{borrowAvailRegs.map(r => (
{r.label}
זמין: {borrowSrcAmmo[r.key]}
setBQ(r.key, e.target.value)} style={{ width: '60px', textAlign: 'center' }} />
))}
)}
מעדכן מלאי ורושם בהיסטוריה מיד
)}
{!isEdit && (
📋
בדיקות הכרחיות במהלך האש
{CHECKLIST.filter(c => m.checks[c.id]).length} / {CHECKLIST.length}
{CHECKLIST.map((item, ci) => {
const checked = !!m.checks[item.id];
return (
);
})}
{!allChecked && ammoReady &&
⚠ יש לסמן את כל 9 הבדיקות לפני השיגור
}
)}
{isEdit ? (
) : (
)}
);
}
// ── Edit gun stock ───────────────────────────────────────────
const CUSTOM_SENTINEL = '__OTHER__';
const CAT_OPTIONS = [{ value: 'shell', label: 'פגז', unit: 'יח"' }, { value: 'charge', label: 'חנ"ה', unit: 'מטען' }, { value: 'fuze', label: 'מרעום', unit: 'יח"' }];
function EditGunStockModal({ state, dispatch, onClose }) {
const regs = state.registeredTypes;
const [showAuth, setShowAuth] = useStateF(!!(window.APP_CONFIG?.requireEditAuth ?? true));
const [gun, setGun] = useStateF('');
const [rows, setRows] = useStateF([]);
const loadGun = g => {
setGun(g);
if (!g) { setRows([]); return; }
const inv = state.guns[g] || {};
// Include all keys that have qty > 0, even if not in regs catalog
const invKeys = Object.entries(inv).filter(([, v]) => v > 0);
setRows(invKeys.map(([key, qty]) => {
const reg = regs.find(r => r.key === key);
return { id: genIdF(), key, qty: String(qty), isNew: false, isCustom: false,
customLabel: '', customCat: 'shell', customSubType: '', customSeries: '',
_fallbackLabel: reg?.label || keyLabelF(key) };
}));
};
const usedKeys = new Set(rows.filter(r => r.key && r.key !== CUSTOM_SENTINEL).map(r => r.key));
const availableToAdd = regs.filter(r => !usedKeys.has(r.key));
const updateQty = (id, v) => setRows(p => p.map(r => r.id === id ? { ...r, qty: v } : r));
const removeRow = id => setRows(p => p.filter(r => r.id !== id));
const addRow = () => setRows(p => [...p, { id: genIdF(), key: '', qty: '', isNew: true, isCustom: false, customLabel: '', customCat: 'shell', customSubType: '', customSeries: '' }]);
const setCustomLabel = (id, v) => setRows(p => p.map(r => r.id === id ? { ...r, customLabel: v } : r));
const setCustomCat = (id, v) => setRows(p => p.map(r => r.id === id ? { ...r, customCat: v, customSubType: '', customSeries: '' } : r));
const setCustomSubType = (id, v) => setRows(p => p.map(r => r.id === id ? { ...r, customSubType: v } : r));
const setCustomSeries = (id, v) => setRows(p => p.map(r => r.id === id ? { ...r, customSeries: v } : r));
const setNewKey = (id, k) => {
if (k === CUSTOM_SENTINEL) setRows(p => p.map(r => r.id === id ? { ...r, key: CUSTOM_SENTINEL, isCustom: true, customLabel: '', customCat: 'shell', customSubType: '', customSeries: '' } : r));
else setRows(p => p.map(r => r.id === id ? { ...r, key: k, isCustom: false, customLabel: '', customCat: 'shell', customSubType: '', customSeries: '' } : r));
};
const rowIsValid = r => {
if (!r.isNew) return r.key && parseInt(r.qty) >= 0;
if (r.isCustom) {
const q = parseInt(r.qty);
if (!r.customCat || !q) return false;
if (r.customCat === 'charge') return !!r.customSubType && !!r.customSeries.trim();
return !!r.customLabel.trim();
}
return r.key && r.key !== CUSTOM_SENTINEL && parseInt(r.qty) >= 0;
};
const canSubmit = gun && rows.length > 0 && rows.every(rowIsValid);
const handleSubmit = () => {
const ammo = {}, newTypes = [];
rows.forEach(r => {
const q = parseInt(r.qty) || 0;
if (!q) return;
if (r.isCustom) {
const cat = r.customCat || 'shell';
let key, displayLabel, unit;
if (cat === 'charge') {
const cType = r.customSubType; const series = r.customSeries.trim();
if (!cType || !series) return;
key = mckF(cType, series); displayLabel = `${cType} סדרה ${series}`; unit = CB_F[cType]?.unit || 'מטען';
} else if (cat === 'fuze') { const label = r.customLabel.trim(); if (!label) return; key = mfkF(label); displayLabel = label; unit = 'יח"'; }
else { const label = r.customLabel.trim(); if (!label) return; key = mskF(label); displayLabel = label; unit = 'יח"'; }
ammo[key] = q;
if (!regs.find(x => x.key === key)) newTypes.push({ key, label: displayLabel, category: cat, unit, chargeType: cat === 'charge' ? r.customSubType : null, series: cat === 'charge' ? r.customSeries.trim() : null });
} else if (r.key && r.key !== CUSTOM_SENTINEL) ammo[r.key] = q;
});
dispatch({ type: 'EDIT_GUN_STOCK', gun, ammo, newTypes });
onClose();
};
if (showAuth) return