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
75 lines
1.7 KiB
TypeScript
75 lines
1.7 KiB
TypeScript
import { create } from 'zustand'
|
|
import { persist } from 'zustand/middleware'
|
|
|
|
export interface User {
|
|
id: string
|
|
email: string
|
|
display_name?: string
|
|
is_verified: boolean
|
|
}
|
|
|
|
export interface AuthState {
|
|
user: User | null
|
|
accessToken: string | null
|
|
refreshToken: string | null
|
|
isAuthenticated: boolean
|
|
|
|
// Actions
|
|
setAuth: (user: User, accessToken: string, refreshToken: string) => void
|
|
updateUser: (user: Partial<User>) => void
|
|
clearAuth: () => void
|
|
}
|
|
|
|
export const useAuthStore = create<AuthState>()(
|
|
persist(
|
|
(set) => ({
|
|
user: null,
|
|
accessToken: null,
|
|
refreshToken: null,
|
|
isAuthenticated: false,
|
|
|
|
setAuth: (user, accessToken, refreshToken) => {
|
|
// Store tokens in localStorage for API client
|
|
if (typeof window !== 'undefined') {
|
|
localStorage.setItem('access_token', accessToken)
|
|
localStorage.setItem('refresh_token', refreshToken)
|
|
}
|
|
|
|
set({
|
|
user,
|
|
accessToken,
|
|
refreshToken,
|
|
isAuthenticated: true,
|
|
})
|
|
},
|
|
|
|
updateUser: (updates) => {
|
|
set((state) => ({
|
|
user: state.user ? { ...state.user, ...updates } : null,
|
|
}))
|
|
},
|
|
|
|
clearAuth: () => {
|
|
// Clear tokens from localStorage
|
|
if (typeof window !== 'undefined') {
|
|
localStorage.removeItem('access_token')
|
|
localStorage.removeItem('refresh_token')
|
|
}
|
|
|
|
set({
|
|
user: null,
|
|
accessToken: null,
|
|
refreshToken: null,
|
|
isAuthenticated: false,
|
|
})
|
|
},
|
|
}),
|
|
{
|
|
name: 'auth-storage',
|
|
partialize: (state) => ({
|
|
user: state.user,
|
|
// Don't persist tokens in zustand, only in localStorage
|
|
}),
|
|
}
|
|
)
|
|
)
|