Implemented complete design system and foundational infrastructure: **Design System Components:** - Button (all variants: primary, secondary, ghost, danger) - Input & Textarea (with validation and error states) - Card (elevated, outlined, flat variants) - Modal/Dialog (with focus trap and accessibility) - Avatar (with fallback initials) - Badge (all color variants) - Form helpers (FormField, Checkbox, Select) - Link component with Next.js integration - Navigation (Header, Footer with responsive design) **Layouts:** - MainLayout (with Header/Footer for public pages) - AuthLayout (minimal layout for auth flows) - DashboardLayout (with sidebar navigation) **Hooks & Utilities:** - useAuth() - authentication state management - useApi() - API calls with loading/error states - useLocalStorage() - persistent state management - apiClient - Axios instance with token refresh - authStore - Zustand store for auth state **Configuration:** - Tailwind config with design tokens - Dark mode support via CSS variables - Global styles with accessibility focus - WCAG 2.2 AA+ compliant focus indicators All components follow accessibility best practices with proper ARIA labels, keyboard navigation, and screen reader support. Job ID: MTAD-IMPL-2025-11-18-CL
63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect } from 'react'
|
|
|
|
export function useLocalStorage<T>(key: string, initialValue: T) {
|
|
// State to store our value
|
|
// Pass initial state function to useState so logic is only executed once
|
|
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
if (typeof window === 'undefined') {
|
|
return initialValue
|
|
}
|
|
|
|
try {
|
|
// Get from local storage by key
|
|
const item = window.localStorage.getItem(key)
|
|
// Parse stored json or if none return initialValue
|
|
return item ? JSON.parse(item) : initialValue
|
|
} catch (error) {
|
|
console.error(`Error loading localStorage key "${key}":`, error)
|
|
return initialValue
|
|
}
|
|
})
|
|
|
|
// Return a wrapped version of useState's setter function that
|
|
// persists the new value to localStorage.
|
|
const setValue = (value: T | ((val: T) => T)) => {
|
|
try {
|
|
// Allow value to be a function so we have same API as useState
|
|
const valueToStore =
|
|
value instanceof Function ? value(storedValue) : value
|
|
|
|
// Save state
|
|
setStoredValue(valueToStore)
|
|
|
|
// Save to local storage
|
|
if (typeof window !== 'undefined') {
|
|
window.localStorage.setItem(key, JSON.stringify(valueToStore))
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error setting localStorage key "${key}":`, error)
|
|
}
|
|
}
|
|
|
|
// Listen for changes to this key in other tabs/windows
|
|
useEffect(() => {
|
|
if (typeof window === 'undefined') return
|
|
|
|
const handleStorageChange = (e: StorageEvent) => {
|
|
if (e.key === key && e.newValue !== null) {
|
|
try {
|
|
setStoredValue(JSON.parse(e.newValue))
|
|
} catch (error) {
|
|
console.error(`Error parsing storage event for key "${key}":`, error)
|
|
}
|
|
}
|
|
}
|
|
|
|
window.addEventListener('storage', handleStorageChange)
|
|
return () => window.removeEventListener('storage', handleStorageChange)
|
|
}, [key])
|
|
|
|
return [storedValue, setValue] as const
|
|
}
|