Files
dofus-manager/docs/architecture/10-frontend-architecture.md
2026-01-19 08:52:38 +01:00

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
*/