fix: date rendering now shows only date for date fields

This commit is contained in:
2026-06-10 00:29:19 +05:30
parent a227c14e0a
commit 386297dc1e
5 changed files with 282 additions and 1 deletions

172
REFRACTOR_GUIDE.md Normal file
View File

@@ -0,0 +1,172 @@
# 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`
```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`
```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.