import { create } from 'zustand'; export interface CalculatorState { activeSheet: string; setActiveSheet: (sheet: string) => void; // --- GENERAL --- general: { jobTitle: string; jobNo: string; calculatedBy: string; date: string; code: string; occupancyGroup: string; riskCategory: string; fireRating: { roof: number; floor: number; }; }; setGeneral: (vals: Partial) => void; // --- BUILDING GEOMETRY --- buildingGeometry: { roofSlope: string; // e.g., "0.25 / 12" buildingLength: number; leastWidth: number; meanRoofHeight: number; // Single source of truth for height parapetHeight: number; minimumParapetHeight: number; hb: number; roofType: 'Gable' | 'Hip' | 'Monoslope' | 'Flat'; }; setGeometry: (vals: Partial) => void; // --- WIND --- wind: { speed: number; exposure: string; directionality: number; // Kd internalPressure: number; // +/- GCpi // Topography (Kzt) topography: { factor: number; // Kzt shape: 'Flat' | 'Ridge' | 'Escarpment' | 'Hill'; hillHeight: number; // H halfHillLength: number; // Lh crestDistance: number; // x condition: 'Upwind' | 'Downwind'; }; // Gust Factor (G) gust: { factor: number; // G type: 'Rigid' | 'Flexible'; dampingRatio: number; naturalFrequency: number; buildingType: 'Steel MRF' | 'Concrete MRF' | 'Other'; // For approx freq }; // Enclosure enclosure: { classification: 'Enclosed' | 'Partially Enclosed' | 'Open'; reductionFactorRi: number; }; groundElevationFactor: number; // Ke }; setWind: (vals: Partial) => void; // --- SNOW --- snow: { groundLoad: number; // pg exposureFactor: number; // Ce thermalFactor: number; // Ct importanceFactor: number; // Is flatRoofSnow: number; // pf }; setSnow: (vals: Partial) => void; // --- SEISMIC --- seismic: { ss: number; s1: number; siteClass: string; importanceFactor: number; // Ie sds: number; // calc sd1: number; // calc designCategory: string; // calc }; setSeismic: (vals: Partial) => void; // --- MWFRS --- mwfrs: { ridgeOrientation: 'Parallel to L' | 'Normal to L'; userRidgeHeight: number; // optional override, default 0 means use meanRoofHeight }; setMwfrs: (vals: Partial) => void; // --- LIVE LOADS --- liveLoads: { roof: { range1: number; // 0 to 200 sf range2: string; // 200 to 600 sf (formula) range3: number; // over 600 sf }; floor: { typical: number; partitions: number; corridorsUpper: number; lobbies: number; }; }; setLiveLoads: (vals: Partial) => void; // --- TORNADO --- tornado: { Ae: number; Vt: number; Ke: number; KhTor: number; enclosure: string; isEssential: 'Yes' | 'No'; h: number; B: number; userG: string; // '0.85' or 'calc' }; setTornado: (vals: Partial) => void; } export const useCalculatorStore = create((set) => ({ activeSheet: 'Code', setActiveSheet: (sheet) => set({ activeSheet: sheet }), general: { jobTitle: 'Creech 2 - Admin Criteria', jobNo: '', calculatedBy: 'ACV', date: new Date().toLocaleDateString(), code: 'IBC 2024', occupancyGroup: 'F', riskCategory: 'III', fireRating: { roof: 0.0, floor: 0.0 }, }, setGeneral: (vals) => set((state) => { // Handle nested updates if necessary, but for now simple merge // For deep merge of general, we might need more logic if we pass partial nested objects. // But since we pass Partial, we need to be careful with fireRating. // Let's assume the component helps us or we do a spread. const merged = { ...state.general, ...vals }; // If vals has fireRating, it overwrites. Ideally we want deep merge but let's see usage. return { general: merged }; }), buildingGeometry: { roofSlope: '0.08 / 12', buildingLength: 50.4, leastWidth: 23.8, meanRoofHeight: 24.0, parapetHeight: 0.0, minimumParapetHeight: 0.0, hb: 0.0, roofType: 'Monoslope', }, setGeometry: (vals) => set((state) => ({ buildingGeometry: { ...state.buildingGeometry, ...vals } })), wind: { speed: 105, exposure: 'C', directionality: 0.85, internalPressure: 0.18, topography: { factor: 1.0, shape: 'Flat', hillHeight: 0, halfHillLength: 0, crestDistance: 0, condition: 'Upwind', }, gust: { factor: 0.85, type: 'Rigid', dampingRatio: 0.01, naturalFrequency: 0, buildingType: 'Other', }, enclosure: { classification: 'Enclosed', reductionFactorRi: 1.0, }, groundElevationFactor: 1.0, }, setWind: (vals) => set((state) => ({ wind: { ...state.wind, ...vals } })), snow: { groundLoad: 20, exposureFactor: 1.0, thermalFactor: 1.0, importanceFactor: 1.1, flatRoofSnow: 0, }, setSnow: (vals) => set((state) => ({ snow: { ...state.snow, ...vals } })), seismic: { ss: 0.2, s1: 0.1, siteClass: 'D', importanceFactor: 1.25, sds: 0, sd1: 0, designCategory: 'B', }, setSeismic: (vals) => set((state) => ({ seismic: { ...state.seismic, ...vals } })), mwfrs: { ridgeOrientation: 'Parallel to L', userRidgeHeight: 0, }, setMwfrs: (vals) => set((state) => ({ mwfrs: { ...state.mwfrs, ...vals } })), liveLoads: { roof: { range1: 20, range2: '24 - 0.02Area, but not less than 12 psf', range3: 12, }, floor: { typical: 50, // Offices partitions: 15, // Partitions corridorsUpper: 80, // Corridors above first floor lobbies: 100, // Lobbies & first floor corridors } }, setLiveLoads: (vals) => set((state) => ({ liveLoads: { ...state.liveLoads, ...vals } })), tornado: { Ae: 50000, Vt: 120.0, Ke: 1.00, KhTor: 1.00, enclosure: 'Enclosed Building', isEssential: 'Yes', h: 24.0, B: 23.8, userG: '0.85', }, setTornado: (vals) => set((state) => ({ tornado: { ...state.tornado, ...vals } })), }));