Files
hihala-dashboard/docs/superpowers/specs/2026-03-31-hijri-seasons-design.md
fahed 1dd216f933 docs: add hijri seasons feature design spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:54:52 +03:00

5.0 KiB
Raw Blame History

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 <T extends Record<string, unknown>> 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

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