# Refactor Guide – Deep Dive into the Khata‑UI Codebase > This document walks through the entire repository, explains the current architecture, and provides a step‑by‑step refactor plan that will improve maintainability, type safety, and UI/UX while preserving the existing functional behavior. --- ## 1. Repository Layout (high‑level) ``` khata-ui/ ├─ react-openapi/ # Core UI generated from OpenAPI configs │ ├─ components/ # UI pieces: EnhancedTable, FilterBar, etc. │ ├─ types/ # TypeScript interfaces (config, overrides) │ └─ utils/ # Helper utilities (options, template resolution) ├─ src/ # Application entry point and pages │ ├─ auth/ # Authentication context, hooks, and protected routes │ ├─ pages/ # Dynamic resources (list, form) │ └─ main.tsx # React root, providers, theming ├─ public/ # Static assets (favicon, index.html) ├─ index.html ├─ package.json └─ tsconfig.json ``` ### Key Concepts | Area | Responsibility | |------|-----------------| | **Auth** | Central JWT handling, `AuthProvider`, `useAuth`, route guarding. | | **OpenAPI‑driven UI** | Describes each resource via `ResourceConfig`/`ResourceField`. Generates tables, filters, and forms automatically. | | **Data Layer** | TanStack Query (`useQuery`) fetches data; Axios instance carries auth token via interceptor. | | **Theming** | MUI theme with light/dark mode toggle (future). | | **Extensibility** | `components` prop on `EnhancedTable` / `FilterBar` lets callers inject custom cell renderers, filter widgets, or action buttons. | --- ## 2. Detailed Module Walk‑through ### 2.1 `react-openapi/types/config.ts` ```ts export interface ResourceField { displayFormat: string; // <- single source of truth for rendering type: FieldType; label: string; required?: boolean; options?: string[]; readOnly?: boolean; schema?: Record; formatter?: (value: any) => string; relation?: string; filterType?: "autocomplete" | "multiselect" | "number-range" | "date-range"; enumOption?: EnumOption; enumLabels?: Record; } ``` - `displayFormat` replaces the legacy `displayField`. It can be a **template string** (`"{{first}} {{last}}"`) or an **array of keys** for concatenation. - All UI components now rely exclusively on this field. ### 2.2 `react-openapi/utils/options.ts` - `resolveTemplate(format: string, item: any)` – interpolates `{{key}}` placeholders. - `getFieldOptions`, `toGridValueOptions` convert enum definitions into MUI‑compatible arrays. - **Refactor idea**: Move the `displayFormat` resolution logic from `EnhancedTable`/`FilterBar` into a dedicated helper (`formatDisplay(item, field)`), reducing duplication. ### 2.3 `react-openapi/components/EnhancedTable.tsx` - **Core responsibilities** 1. Build column definitions from `config.fields`. 2. Render each cell via `FieldRenderer`. 3. Provide server‑side or client‑side pagination. 4. Add a static "Actions" column. - **Key functions** - `getFormattedDisplayValue(item, displayFormat?, enumValue?)` – now uses `resolveTemplate` and falls back to generic fields. - `FieldRenderer` – decides how to render a cell based on `field.type`, `field.relation`, custom renderers, and `displayFormat`. - **Duplication**: Both `EnhancedTable` and `FilterBar` perform very similar `displayFormat` extraction. Extracting this into a shared utility will shrink the component size and make testing easier. ### 2.4 `react-openapi/components/FilterBar.tsx` - Generates filter controls for each **filterable** field. - Uses `extractOptions` to populate autocomplete lists, falling back to `displayFormat` for label generation. - **Opportunity**: Replace the inline `pull` helper with the shared formatter from `utils/options`. ### 2.5 Authentication (`src/auth`) - `AuthContext.tsx` – provides `user`, `accessToken`, `isAuthenticated` plus actions. - `useAuth.ts` – thin wrapper exposing the context values. - `ProtectedRoute.tsx` – guards routes, redirects to `/login` when unauthenticated. - `api.ts` – thin Axios wrapper (`login`, `logout`, `refresh`). - **Refactor suggestions** - Consolidate token storage (localStorage ↔ sessionStorage) behind a small `tokenStore` service. - Add automatic token refresh using an interceptor that retries the original request. - Provide a hook (`useAuthorizedQuery`) that injects the auth token into TanStack Query automatically. ### 2.6 Application Core (`src/pages`, `src/main.tsx`) - `ResourceList.tsx` – reads `resource` param, loads the related `ResourceConfig` from a central map, fetches data, and renders `EnhancedTable` + `FilterBar`. - `ResourceForm.tsx` – builds a dynamic form based on `ResourceField` definitions; uses `displayFormat` for default values on relation fields. - `main.tsx` – wraps the app with `AuthProvider`, `QueryClientProvider`, and MUI `ThemeProvider`. - **Future work**: Extract the “resource loader” into a hook (`useResourceConfig(resourceName)`) that also validates the config at runtime. --- ## 3. Refactor Roadmap – Step‑by‑Step ### Phase 1 – Consolidate Formatting Logic 1. **Create utility** `src/react-openapi/utils/formatDisplay.ts` ```ts export const formatDisplay = (item: any, field: ResourceField, enumValue?: string) => { if (enumValue) return resolveTemplate(enumValue, item); const fmt = field.displayFormat; if (!fmt) return item.name ?? item.title ?? item.label ?? item.id ?? JSON.stringify(item); if (Array.isArray(fmt)) { return fmt.map(k => item[k]).filter(Boolean).join(' '); } return resolveTemplate(fmt, item) || item.id || JSON.stringify(item); }; ``` 2. Replace *all* inline calls to `getFormattedDisplayValue` in `EnhancedTable` and `FilterBar` with `formatDisplay`. 3. Remove `getFormattedDisplayValue` from `EnhancedTable.tsx` (or keep it as a thin wrapper for backward compatibility). 4. Update imports accordingly. 5. Run TypeScript check – no errors. ### Phase 2 – Decouple UI from Config Loading - Introduce **`configLoader.ts`** under `src/react-openapi/utils` that reads a JSON file (or fetches a remote spec) and produces a `Record`. - Replace hard‑coded imports in `src/pages/ResourceList.tsx` with a call to `useResourceConfig(resourceName)`. - Add runtime validation (e.g., using `zod`) to ensure required fields (`displayFormat`, `type`, `label`) are present; surface errors via a toast. ### Phase 3 – Centralize Error & Loading UI - Create `src/components/LoadingSpinner.tsx` and `src/components/ErrorToast.tsx`. - Wrap all data‑fetching hooks (`useResource`, `useAuth` actions) with a HOC that automatically displays these components. - Migrate the scattered `if (loading) …` checks into the new components. ### Phase 4 – Theming & Dark Mode 1. Add a `ThemeContext` that stores `mode: 'light' | 'dark'` and persists the preference. 2. Expose a toggle button (e.g., in the top‑right corner of `App.tsx`). 3. Update component styles to use theme‑aware colors (via `theme.palette`), ensuring the `Chip` variants already respect the palette. ### Phase 5 – Testing & CI - **Unit tests** using `vitest` for: - `formatDisplay` utility (various template & array cases). - `AuthProvider` behavior (login, logout, token refresh). - **Component tests** (`@testing-library/react`) for `EnhancedTable` and `FilterBar` verifying that `displayFormat` rendering matches expectations. - Add a GitHub Actions workflow that runs `npm run lint && npx tsc --noEmit && vitest run` on each PR. ### Phase 6 – Documentation (the files you will publish) - **DESIGN.md** – high‑level architecture (already present). - **IMPLEMENTATION.md** – detailed file‑by‑file breakdown (already present). - **CONCEPT.md** – why the metadata‑driven approach works (already present). - **REFRACTOR_GUIDE.md** – the detailed guide you are reading now (this file). - Keep these files in the repo root; they can be exported to the **lovable** platform directly. --- ## 4. Migration Checklist (what to verify after refactor) - [ ] All UI components compile with TypeScript (`npx tsc --noEmit`). - [ ] No runtime references to `displayField` remain (search `\.displayField`). - [ ] `formatDisplay` correctly resolves: - Template strings with multiple placeholders. - Array of keys. - Fallback to generic fields. - [ ] Auth flow works (login ➜ token stored ➜ API requests succeed, protected routes guarded). - [ ] Pagination works both client‑ and server‑side. - [ ] Mobile layout (card view) still renders correctly. - [ ] Dark‑mode toggle persists across reloads. - [ ] Lint passes (`npm run lint` if configured) and tests pass. --- ## 5. Potential Future Enhancements | Feature | Benefit | Rough Implementation | |---------|---------|----------------------| | **Bulk actions** (delete, export) | Improves admin productivity | Add a toolbar with selection model in `EnhancedTable`. | | **Inline editing** | Faster data tweaks | Replace `onEdit` dialog with cell‑level edit mode using MUI `TextField`. | | **GraphQL fallback** | Flexibility for back‑ends | Abstract data fetching behind an adapter interface (`useDataProvider`). | | **Internationalisation** | Multi‑language UI | Wrap all static strings with `i18n.t()` and provide locale files. | | **Performance profiling** | Identify render bottlenecks | Use React Profiler and memoize expensive formatters (`useMemo`). | --- ### Closing Note The current codebase already demonstrates a powerful pattern: **declare once, render everywhere**. By consolidating the display logic, adding a small utility layer, and strengthening the authentication and theming foundations, the project will become easier to extend, test, and hand‑off to the **lovable** UI platform while retaining its low‑code advantage.