Commit Graph
100 Commits
Author SHA1 Message Date
fahed 553928a3a9 feat(report): form component with all config fields 2026-04-28 14:41:44 +03:00
fahed d925d41a79 feat(report): static preview panel 2026-04-28 14:40:44 +03:00
fahedandClaude Sonnet 4.6 d7d035adb0 feat(report): PDF document component (cover + content pages + charts)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 14:39:45 +03:00
fahed cf6a4c0b3d feat(report): PDF SVG chart components (trend line + horizontal bar) 2026-04-28 14:37:03 +03:00
fahed 2f90753f57 fix(report): allow zero-visitor pilgrim capture rate 2026-04-28 14:34:36 +03:00
fahedandClaude Sonnet 4.6 65025d7f3c feat(report): types, data computation, formatters, executive summary
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 14:33:05 +03:00
fahed ab94d33868 chore: add @react-pdf/renderer 2026-04-28 14:30:42 +03:00
fahedandClaude Sonnet 4.6 64955f0f51 docs: report builder design spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 14:20:07 +03:00
fahedandClaude Sonnet 4.6 c9cfb58896 fix: mobile UX overhaul — collapsible filters, settings nav, responsive layout
Deploy HiHala Dashboard / deploy (push) Successful in 8s
- Add Settings link to desktop nav bar for admin users
- Rewrite Settings page from table layout to responsive card list (fixes unusable mobile state)
- Filter bar (Dashboard + Comparison): collapsible panel on mobile via display:contents trick; stacked full-width dropdowns replace horizontal scroll
- Active filter count badge shown in collapsed filter header
- AltMultiSelect dropdowns go full-width on mobile to prevent viewport overflow
- Chart control separators hidden on mobile to avoid crowding
- Metric grid: 2-col at ≤700px, 1-col at ≤480px
- Comparison period cards: smaller font and tighter padding at ≤680px
- Page shell padding reduced on mobile (48px→20px top, 24px→16px sides)
- Settings page gets correct 80px bottom padding for mobile nav

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 12:22:07 +03:00
fahedandClaude Sonnet 4.6 30cdb5064a refactor: extract shared locale, date helpers, and components (H6)
~300 lines of code that were independently duplicated in Dashboard.tsx
and Comparison.tsx are now in shared modules:

- src/lib/locale.ts — LC interface, EN and AR language configs (merged
  fields from both pages into one unified interface)
- src/lib/dateHelpers.ts — MONTH_KEYS, isLeap, makePresets, guessPreset,
  periodNameL, dateRangeTextL, currentMonth, shiftYear
- src/components/shared/PeriodPicker.tsx — InlinePicker + PeriodHero
- src/components/shared/AltMultiSelect.tsx — AltMultiSelect
- src/components/shared/MetricCard.tsx — MetricCard

Dashboard.tsx and Comparison.tsx now import from these shared modules.
Zero behavioral changes — all props, ARIA, and render output unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 17:53:35 +03:00
fahedandClaude Sonnet 4.6 25cb91e31b refactor: extract inline style blocks to App.css (H1)
The 130-line (Dashboard) and 155-line (Comparison) inline <style> JSX
blocks are removed and replaced with static CSS in App.css.

Font-family values that changed per language are now set as CSS custom
properties (--alt-body-font, --alt-display-font, --alt-mono-font) via
the root element's style prop — 3 vars instead of re-injecting 130+
lines of CSS on every language switch.

The redundant @import font URLs are dropped (fonts already preloaded
in index.html). Default values for the three font vars are defined in
:root so the page renders correctly before JS executes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 17:46:41 +03:00
fahedandClaude Sonnet 4.6 ef9a960e5d fix: responsive, ARIA, performance and CSS cleanup improvements
Addresses remaining medium and low severity audit findings:

- H2: Dark mode @media selector narrowed to :root:not([data-theme]) so
  OS-preference and manual-override blocks are now mutually exclusive
- L2: Remove ~410 lines of dead Slides Builder CSS (no component exists)
- M2: VAT toggle uses flex spacer instead of margin-inline-start:auto,
  preventing layout break when filter bar wraps at medium-small widths
