7.7 KiB
7.7 KiB
10. Frontend Architecture
State Management Strategy
┌─────────────────────────────────────────────────────────────────┐
│ STATE MANAGEMENT │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ TanStack Query │ │
│ │ (Server State / Cache) │ │
│ │ │ │
│ │ • Characters list │ │
│ │ • Accounts data │ │
│ │ • Teams & members │ │
│ │ • Progressions │ │
│ │ • DofusDB reference data │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Zustand │ │
│ │ (Client/UI State) │ │
│ │ │ │
│ │ • Selected items (multi-select) │ │
│ │ • UI preferences (sidebar collapsed, etc.) │ │
│ │ • Filter states │ │
│ │ • Modal open/close states │ │
│ │ • Theme preference │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ React State │ │
│ │ (Component-local State) │ │
│ │ │ │
│ │ • Form inputs │ │
│ │ • Hover/focus states │ │
│ │ • Animation states │ │
│ │ • Temporary UI states │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
TanStack Query Setup
// src/lib/client/query-client.ts
import { QueryClient } from '@tanstack/react-query';
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 30, // 30 minutes
retry: 1,
refetchOnWindowFocus: false,
},
mutations: {
onError: (error) => {
console.error('Mutation error:', error);
},
},
},
});
// Query keys factory
export const queryKeys = {
characters: {
all: ['characters'] as const,
list: (filters: CharacterFilters) => [...queryKeys.characters.all, 'list', filters] as const,
detail: (id: string) => [...queryKeys.characters.all, 'detail', id] as const,
},
accounts: {
all: ['accounts'] as const,
list: () => [...queryKeys.accounts.all, 'list'] as const,
detail: (id: string) => [...queryKeys.accounts.all, 'detail', id] as const,
},
teams: {
all: ['teams'] as const,
list: () => [...queryKeys.teams.all, 'list'] as const,
detail: (id: string) => [...queryKeys.teams.all, 'detail', id] as const,
},
progressions: {
all: ['progressions'] as const,
list: (type?: ProgressionType) => [...queryKeys.progressions.all, 'list', type] as const,
byCharacter: (characterId: string) => [...queryKeys.progressions.all, 'character', characterId] as const,
},
} as const;
Zustand Store
// src/lib/client/stores/ui-store.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface UIState {
// Sidebar
sidebarCollapsed: boolean;
toggleSidebar: () => void;
// Theme
theme: 'light' | 'dark';
setTheme: (theme: 'light' | 'dark') => void;
// Selection (for bulk actions)
selectedCharacterIds: string[];
selectCharacter: (id: string) => void;
deselectCharacter: (id: string) => void;
selectAllCharacters: (ids: string[]) => void;
clearSelection: () => void;
}
export const useUIStore = create<UIState>()(
persist(
(set) => ({
// Sidebar
sidebarCollapsed: false,
toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),
// Theme
theme: 'dark',
setTheme: (theme) => set({ theme }),
// Selection
selectedCharacterIds: [],
selectCharacter: (id) =>
set((state) => ({
selectedCharacterIds: [...state.selectedCharacterIds, id]
})),
deselectCharacter: (id) =>
set((state) => ({
selectedCharacterIds: state.selectedCharacterIds.filter((i) => i !== id)
})),
selectAllCharacters: (ids) => set({ selectedCharacterIds: ids }),
clearSelection: () => set({ selectedCharacterIds: [] }),
}),
{
name: 'dofus-manager-ui',
partialize: (state) => ({
sidebarCollapsed: state.sidebarCollapsed,
theme: state.theme,
}),
}
)
);
Routing Structure
// src/routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router';
import { AppShell } from '@/components/layout/app-shell';
export const Route = createRootRoute({
component: () => (
<AppShell>
<Outlet />
</AppShell>
),
});
// Route tree
/*
src/routes/
├── __root.tsx # Root layout with AppShell
├── index.tsx # / → Dashboard
├── characters/
│ ├── index.tsx # /characters → List
│ └── $id.tsx # /characters/:id → Detail
├── accounts/
│ ├── index.tsx # /accounts → List
│ └── $id.tsx # /accounts/:id → Detail
├── teams/
│ ├── index.tsx # /teams → List
│ └── $id.tsx # /teams/:id → Detail
├── progressions/
│ └── index.tsx # /progressions → Tracker
└── settings/
└── index.tsx # /settings → Settings
*/