import { create } from 'zustand'; import { calculateHoleWidth, calculateHoleMinWidth, calculateHoleMaxWidth, calculateSidePanelWidth, calculateDoorLeafWidth, type DoorConfig, type SidePanel, } from './calculations'; import type { GlassPattern } from './glass-patterns'; import { calculatePrice, type PriceBreakdown } from './pricing'; export type DoorType = 'taats' | 'scharnier' | 'paneel'; export type GridType = | 'geen' | '2-vlak' | '3-vlak' | '4-vlak' | '6-vlak' | '8-vlak' | 'kruis' | 'ongelijk-3' | 'boerderij' | 'herenhuis'; export type Finish = 'zwart' | 'brons' | 'grijs' | 'goud' | 'beige' | 'ral'; export type GlassColor = 'helder' | 'grijs' | 'brons' | 'mat-blank' | 'mat-brons' | 'mat-zwart'; export type FrameSize = 20 | 30 | 40; export type Handle = 'beugelgreep' | 'hoekgreep' | 'maangreep' | 'ovaalgreep' | 'klink' | 'u-greep' | 'geen'; interface ConfiguratorState { // Door configuration doorType: DoorType; doorConfig: DoorConfig; sidePanel: SidePanel; // Styling gridType: GridType; finish: Finish; glassColor: GlassColor; handle: Handle; glassPattern: GlassPattern; frameSize: FrameSize; // Dimensions (in mm) width: number; height: number; // Calculated values holeWidth: number; doorLeafWidth: number; sidePanelWidth: number; minWidth: number; maxWidth: number; // Pricing priceBreakdown: PriceBreakdown; // Contact info name: string; email: string; phone: string; note: string; // Extra options extraOptions: string[]; // Screenshot screenshotDataUrl: string | null; // Actions setDoorType: (type: DoorType) => void; setDoorConfig: (config: DoorConfig) => void; setSidePanel: (panel: SidePanel) => void; setGridType: (type: GridType) => void; setFinish: (finish: Finish) => void; setGlassColor: (color: GlassColor) => void; setHandle: (handle: Handle) => void; setGlassPattern: (pattern: GlassPattern) => void; setFrameSize: (size: FrameSize) => void; setWidth: (width: number) => void; setHeight: (height: number) => void; setDimensions: (width: number, height: number) => void; setName: (name: string) => void; setEmail: (email: string) => void; setPhone: (phone: string) => void; setNote: (note: string) => void; toggleExtraOption: (option: string) => void; setScreenshotDataUrl: (url: string | null) => void; } // Helper function for recalculation const recalculate = (get: () => ConfiguratorState, set: (state: Partial) => void) => { const { width, doorConfig, sidePanel } = get(); set({ holeWidth: calculateHoleWidth(width, doorConfig, sidePanel), doorLeafWidth: calculateDoorLeafWidth(width, doorConfig, sidePanel), sidePanelWidth: calculateSidePanelWidth(width, doorConfig, sidePanel), minWidth: calculateHoleMinWidth(doorConfig, sidePanel), maxWidth: calculateHoleMaxWidth(doorConfig, sidePanel), }); }; // Helper function for price recalculation const recalculatePrice = (get: () => ConfiguratorState, set: (state: Partial) => void) => { const { doorLeafWidth, height, doorType, gridType, doorConfig, sidePanel, handle, finish, frameSize } = get(); const priceBreakdown = calculatePrice(doorLeafWidth, height, doorType, gridType, doorConfig, sidePanel, handle, finish, frameSize); set({ priceBreakdown }); }; export const useConfiguratorStore = create((set, get) => ({ // Initial state doorType: 'taats', doorConfig: 'enkele', sidePanel: 'geen', gridType: '3-vlak', finish: 'zwart', glassColor: 'helder', handle: 'beugelgreep', glassPattern: 'standard', frameSize: 40, width: 1000, height: 2400, // Initial calculated values holeWidth: 1160, doorLeafWidth: 1000, sidePanelWidth: 0, minWidth: 860, maxWidth: 1360, // Initial price priceBreakdown: calculatePrice(1000, 2400, 'taats', '3-vlak', 'enkele', 'geen', 'beugelgreep', 'zwart', 40), // Contact info name: '', email: '', phone: '', note: '', // Extra options extraOptions: [], // Screenshot screenshotDataUrl: null, // Actions with automatic recalculation setDoorType: (doorType) => { set({ doorType }); recalculate(get, set); recalculatePrice(get, set); }, setDoorConfig: (doorConfig) => { set({ doorConfig }); recalculate(get, set); recalculatePrice(get, set); }, setSidePanel: (sidePanel) => { set({ sidePanel }); recalculate(get, set); recalculatePrice(get, set); }, setGridType: (gridType) => { set({ gridType }); recalculatePrice(get, set); }, setFinish: (finish) => { set({ finish }); recalculatePrice(get, set); }, setGlassColor: (glassColor) => set({ glassColor }), setHandle: (handle) => { set({ handle }); recalculatePrice(get, set); }, setGlassPattern: (glassPattern) => set({ glassPattern }), setFrameSize: (frameSize) => { set({ frameSize }); recalculatePrice(get, set); }, setWidth: (width) => { const { doorConfig, sidePanel } = get(); const minWidth = calculateHoleMinWidth(doorConfig, sidePanel); const maxWidth = calculateHoleMaxWidth(doorConfig, sidePanel); const clampedWidth = Math.max(minWidth, Math.min(maxWidth, width)); set({ width: clampedWidth }); recalculate(get, set); recalculatePrice(get, set); }, setHeight: (height) => { const clampedHeight = Math.max(1800, Math.min(3000, height)); set({ height: clampedHeight }); recalculatePrice(get, set); }, setDimensions: (width, height) => { get().setWidth(width); get().setHeight(height); }, setName: (name) => set({ name }), setEmail: (email) => set({ email }), setPhone: (phone) => set({ phone }), setNote: (note) => set({ note }), toggleExtraOption: (option) => { const { extraOptions } = get(); if (extraOptions.includes(option)) { set({ extraOptions: extraOptions.filter((o) => o !== option) }); } else { set({ extraOptions: [...extraOptions, option] }); } }, setScreenshotDataUrl: (screenshotDataUrl) => set({ screenshotDataUrl }), }));