/** * useCalculatorState Hook * * Persists calculator state in localStorage to survive page reloads, * browser navigation, and Stripe checkout redirects. * * State automatically expires after 1 hour to prevent stale data. */ import { useState, useEffect } from 'react'; export interface CalculatorState { // Calculation type calculationType: 'fuel' | 'distance' | 'custom'; // Distance-based inputs distance: string; speed: string; fuelRate: string; // Fuel-based inputs fuelAmount: string; fuelUnit: 'liters' | 'gallons'; // Custom amount input customAmount: string; // Offset order settings offsetPercentage: number; portfolioId?: number; // Metadata timestamp: number; // Used for auto-expiry } const STORAGE_KEY = 'puffin_calculator_state'; const EXPIRY_MS = 60 * 60 * 1000; // 1 hour (per user preference) /** * Custom hook for calculator state persistence * * @returns Object with state, saveState, and clearState functions */ export function useCalculatorState() { const [state, setState] = useState(null); const [isLoaded, setIsLoaded] = useState(false); // Load from localStorage on mount useEffect(() => { const stored = localStorage.getItem(STORAGE_KEY); if (stored) { try { const parsed = JSON.parse(stored) as CalculatorState; const age = Date.now() - parsed.timestamp; // Check if state has expired if (age < EXPIRY_MS) { setState(parsed); } else { // State expired, clean up localStorage.removeItem(STORAGE_KEY); } } catch (err) { // Corrupted data, clean up console.warn('Failed to parse calculator state from localStorage:', err); localStorage.removeItem(STORAGE_KEY); } } setIsLoaded(true); }, []); /** * Save partial or complete state to localStorage * Merges with existing state */ const saveState = (newState: Partial) => { const updated: CalculatorState = { ...(state || { calculationType: 'fuel', distance: '', speed: '12', fuelRate: '100', fuelAmount: '', fuelUnit: 'liters', customAmount: '', offsetPercentage: 100, }), ...newState, timestamp: Date.now(), // Always update timestamp }; setState(updated); try { localStorage.setItem(STORAGE_KEY, JSON.stringify(updated)); } catch (err) { console.error('Failed to save calculator state to localStorage:', err); } }; /** * Clear calculator state from memory and localStorage * Call this after successful payment completion */ const clearState = () => { setState(null); try { localStorage.removeItem(STORAGE_KEY); } catch (err) { console.error('Failed to clear calculator state from localStorage:', err); } }; return { /** Current calculator state (null if none saved or expired) */ state, /** Whether state has been loaded from localStorage */ isLoaded, /** Save new or partial state */ saveState, /** Clear all saved state */ clearState, }; }