// CTSC store — localStorage-backed collections + auth, exposed via React context. const CTSCStore = (function () { const LS_KEY = 'ctsc_store_v5'; const AUTH_KEY = 'ctsc_auth_v3'; const SEED = window.CTSC_SEED; function defaults() { return { federations: SEED.FEDERATIONS, heroes: SEED.HEROES, events: SEED.EVENTS, news: SEED.NEWS, coaching: SEED.COACHING, fundraising: SEED.FUNDRAISING, blog: SEED.BLOG, colours: SEED.COLOURS || [], awards: SEED.AWARDS || [], awardEvents: SEED.AWARD_EVENTS || [], nominations: SEED.NOMINATIONS || [], documents: SEED.DOCUMENTS || [], calendar: SEED.CALENDAR || [], scorecards: SEED.SCORECARDS || [], scorecardCycle: SEED.SCORECARD_CYCLE || { activeYear: '2026/2027', years: ['2025/2026', '2026/2027'] }, credentials: SEED.CREDENTIALS || {}, }; } function load() { const base = defaults(); try { const raw = localStorage.getItem(LS_KEY); if (raw) { const saved = JSON.parse(raw); // merge: keep saved collections, seed any that are missing (e.g. newly added features) return { ...base, ...saved }; } } catch (e) {} return base; } function loadAuth() { try { return JSON.parse(localStorage.getItem(AUTH_KEY)) || null; } catch (e) { return null; } } const StoreCtx = React.createContext(null); function StoreProvider({ children }) { const [data, setData] = React.useState(load); const [user, setUser] = React.useState(loadAuth); React.useEffect(() => { localStorage.setItem(LS_KEY, JSON.stringify(data)); }, [data]); React.useEffect(() => { if (user) localStorage.setItem(AUTH_KEY, JSON.stringify(user)); else localStorage.removeItem(AUTH_KEY); }, [user]); const uid = (p) => p + '_' + Math.random().toString(36).slice(2, 8); const actions = { login: (u) => setUser(u), logout: () => setUser(null), addItem: (coll, item) => setData(d => ({ ...d, [coll]: [{ ...item, id: uid(coll) }, ...d[coll]] })), updateItem: (coll, id, patch) => setData(d => ({ ...d, [coll]: d[coll].map(x => x.id === id ? { ...x, ...patch } : x) })), deleteItem: (coll, id) => setData(d => ({ ...d, [coll]: d[coll].filter(x => x.id !== id) })), setStatus: (coll, id, status) => setData(d => ({ ...d, [coll]: d[coll].map(x => x.id === id ? { ...x, status } : x) })), updateCycle: (patch) => setData(d => ({ ...d, scorecardCycle: { ...d.scorecardCycle, ...patch } })), setPassword: (key, password, meta = {}) => setData(d => ({ ...d, credentials: { ...(d.credentials || {}), [key]: { password, updated: new Date().toISOString().slice(0, 10), ...meta } } })), resetAll: () => { localStorage.removeItem(LS_KEY); setData(load()); }, }; return {children}; } function useStore() { return React.useContext(StoreCtx); } // helpers function fedName(data, id) { const f = data.federations.find(x => x.id === id); return f ? f.name : 'Cape Town Sport Council'; } function fmtDate(s) { const d = new Date(s + 'T00:00:00'); return d.toLocaleDateString('en-ZA', { day: 'numeric', month: 'short', year: 'numeric' }); } function fmtMoney(n) { return 'R' + n.toLocaleString('en-ZA'); } return { StoreProvider, useStore, fedName, fmtDate, fmtMoney }; })(); window.CTSCStore = CTSCStore;