// RMItems.jsx — Master Data › Repair & Maintenance Items. // The catalog behind the R&M module: the fixed service-item list (with its // locked countdown interval) that drives the Maintenance Schedule, plus the // repair issue templates that populate the New Ticket dropdown. Admin edits // here; the Operations › Repair & Maintenance screen consumes these lists. const RM_ISSUE_TEMPLATES = [ 'Hydraulic leak', 'Engine fault', 'Slew gear noise', 'Outrigger drift', 'Boom inspection', 'Electrical fault', 'Tyre / wheel', 'Other (see Info)', ]; function intervalBand(months) { if (months <= 3) return { label: 'Frequent', cls: 'red' }; if (months <= 12) return { label: 'Routine', cls: 'yellow' }; return { label: 'Long-cycle', cls: 'green' }; } function RMItemsPage({ role }) { const isAdmin = role === 'Admin'; const [items, setItems] = React.useState(SERVICE_ITEMS.map((s, i) => ({ id: 'RMI-' + String(i + 1).padStart(2, '0'), ...s }))); const [issues] = React.useState(RM_ISSUE_TEMPLATES); const [q, setQ] = React.useState(''); const [showAdd, setShowAdd] = React.useState(false); const [draft, setDraft] = React.useState({ item: '', months: 6 }); const [editing, setEditing] = React.useState(null); const [editDraft, setEditDraft] = React.useState(null); const query = q.trim().toLowerCase(); const rows = items.filter(s => !query || s.item.toLowerCase().includes(query) || String(s.months).includes(query)); const syncGlobal = (next) => { setItems(next); // Keep the global catalog in sync so the R&M schedule + interval lookup update. SERVICE_ITEMS.length = 0; next.forEach(x => SERVICE_ITEMS.push({ item: x.item, months: x.months })); Object.keys(SERVICE_INTERVAL_MONTHS).forEach(k => delete SERVICE_INTERVAL_MONTHS[k]); next.forEach(x => { SERVICE_INTERVAL_MONTHS[x.item] = x.months; }); }; const addItem = () => { if (!draft.item.trim()) return; const id = 'RMI-' + String(items.length + 1).padStart(2, '0'); const next = [...items, { id, item: draft.item.trim(), months: Number(draft.months) || 6 }]; syncGlobal(next); setDraft({ item: '', months: 6 }); setShowAdd(false); }; const startEdit = (s) => { setEditing(s.id); setEditDraft({ ...s }); }; const saveEdit = () => { window.askAdminPassword('Edit R&M item · ' + editDraft.item, () => { syncGlobal(items.map(s => s.id === editDraft.id ? { ...editDraft, months: Number(editDraft.months) || 1 } : s)); setEditing(null); setEditDraft(null); }); }; const deleteItem = (s) => { window.askAdminPassword('Delete R&M item · ' + s.item, () => { syncGlobal(items.filter(x => x.id !== s.id)); }); }; return (
Repair & Maintenance Items — the master catalog behind the workshop. Service items carry a fixed countdown interval and drive the Maintenance Schedule on every crane; repair issue types populate the New Ticket form. Manage them here in Master Data — the Operations › Repair & Maintenance screen consumes these lists.
{items.length} service item{items.length === 1 ? '' : 's'} · {issues.length} repair issue type{issues.length === 1 ? '' : 's'}
{isAdmin ? ( ) : Admin only}
{/* Search */}
setQ(e.target.value)} placeholder="Search service items by name or interval..." className="input" style={{height: 46, paddingLeft: 44, paddingRight: q ? 40 : 14, width: '100%', fontSize: 15, borderRadius: 12}}/> {q ? ( ) : null}
{/* Service items catalog */}

Service Items

Fixed countdown interval (months) · applied to every crane
{rows.length} shown
{isAdmin ? : null} {rows.map(s => { const band = intervalBand(s.months); return ( {isAdmin ? ( ) : null} ); })} {rows.length === 0 ? ( ) : null}
IDService ItemInterval (fixed)FrequencyActions
{s.id} {editing === s.id ? ( setEditDraft({...editDraft, item: e.target.value})}/> ) : ( {s.item} )} {editing === s.id ? (
setEditDraft({...editDraft, months: e.target.value})}/> months
) : ( {s.months} mo )}
{band.label} {editing === s.id ? (
) : (
)}
No service items match “{q}”
Interval is fixed per item and applies fleet-wide. Changing it here updates the countdown on every scheduled crane.
{/* Repair issue templates */}

Repair Issue Types

Templates shown in the New Ticket dropdown
{issues.length}
{issues.map(issue => ( {issue} ))}
{/* Add service item modal */} {showAdd ? (
setShowAdd(false)}>
e.stopPropagation()} style={{maxWidth: 480}}>
Add Service Item
setDraft({...draft, item: e.target.value})} placeholder="e.g. Brake Fluid" autoFocus/>
setDraft({...draft, months: e.target.value})}/>
This becomes the locked countdown period applied to every crane.
) : null}
); } Object.assign(window, { RMItemsPage });