Files
khata-ui/REFRACTOR_GUIDE.md

9.9 KiB
Raw Permalink Blame History

Refactor Guide Deep Dive into the KhataUI Codebase

This document walks through the entire repository, explains the current architecture, and provides a stepbystep refactor plan that will improve maintainability, type safety, and UI/UX while preserving the existing functional behavior.


1. Repository Layout (highlevel)

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.
OpenAPIdriven 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 Walkthrough

2.1 react-openapi/types/config.ts

export interface ResourceField {
    displayFormat: string;          // <- single source of truth for rendering
    type: FieldType;
    label: string;
    required?: boolean;
    options?: string[];
    readOnly?: boolean;
    schema?: Record<string, ResourceField>;
    formatter?: (value: any) => string;
    relation?: string;
    filterType?: "autocomplete" | "multiselect" | "number-range" | "date-range";
    enumOption?: EnumOption;
    enumLabels?: Record<string, string>;
}
  • 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 MUIcompatible 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 serverside or clientside 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 StepbyStep

Phase1 Consolidate Formatting Logic

  1. Create utility src/react-openapi/utils/formatDisplay.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.

Phase2 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<string, ResourceConfig>.
  • Replace hardcoded 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.

Phase3 Centralize Error & Loading UI

  • Create src/components/LoadingSpinner.tsx and src/components/ErrorToast.tsx.
  • Wrap all datafetching hooks (useResource, useAuth actions) with a HOC that automatically displays these components.
  • Migrate the scattered if (loading) … checks into the new components.

Phase4 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 topright corner of App.tsx).
  3. Update component styles to use themeaware colors (via theme.palette), ensuring the Chip variants already respect the palette.

Phase5 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.

Phase6 Documentation (the files you will publish)

  • DESIGN.md highlevel architecture (already present).
  • IMPLEMENTATION.md detailed filebyfile breakdown (already present).
  • CONCEPT.md why the metadatadriven 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 serverside.
  • Mobile layout (card view) still renders correctly.
  • Darkmode 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 celllevel edit mode using MUI TextField.
GraphQL fallback Flexibility for backends Abstract data fetching behind an adapter interface (useDataProvider).
Internationalisation Multilanguage 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 handoff to the lovable UI platform while retaining its lowcode advantage.