- M3: Page content max-width aligned to 1400px (matches nav bar)
- M5: Period picker toggle now has aria-controls="period-picker-panel"
  pointing to the InlinePicker root in both Dashboard and Comparison
- M6: Offline badge cache timestamp exposed via sr-only span for
  screen reader accessibility (was title-only before)
- M7: chartOpts/barHorizOpts/barNoLegend wrapped in useMemo([baseOpts])
  to prevent unnecessary Chart.js re-renders
- L4: Filter bar scrolls horizontally on mobile instead of wrapping
- L5: Metrics grid uses auto-fit/minmax to eliminate orphaned cards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 17:41:44 +03:00
fahedandClaude Sonnet 4.6 9138ac1098 fix: accessibility, theming, and focus-visibility improvements
Addresses critical and high-severity findings from UI audit:

- C1: Define missing CSS tokens (--hover, --bg-primary/secondary/tertiary)
  fixing broken hover states and Slides Builder backgrounds
- C2: Chart colors now read CSS custom properties at render-time via
  getChartTheme(), adapting tooltip, ticks, and grid to dark mode
- C3: Multi-select ARIA fixed — label elements now carry role="option"
  and aria-selected for valid listbox semantics
- H1/M1: Remove unused --gold and duplicate --primary tokens;
  replace all var(--primary) with var(--accent) throughout App.css
- H3/H4: Focus-visible outlines added to all custom interactive elements
  (chips, controls, year buttons, hero button, multi-select trigger)
