# Hijri Seasons Feature ## Goal Add configurable hijri seasons (Ramadan, Hajj, etc.) to the dashboard as a presentation overlay. Seasons are user-defined with Gregorian date ranges (since hijri months shift ~11 days each year). They appear as filter presets, chart bands, and are managed through a settings page. ## Data Storage New NocoDB `Seasons` table: | Column | Type | Example | |--------|------|---------| | Name | string | `Ramadan` | | HijriYear | number | `1446` | | StartDate | string | `2025-02-28` | | EndDate | string | `2025-03-30` | | Color | string | `#10b981` | Read on dashboard load alongside PilgrimStats. Written via server proxy to keep NocoDB credentials server-side. **Loading lifecycle:** Seasons load independently of the main data fetch. A failure to load seasons degrades gracefully — seasons state defaults to `[]`, the dashboard renders normally without bands or season presets. Seasons are non-blocking and non-critical. ## Server Changes ### New files | File | Responsibility | |------|----------------| | `server/src/routes/seasons.ts` | `GET /api/seasons` (read all), `POST /api/seasons` (create), `PUT /api/seasons/:id` (update), `DELETE /api/seasons/:id` (delete) | ### Modified files | File | Change | |------|--------| | `server/src/index.ts` | Mount seasons routes at `/api/seasons` | | `server/src/services/nocodbClient.ts` | Add generic CRUD helpers typed as `>` so both ETL and seasons routes can share them without coupling | | `vite.config.ts` | Add `/api/seasons` proxy rule **before** the catch-all `/api` rule (same pattern as `/api/erp`). Order: `/api/erp` → `/api/etl` → `/api/seasons` → `/api` | ## Client Changes ### New files | File | Responsibility | |------|----------------| | `src/components/Settings.tsx` | Settings page with seasons CRUD table | | `src/services/seasonsService.ts` | Fetch/create/update/delete seasons via server proxy | ### Modified files | File | Change | |------|--------| | `src/types/index.ts` | Add `Season` interface | | `src/App.tsx` | Add `/settings` route, nav link (both desktop and mobile bottom nav), load seasons on mount (non-blocking) | | `src/components/Dashboard.tsx` | Add season filter dropdown, chart annotation bands | | `src/components/Comparison.tsx` | Add season filter as period preset | | `src/config/chartConfig.ts` | Import and register `chartjs-plugin-annotation` in the central `ChartJS.register()` call | | `src/locales/en.json` | Settings page labels, season filter labels | | `src/locales/ar.json` | Arabic translations | | `package.json` | Add `chartjs-plugin-annotation` dependency | ## Season Interface ```typescript export interface Season { Id?: number; Name: string; HijriYear: number; StartDate: string; EndDate: string; Color: string; } ``` ## Settings Page (`/settings`) New route accessible from the nav bar (gear icon on desktop, gear in mobile bottom nav). Contains: - **Seasons table**: lists all defined seasons with columns: Name, Hijri Year, Start Date, End Date, Color, Actions (edit/delete) - **Add season form**: inline row at the bottom of the table with inputs for each field + color picker + save button - **Edit**: click a row to edit inline - **Delete**: delete button per row with confirmation - **No empty state needed**: just show the empty table with the add form ## Period Filter Integration ### Dashboard Add a "Season" select in the filters section (after Quarter). Options populated from the loaded seasons list: - `All Seasons` (default — no date filtering from season) - `Ramadan 1446 (Feb 28 – Mar 30, 2025)` - `Hajj 1446 (Jun 4 – Jun 9, 2025)` - etc. Selecting a season sets a date range filter on the data — equivalent to filtering by start/end date. This works alongside existing year/district/channel/event filters. Implementation: when a season is selected, filter data to `row.date >= season.StartDate && row.date <= season.EndDate`. Store the selected season ID in state (not URL params — seasons are dynamic). ### Comparison Seasons appear as preset period options alongside months/quarters. Selecting "Ramadan 1446" sets the period dates and auto-compares with the same season name in the previous hijri year if defined (e.g. "Ramadan 1445"). ## Chart Bands (Revenue Trend) Uses `chartjs-plugin-annotation` to draw semi-transparent vertical bands on the revenue trend chart. Must be registered in `chartConfig.ts` via `ChartJS.register(Annotation)`. For each season whose date range overlaps the chart's visible range: - Draw a vertical box from `season.StartDate` to `season.EndDate` - Fill with `season.Color` at 15% opacity - Label at the top with season name + hijri year Only the revenue trend chart gets bands (it's the only time-series chart where seasons make visual sense). ## What's NOT Changing - ETL pipeline unchanged — seasons are a UI/presentation concern - NocoDB DailySales schema unchanged - All existing filters (year, district, channel, event, quarter) unchanged - Seasons don't affect data aggregation or storage