// Admin managers for the Resources hub — Documents (file upload) + Calendar. const HUBADMIN = (function () { const fileSize = (bytes) => bytes < 1024 ? bytes + ' B' : bytes < 1048576 ? (bytes / 1024).toFixed(0) + ' KB' : (bytes / 1048576).toFixed(1) + ' MB'; const extOf = (name) => { const m = (name || '').match(/\.([a-z0-9]+)$/i); return m ? m[1].toUpperCase() : 'FILE'; }; function Dialog({ title, onClose, children, footer }) { return (
e.stopPropagation()} className="fade-in" style={{ background: '#fff', borderRadius: 14, width: 'min(560px,100%)', maxHeight: '88vh', overflow: 'auto', boxShadow: 'var(--shadow-lg)' }}>

{title}

{children}
{footer}
); } // ---------------- Documents ---------------- function DocForm({ item, onClose }) { const { data, actions } = CTSCStore.useStore(); const { DOC_CATS } = CTSCHub; const [v, setV] = React.useState(item ? { ...item } : { title: '', category: 'Constitution', fedId: '', date: '2026-06-09', note: '', ext: '', size: '', data: '' }); const set = (k, val) => setV(s => ({ ...s, [k]: val })); const ref = React.useRef(); const pick = (e) => { const f = e.target.files[0]; if (!f) return; const r = new FileReader(); r.onload = () => setV(s => ({ ...s, data: r.result, ext: extOf(f.name), size: fileSize(f.size), title: s.title || f.name.replace(/\.[a-z0-9]+$/i, '') })); r.readAsDataURL(f); }; const save = () => { const payload = { ...v, fedId: v.fedId || null, status: 'Published' }; if (item) actions.updateItem('documents', item.id, payload); else actions.addItem('documents', payload); onClose(); }; const valid = v.title.trim() && (v.data || item); return ( }>
ref.current.click()} style={{ border: '1.5px dashed var(--line)', borderRadius: 8, padding: 22, textAlign: 'center', cursor: 'pointer', background: '#fbfcfe' }}> {v.data ?
{v.ext} file ready · {v.size}
Click to replace
:
Click to upload a file
PDF, Word or Excel
}
set('title', e.target.value)} placeholder="e.g. CTSC Constitution 2024" />
set('date', e.target.value)} />