- H5: access-badge--full hardcoded colors replaced with design tokens
- H7: aria-pressed added to all chart toggle buttons
- L1: Hardcoded #fff/white replaced with var(--text-inverse)
- M4: index.html now preloads DM Serif Display, Outfit, and IBM Plex
  Sans Arabic — all fonts actually used in the app

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 15:46:54 +03:00
fahedandClaude Sonnet 4.6 d3f9a6cd43 fix: remove duplicate EN/AR language toggle from filter bars
The header already has a language switcher; the one in the filter
bar was redundant on both Dashboard and Comparison pages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 15:42:09 +03:00
fahedandClaude Sonnet 4.6 36df0065ed refactor: rename Demo components to canonical names and purge dead code
Deploy HiHala Dashboard / deploy (push) Successful in 9s
- DashboardDemo → Dashboard, PeriodSelectorDemo → Comparison (these were the real active routes)
- Delete old Dashboard, Comparison, NavDemo, Slides, ChartExport (replaced / unused)
- Delete 8 unused shared components: DateRangePicker, PeriodPicker, FilterControls, MultiSelect, Carousel, ChartCard, EmptyState, StatCard, ToggleSwitch
- Fix date picker stay-open behavior: selections now update draft state only; Apply/Cancel buttons commit or discard
- shared/index.tsx now only exports LoadingSkeleton

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 17:07:39 +03:00
fahedandClaude Sonnet 4.6 c8c3465233 feat: redesigned dashboard UI with editorial aesthetic and RTL support
Deploy HiHala Dashboard / deploy (push) Successful in 9s
- Replace Dashboard/Comparison with DashboardDemo/PeriodSelectorDemo as primary pages at / and /comparison
- New editorial design: DM Serif Display + Outfit fonts, inline period picker, multi-select filters for museum/channel/district
- Full Arabic RTL support with IBM Plex Sans Arabic; EN/AR toggle synced to global LanguageContext
- Bar/pie chart toggle + absolute/percent toggle for museum, channel, district charts
- Refined top nav: transparent inactive links, accent active state, visual separator between nav links and utilities
- DateRangePicker, MultiSelect, FilterControls shared components added
- NavDemo: sidebar layout alternative (accessible at /nav-demo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 17:58:33 +03:00
fahedandClaude Sonnet 4.6 0f6881309c feat: replace year/quarter filters with free date range pickers
Deploy HiHala Dashboard / deploy (push) Successful in 8s
Dashboard: PeriodPicker replaces year + quarter dropdowns. Defaults to
current month. YoY stat card now compares same range vs previous year.

Comparison: two independent PeriodPicker blocks (Period A and Period B).
Changing Period A auto-updates Period B to same period previous year,
but Period B remains freely editable.

Both pages use filterDataByDateRange; Filters type drops year/quarter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 15:02:06 +03:00
fahedandClaude Sonnet 4.6 9064df82be feat: fire-and-forget ETL sync with progress status endpoint
Deploy HiHala Dashboard / deploy (push) Successful in 8s
POST /api/etl/sync now returns immediately (202-style).
GET /api/etl/status shows running state, current month being
processed, and final result or error when done.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 13:40:19 +03:00
fahedandClaude Sonnet 4.6 ac32a541a1 fix: count full visitor per museum for combo tickets
Deploy HiHala Dashboard / deploy (push) Successful in 10s
Bundle tickets grant access to multiple museums, so each museum
should count 1 visitor — not 0.5. Revenue split remains 50/50.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:55:49 +03:00
fahedandClaude Sonnet 4.6 35771595dc fix: correct NocoDB column creation endpoint and add startup delay
Deploy HiHala Dashboard / deploy (push) Successful in 9s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 18:14:56 +03:00
fahedandClaude Sonnet 4.6 e09c3f8190 fix: auto-create AllowedMuseums/AllowedChannels fields in NocoDB on startup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 18:08:34 +03:00
fahedandClaude Sonnet 4.6 e41cff831b feat: per-user museum and channel access control
- PATCH /api/users/:id route to update user permissions
- Auth session stores and returns allowedMuseums/allowedChannels
- User type gains AllowedMuseums/AllowedChannels (JSON string fields)
- parseAllowed() with fail-closed semantics (empty string → null → no data)
- Dashboard/Comparison apply permission base filter before user filters
- Filter dropdowns (museums, channels, years, districts) derived from
  permission-filtered data — restricted users only see their allowed options
- Settings UserRow component with inline checkbox pickers for access config
- Access badges in users table showing current restriction summary

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 18:03:19 +03:00
fahedandClaude Sonnet 4.6 d4ce5b6478 docs: update access control spec — fail-closed on corrupted permissions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 17:38:26 +03:00
fahedandClaude Sonnet 4.6 aa143dfacd docs: add per-user museum & channel access control spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 17:20:54 +03:00
fahedandClaude Sonnet 4.6 f615407bba fix: default district performance chart to pie
Deploy HiHala Dashboard / deploy (push) Successful in 8s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:19:47 +03:00
fahedandClaude Sonnet 4.6 47122b5445 feat: add bar/pie and #/% toggles to district performance chart
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:17:58 +03:00
fahedandClaude Sonnet 4.6 e373363e75 feat: add % toggle to revenue/visitors by event chart
Deploy HiHala Dashboard / deploy (push) Successful in 8s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:16:15 +03:00
fahedandClaude Sonnet 4.6 0a80103cfc feat: add % toggle to channel performance, default events and channel to pie chart
Deploy HiHala Dashboard / deploy (push) Successful in 8s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:14:17 +03:00
fahedandClaude Sonnet 4.6 ebdf90c8ab fix: use correct translation keys for visitors/revenue/bar/pie toggles
Deploy HiHala Dashboard / deploy (push) Successful in 8s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:11:47 +03:00
fahedandClaude Sonnet 4.6 cb4fb6071a feat: merge event charts with metric toggle, add pie chart option to events and channels
Deploy HiHala Dashboard / deploy (push) Successful in 8s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:09:37 +03:00
fahedandClaude Sonnet 4.6 e70d9b92c6 chore: consolidate start scripts — replace start.sh with start-dev.sh content
Deploy HiHala Dashboard / deploy (push) Successful in 8s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 11:55:19 +03:00
fahedandClaude Sonnet 4.6 418eb2c17c ci: remove sudo restart step — restart manually after deploy
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 11:16:24 +03:00
fahedandClaude Sonnet 4.6 b8d33f4f8c feat: deploy Express server via CI/CD with systemd + nginx proxy
Deploy HiHala Dashboard / deploy (push) Failing after 51m18s
- Update deploy.yml to rsync server/, install deps, write .env from
  Gitea secrets, and restart hihala-dashboard.service
- Move tsx to regular dependencies for production use
- Remove unused SESSION_SECRET from config
- Accept PORT env var as fallback for SERVER_PORT

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 17:59:34 +03:00
fahedandClaude Opus 4.6 f3ce7705d6 fix: style select input in settings, fix user name placeholder
Deploy HiHala Dashboard / deploy (push) Successful in 6s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 22:20:39 +03:00
fahedandClaude Opus 4.6 70af4962a6 feat: multi-user auth with role-based access
Deploy HiHala Dashboard / deploy (push) Successful in 6s
- Server checks PIN against env (super admin) + NocoDB Users table
- Session stores name + role (admin/viewer)
- Admin: sees Settings page (seasons + users management)
- Viewer: sees Dashboard + Comparison only, no Settings
- Users CRUD on Settings page: add name + PIN + role, delete
- Settings link + nav hidden for non-admin users

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 22:17:44 +03:00
fahedandClaude Opus 4.6 8cf6f9eedd feat: add PIN-based login with server-side cookie sessions
Deploy HiHala Dashboard / deploy (push) Successful in 6s
- Server: POST /auth/login (verify PIN, set httpOnly cookie)
- Server: GET /auth/check, POST /auth/logout
- Client: Login page shown when not authenticated
- Session persists 7 days via httpOnly cookie
- PIN stored server-side only (ADMIN_PIN env var)
- Dashboard loads data only after successful auth

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 22:02:34 +03:00
fahedandClaude Opus 4.6 c99f2abe10 fix: center settings page to match dashboard layout
Deploy HiHala Dashboard / deploy (push) Successful in 6s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 17:01:55 +03:00
fahedandClaude Opus 4.6 a06436baac fix: change NocoDB proxy from /api to /api/v2 to avoid route collision
Deploy HiHala Dashboard / deploy (push) Successful in 9s
The catch-all /api proxy was swallowing /api/seasons requests before
the specific proxy rule could match. Narrowing to /api/v2 fixes this
since all NocoDB REST calls use /api/v2/ paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:58:41 +03:00
fahedandClaude Opus 4.6 9657a9d221 ci: trigger rebuild with new NocoDB base ID
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:45:24 +03:00
fahedandClaude Opus 4.6 3c19dee236 feat: add season annotation bands to Comparison trend chart
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Seasons that overlap the current comparison period appear as
colored bands on the Revenue Trend chart, same as Dashboard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:23:35 +03:00
fahedandClaude Opus 4.6 b4c436f909 feat: add settings link at bottom of dashboard
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:20:02 +03:00
fahedandClaude Opus 4.6 db6a6ac609 feat: season filter + chart bands on Dashboard and Comparison
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Dashboard:
- Season dropdown filter (filters data by season date range)
- Revenue trend chart shows colored annotation bands for each season
- All downstream memos use season-filtered data

Comparison:
- Season presets in period selector (optgroup)
- Auto-compares with same season from previous hijri year if defined
- Season preset persists start/end dates in URL

Added chartjs-plugin-annotation for chart bands.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:10:49 +03:00
fahedandClaude Opus 4.6 ef48372033 feat: add Settings page with hijri seasons CRUD
- Server: seasons CRUD routes + generic NocoDB helpers
- Client: Settings page at /settings with inline add/edit/delete
- Seasons stored in NocoDB Seasons table
- Vite proxy: /api/seasons routed to Express server
- Nav links added (desktop + mobile)
- Locale keys for EN + AR
- Seasons loaded non-blocking on app mount

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:03:50 +03:00
fahedandClaude Opus 4.6 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
fahedandClaude Opus 4.6 ac5b23326c fix: stable multi-select trigger width (no layout shift on selection)
Deploy HiHala Dashboard / deploy (push) Successful in 6s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:28:58 +03:00
fahedandClaude Opus 4.6 3912b3dd41 polish: fix page title, multi-select styling, chart colors
Deploy HiHala Dashboard / deploy (push) Successful in 6s
- Page title: "HiHala Data - Museums" -> "HiHala Data"
- Meta description: updated to "Event analytics"
- Multi-select dropdown: fix inherited uppercase, wider to fit labels
- Multi-select arrow: smooth CSS rotation instead of swapping characters
- Chart colors: 10-color palette for events/channels (was 3)
- Remove unused ArcElement (Doughnut) from Chart.js registration (-5KB)
- District chart uses dynamic palette instead of hardcoded 2 colors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:16:20 +03:00
fahedandClaude Opus 4.6 9332cae350 feat: always-visible visitors bar chart, replace doughnut
Deploy HiHala Dashboard / deploy (push) Successful in 7s
- Visitors by Event and Revenue by Event are now horizontal bar charts
- Both always visible (no longer hidden when events are filtered)
- Free attractions (Trail To Hira Cave, Makkah Greets Us) now visible
- Removed Doughnut chart and unused import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:55:06 +03:00
fahedandClaude Opus 4.6 aa9813aed4 feat: multi-select filters for events and channels
- New MultiSelect component with checkbox dropdown
- Event and channel filters now accept multiple selections
- Empty array = all selected (no filter applied)
- URL params store selections as comma-separated values
- District and quarter remain single-select

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:53:23 +03:00
fahedandClaude Opus 4.6 fba72692ee feat: rename "Museum" to "Event" across all UI labels
Display labels only — internal code references unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:49:03 +03:00
fahedandClaude Opus 4.6 04789ea9a1 fix: B2C visitor count uses UnitQuantity (1 ticket = 1 visitor)
Deploy HiHala Dashboard / deploy (push) Successful in 8s
B2C generates one PDF ticket per person, so UnitQuantity = visitors.
Other channels (POS, Safiyyah POS, etc.) use PeopleCount for visitors
since group tickets cover multiple people.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:41:51 +03:00
fahedandClaude Opus 4.6 219680fb5e feat: add district filter (Hiraa/AsSaffiyah) from static mapping
- ETL writes District column to NocoDB DailySales
- Museums mapped: Hiraa (Revelation, Holy Quraan, Trail, Makkah, VIP)
  AsSaffiyah (Creation Story, Best of Creation)
- District filter added to Dashboard and Comparison (cascades to museum)
- District Performance chart added (desktop + mobile)
- Locale keys added for both EN and AR

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:08:16 +03:00
fahedandClaude Opus 4.6 4f4559023b feat: combo ticket 50/50 split + Best of Creation museum
- Combo tickets (matching multiple museums) split revenue/visits evenly
- Each museum gets its own row tagged with TicketType=combo, ComboWith
- Added Best of Creation (متحف خير الخلق) to museum mapping
- Holy Quraan Museum now shows 3.3M total (was 971K without combo share)
- ComboMuseums column tracks split factor for auditing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:53:25 +03:00
fahedandClaude Opus 4.6 1f1e0756d0 feat: add server-side ETL pipeline, revert client to NocoDB reads
ETL Pipeline (server):
- POST /api/etl/sync?mode=full|incremental — fetches ERP, aggregates, writes NocoDB
- nocodbClient.ts: table discovery, paginated delete/insert
- etlSync.ts: orchestrates fetch → aggregate → upsert
- museumMapping.ts moved from client to server
- Auth via ETL_SECRET bearer token

Client:
- dataService.ts reverts to reading NocoDB DailySales table
- Paginated fetch via fetchNocoDBTable (handles >1000 rows)
- Suspicious data check: prefers cache if NocoDB returns <10 rows
- Deleted erpService.ts and client-side museumMapping.ts

First full sync: 391K transactions → 5,760 daily records in 108s.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:25:50 +03:00
fahedandClaude Opus 4.6 9c0ffa5721 docs: add ETL pipeline design spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:26:23 +03:00
fahedandClaude Opus 4.6 b4f4104e3e chore: remove Slides page and Salla console output
- Remove Slides route, import, and mobile nav link from App.tsx
- Remove Salla route mounting and console output from server

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:16:40 +03:00
fahedandClaude Opus 4.6 18821fd560 fix: fetch ERP months sequentially to avoid 500 errors
The ERP API can't handle concurrent requests — switch from batched
parallel (4 at a time) to sequential fetching.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:59:21 +03:00
fahedandClaude Opus 4.6 ea71e54058 fix: change server port to 3002 to avoid conflict with rawaj-v2
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:49:59 +03:00
fahedandClaude Opus 4.6 4ed4d83257 feat: add unified dev script that launches server + client
npm run dev now starts both the ERP proxy server and Vite in parallel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:46:31 +03:00
fahedandClaude Opus 4.6 f6b7d4ba8d feat: migrate museum sales from NocoDB to Hono ERP API
- Replace NocoDB museum data (Districts/Museums/DailyStats) with ERP API
- Client fetches via server proxy (/api/erp/sales) — no credentials in browser
- Aggregate transaction-level ERP data into daily/museum/channel records
- Replace "district" dimension with "channel" (B2C/HiHala, POS, B2B, etc.)
- Add product-to-museum mapping (46 products → 6 museums)
- NocoDB retained only for PilgrimStats
- Remove old server/index.js (replaced by modular TS in server/src/)
- Update all components, types, and locale files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:43:34 +03:00
fahedandClaude Opus 4.6 a84caaa31e feat: add product-to-museum and channel mapping config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:03:10 +03:00
fahedandClaude Opus 4.6 8bdfc85027 refactor: extract fetch helpers to shared util
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:02:43 +03:00
fahedandClaude Opus 4.6 e84d961536 feat: convert server to TypeScript + add ERP API proxy
- Migrate server/index.js → modular TS structure (config, routes, services)
- Add ERP proxy: GET /api/erp/sales proxies Hono ERP API with server-side auth
- JWT token cached server-side, auto-refreshes on 401
- ERP credentials stay server-side only (no VITE_ prefix)
- Vite dev proxy routes /api/erp → localhost:3001
- Preserve existing Salla OAuth integration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:58:35 +03:00
fahedandClaude Opus 4.6 9c1552e439 chore: add ERP API migration plan (pre-migration snapshot)
Preserves current NocoDB-based state before switching museum
sales data source to the Hono ERP API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:43:20 +03:00
fahedandClaude Opus 4.6 802ff28754 Update default theme to light and fix data source subtitle
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Default to light theme instead of system preference, and update
dashboard subtitle to reflect VivaTicket as the data source.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:03:17 +03:00
fahedandClaude Opus 4.6 7d919979cc Delight: Add micro-interactions and entrance animations
Deploy HiHala Dashboard / deploy (push) Successful in 6s
- Stat cards lift on hover (translateY -2px + shadow elevation)
- Metric cards lift on hover
- Chart cards fade-up with staggered delays on mount
- All animations respect prefers-reduced-motion (already in place)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:30:21 +03:00
fahedandClaude Opus 4.6 784a914ebf Colorize: Add dark mode with system/dark/light toggle
- Add prefers-color-scheme: dark media query for automatic dark mode
- Add data-theme attribute for manual override (persisted to localStorage)
- 3-state cycle: system → dark → light → system
- Theme toggle button in nav with contextual icon (sun/moon/half)
- Dark palette: slate-900 bg, slate-800 surfaces, adjusted text/accent/success/danger

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:29:39 +03:00
fahedandClaude Opus 4.6 0df13abfee Polish + Optimize: Clean metadata, remove !important, prune unused CSS
- Update theme-color to match brand (#f8fafc), fix stale CRA description
- Remove manifest.json and logo192.png references (not used)
- Replace !important on chart export buttons with higher specificity selectors
- Remove unused .skeleton-text and .skeleton-loading CSS classes
- Remove duplicate skeleton animation keyframes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:28:34 +03:00
fahedandClaude Opus 4.6 cf169b6b69 Normalize + Adapt: CSS tokens, RTL fixes, mobile nav, fluid charts
Normalize:
- Add 10+ new CSS variables (brand-icon, brand-text, text-inverse, warning-*, etc.)
- Replace 35+ hardcoded hex colors with CSS variable references

Adapt:
- Add Slides link to mobile bottom nav (was unreachable on mobile)
- Fix RTL table alignment: text-align left → start
- Make chart height fluid: 380px → clamp(280px, 30vw, 420px)
- Fix carousel dot touch targets to minimum 24px
- Fix margin-left → margin-inline-start for RTL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:27:27 +03:00
fahedandClaude Opus 4.6 25066af67c Harden: Fix critical accessibility issues
- Add aria-labels to icon-only buttons (refresh, language toggle)
- Add aria-hidden to decorative SVGs
- Add aria-label to data source select
- Replace outline:none with visible focus rings on all inputs/selects
- Add <main> landmark for screen reader navigation
- Add prefers-reduced-motion: disable all animations for vestibular safety
- Move error message inline style to CSS class
- Add aria-label to both nav landmarks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:23:04 +03:00
fahedandClaude Opus 4.6 c8567da75f Enable TypeScript strict mode and fix all type errors
Deploy HiHala Dashboard / deploy (push) Successful in 6s
- Enable strict: true in tsconfig.json (was false)
- Add proper interfaces for all component props (Dashboard, Comparison, Slides)
- Add SlideConfig, ChartTypeOption, MetricOption types
- Type all function parameters, callbacks, and state variables
- Fix dynamic property access with proper keyof assertions
- 233 type errors resolved across 5 files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:17:09 +03:00
fahedandClaude Opus 4.6 30ea4b6ecb Add route-based code splitting and loading skeletons
- Lazy-load Dashboard, Comparison, Slides via React.lazy + Suspense
- Main bundle reduced from 606KB to 256KB
- Replace full-screen spinner with skeleton cards during load
- Skeleton used for both initial data fetch and route transitions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:10:42 +03:00
fahedandClaude Opus 4.6 cd1e395ffa Remove unused useUrlState hook and sallaService
Both were implemented but never imported by any component.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:09:18 +03:00
fahedandClaude Opus 4.6 8934ba1e51 Add fetch timeout/retry, friendly error messages, and VAT rate constant
- fetchWithTimeout (10s) + fetchWithRetry (3 attempts, exponential backoff)
- DataError class with type classification (config/network/auth/timeout/unknown)
- User-friendly error messages in EN/AR instead of raw error strings
- Extract VAT_RATE constant (was hardcoded 1.15)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 18:08:24 +03:00
fahedandClaude Opus 4.6 ed29e7c22c Remove CI/CD debug output
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:58:02 +03:00
fahedandClaude Opus 4.6 39b36bf6d9 Add debug output to CI/CD to verify secrets are injected
Deploy HiHala Dashboard / deploy (push) Successful in 6s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:55:23 +03:00
fahedandClaude Opus 4.6 bf996749e5 Discover NocoDB table IDs dynamically instead of hardcoding them
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Table IDs are now fetched at runtime via the NocoDB meta API using
VITE_NOCODB_BASE_ID, so the same code works against any NocoDB instance
(local or Cloudron). Also adds a migration script for moving data between
instances with correct FK remapping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:50:44 +03:00
fahedandClaude Opus 4.6 db2617f37d Support both link columns and plain foreign key columns
Deploy HiHala Dashboard / deploy (push) Successful in 6s
Production NocoDB uses DistrictId/MuseumId columns instead of
nc_epk____ link columns. Code now checks both column names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:03:07 +03:00
fahed a720b4a0aa Retrigger build with updated NocoDB token
Deploy HiHala Dashboard / deploy (push) Successful in 7s
2026-03-09 17:47:31 +03:00
fahed d98fd2cd36 Retrigger CI/CD build
Deploy HiHala Dashboard / deploy (push) Successful in 7s
2026-03-09 17:41:16 +03:00
fahedandClaude Opus 4.6 7c1a8fa31a Add NocoDB env vars to CI/CD build step
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Vite inlines env vars at build time, so they must be available
during the build step via Gitea secrets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:39:43 +03:00
fahedandClaude Opus 4.6 6cf0bf626b Simplify CI/CD to deploy static frontend only
Deploy HiHala Dashboard / deploy (push) Successful in 6s
Remove server deployment, dependency install, and systemd restart.
The app connects directly to NocoDB from the browser.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:36:46 +03:00
fahedandClaude Opus 4.6 b7ad978e29 Migrate from Create React App to Vite
Deploy HiHala Dashboard / deploy (push) Successful in 7s
CRA (react-scripts 5.0.1) is abandoned and incompatible with TypeScript 5.x.
Vite provides faster builds, active maintenance, and native TS5 support.

- Replace react-scripts with vite + @vitejs/plugin-react
- Move index.html to root with script module entry point
- Replace setupProxy.js with vite.config.ts proxy config
- Rename env vars from REACT_APP_ to VITE_ prefix
- Update tsconfig for bundler module resolution
- Add nginx setup script for deployment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:24:11 +03:00
fahed 42cb524cd8 Final NocoDB config update - DailyStats table recreated with correct structure
Deploy HiHala Dashboard / deploy (push) Failing after 4s
2026-03-09 16:43:07 +03:00
fahed a1394d4901 Update NocoDB config for Cloudron - fix DailyStats table ID 2026-03-09 16:29:20 +03:00
fahed 3068463995 Update NocoDB config for Cloudron deployment 2026-03-09 16:04:24 +03:00
fahed 97a208734e updates 2026-02-18 14:13:45 +03:00
fahed 0caef0b89a removed /server/node_modules 2026-02-16 11:00:54 +03:00
fahed 9bb4ecb0dd last changes 2026-02-16 10:59:55 +03:00
fahedandClaude Opus 4.6 e92f11241d feat: add linear regression trendline to revenue charts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 10:56:49 +03:00
fahedandClaude Opus 4.6 a71a741f76 feat: add start script to launch NocoDB and React together
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 10:30:15 +03:00
fahed d1c500a677 Complete TypeScript migration
- Convert all shared components to TypeScript (.jsx → .tsx)
  - Carousel, ChartCard, EmptyState, FilterControls, StatCard, ToggleSwitch
- Add proper TypeScript interfaces for all component props
- Delete unused dataService.legacy.ts (archived Google Sheets code)
- Build passes successfully
2026-02-04 13:59:56 +03:00
fahed 868f46fc6e chore: migrate to TypeScript
- Convert all .js files to .tsx/.ts
- Add types for data structures (MuseumRecord, Metrics, etc.)
- Add type declarations for react-chartjs-2
- Configure tsconfig with relaxed strictness for gradual adoption
- All components now use TypeScript
2026-02-04 13:45:50 +03:00
fahed e98bebd60b fix: match refresh button size to other nav buttons 2026-02-04 11:53:18 +03:00
fahed 7e72d6c02d fix: properly detect offline mode when using cached data 2026-02-04 11:49:25 +03:00
fahed 9044ab7da3 feat: VAT toggle + offline mode
- Rename Revenue to GrossRevenue, add NetRevenue (excl. VAT)
- Add VAT toggle (Incl/Excl) on Dashboard and Comparison pages
- Add offline mode with localStorage caching (24h validity)
- Add refresh button and offline indicator in nav
- Remove Google Sheets fallback (archived to dataService.legacy.js)
- Add AR/EN translations for new UI elements
2026-02-04 11:47:42 +03:00
fahed afe276541f Fix chart data labels RTL alignment issue
- Force LTR direction on chart canvas elements via CSS
- Add locale: 'en-US' to chart options for consistent number formatting
- Add textDirection: 'ltr' to datalabels and tooltip configs
- Fixes background/text misalignment in Arabic RTL mode
2026-02-03 16:40:30 +03:00
fahed 0c7987493e Improve language toggle button design
- Add globe icon to language toggle
- Style with border, proper padding, and hover effects
- Match overall nav design language
- Use Inter font for Arabic mode to show 'EN' consistently
2026-02-03 16:32:31 +03:00
fahed fa43cf8dd1 Fix chart height - override flex with explicit 380px
- Add .exportable-chart.chart-container rule with flex:none and height:380px
- This overrides the flex:1 that was preventing height from being applied
- Also fixed .chart-section .chart-container to 380px
2026-02-03 16:21:22 +03:00
fahed 1d7389cd43 Improve chart UX: taller charts, controls below header
- Increase chart height from 280px to 380px (more square-like)
- Move controls below chart title (column layout)
- Spread two control groups left/right with space-between
- Make controls more compact (smaller padding, font-size)
2026-02-03 15:53:14 +03:00
fahed 60eda25fe3 Position download button in corner + better Arabic font
- Move export button outside header-actions to enable absolute positioning
- Button now positioned at top-right (LTR) / top-left (RTL)
- Switch from Tajawal to IBM Plex Sans Arabic (slicker, more technical)
- Add RTL-specific font-family in CSS
2026-02-03 15:49:31 +03:00