Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | 'use client' import { useState, useEffect, useRef } from 'react' import type { WorksheetFormState } from '@/app/create/worksheets/types' import { defaultAdditionConfig } from '@/app/create/worksheets/config-schemas' interface UseWorksheetStateReturn { formState: WorksheetFormState debouncedFormState: WorksheetFormState updateFormState: (updates: Partial<WorksheetFormState>) => void } /** * Manage worksheet state with debouncing and seed regeneration * * Features: * - Immediate form state updates for controls * - Debounced state updates for preview (500ms) * - Automatic seed regeneration when problem settings change * - StrictMode-safe (handles double renders) */ export function useWorksheetState( initialSettings: Omit<WorksheetFormState, 'date' | 'rows' | 'total'> ): UseWorksheetStateReturn { // Calculate derived state from initial settings const problemsPerPage = initialSettings.problemsPerPage ?? 20 const pages = initialSettings.pages ?? 1 const cols = initialSettings.cols ?? 5 const rows = Math.ceil((problemsPerPage * pages) / cols) const total = problemsPerPage * pages // Immediate form state (for controls - updates instantly) const [formState, setFormState] = useState<WorksheetFormState>(() => { const initial = { ...initialSettings, rows, total, date: '', // Will be set at generation time // Ensure displayRules is always defined (critical for difficulty adjustment) displayRules: initialSettings.displayRules ?? defaultAdditionConfig.displayRules, pAnyStart: initialSettings.pAnyStart ?? defaultAdditionConfig.pAnyStart, pAllStart: initialSettings.pAllStart ?? defaultAdditionConfig.pAllStart, } console.log('[useWorksheetState] Initial formState:', { seed: initial.seed, displayRules: initial.displayRules, }) return initial }) // Debounced form state (for preview - updates after delay) const [debouncedFormState, setDebouncedFormState] = useState<WorksheetFormState>(() => { console.log('[useWorksheetState] Initial debouncedFormState (same as formState)') return formState }) // Store the previous formState to detect real changes const prevFormStateRef = useRef(formState) // Log whenever debouncedFormState changes (this triggers preview re-fetch) useEffect(() => { console.log('[useWorksheetState] debouncedFormState changed - preview will re-fetch:', { seed: debouncedFormState.seed, problemsPerPage: debouncedFormState.problemsPerPage, }) }, [debouncedFormState]) // Debounce preview updates (500ms delay) - only when formState actually changes useEffect(() => { console.log('[useWorksheetState Debounce] Triggered') console.log('[useWorksheetState Debounce] Current formState seed:', formState.seed) console.log( '[useWorksheetState Debounce] Previous formState seed:', prevFormStateRef.current.seed ) // Skip if formState hasn't actually changed (handles StrictMode double-render) if (formState === prevFormStateRef.current) { console.log('[useWorksheetState Debounce] Skipping - formState reference unchanged') return } prevFormStateRef.current = formState console.log('[useWorksheetState Debounce] Setting timer to update debouncedFormState in 500ms') const timer = setTimeout(() => { console.log('[useWorksheetState Debounce] Timer fired - updating debouncedFormState') setDebouncedFormState(formState) }, 500) return () => { console.log('[useWorksheetState Debounce] Cleanup - clearing timer') clearTimeout(timer) } }, [formState]) const updateFormState = (updates: Partial<WorksheetFormState>) => { console.log('[useWorksheetState] updateFormState called with:', updates) setFormState((prev) => { const newState = { ...prev, ...updates } // Generate new seed when problem settings change const affectsProblems = updates.problemsPerPage !== undefined || updates.cols !== undefined || updates.pages !== undefined || updates.orientation !== undefined || updates.pAnyStart !== undefined || updates.pAllStart !== undefined || updates.interpolate !== undefined if (affectsProblems) { newState.seed = Date.now() % 2147483647 console.log( '[useWorksheetState] Problem settings changed - generated new seed:', newState.seed ) } console.log('[useWorksheetState] New formState:', { displayRules: newState.displayRules, additionDisplayRules: (newState as any).additionDisplayRules, subtractionDisplayRules: (newState as any).subtractionDisplayRules, mode: newState.mode, operator: newState.operator, }) return newState }) } return { formState, debouncedFormState, updateFormState, } } |