feat(reports): admin Reports dashboard — ledger-first charts
Adds an admin Reports screen (/setup/reports, gated report:read) — an on-demand dashboard over the signed event log. Server (ledger-first): GET /api/reports/summary?from&to&bucket aggregates in one call — entry/exit counts + all money summed straight from ledger_events (same source the shift Z-report reconciles, so totals tie out to the drawer); revenue split into ticket / subscription-sale / out-of-window mirrors the Z-report. Duration stats come from the sessions cache (flagged). All bucketing is in the SITE timezone (siteTz). A .csv export of the per-bucket series. reports.ts + routes/reports.ts. Web: Reports.tsx — date-range presets (today/7d/30d/90d), hour/day/month grain, KPI cards, entry/exit line, revenue bar + cash/card split, revenue-mix pie, peak-hours histogram, numeric breakdown, subscription stats. Charts via Recharts (MIT), lazy-loaded into its own chunk (~111KB gz) so the booth bundle is untouched. New Setup tab + nav + i18n (sq + en parity). asc() exported from @parking/db; formatMinutes helper. Tests: reports.test.ts (10) pin the sums, tz bucketing, money split, duration stats, subscription counts. server 90/90; build+lint 14/14. Wiki: reporting-analytics.md "Built v1" section + log entry. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -57,6 +57,7 @@ export const sq = {
|
||||
users: "Përdoruesit",
|
||||
roles: "Rolet",
|
||||
shifts: "Turnet",
|
||||
reports: "Raportet",
|
||||
logs: "Loget",
|
||||
},
|
||||
status: {
|
||||
@@ -691,6 +692,40 @@ export const sq = {
|
||||
cashRemoved: "Para të hequra",
|
||||
loadFailed: "Ngarkimi i turneve dështoi.",
|
||||
},
|
||||
reports: {
|
||||
title: "Raportet",
|
||||
groupBy: "Grupo sipas",
|
||||
exportCsv: "Eksporto CSV",
|
||||
loadFailed: "Raporti nuk u ngarkua dot: {{error}}",
|
||||
noData: "Nuk ka të dhëna në këtë interval.",
|
||||
footnote: "Numërimet dhe paratë mblidhen nga regjistri i nënshkruar. Oraret në {{tz}}.",
|
||||
preset: { today: "Sot", "7d": "7 ditë", "30d": "30 ditë", "90d": "90 ditë" },
|
||||
bucket: { hour: "Orë", day: "Ditë", month: "Muaj" },
|
||||
kpi: {
|
||||
entries: "Hyrje",
|
||||
exits: "Dalje",
|
||||
revenue: "Të ardhura",
|
||||
payments: "Pagesa",
|
||||
avgStay: "Qëndrim mes.",
|
||||
subscribers: "Abonentë",
|
||||
},
|
||||
chart: {
|
||||
flow: "Hyrjet & daljet me kalimin e kohës",
|
||||
revenue: "Të ardhurat ({{currency}})",
|
||||
mix: "Përbërja e të ardhurave",
|
||||
peakHours: "Hyrjet sipas orës së ditës",
|
||||
breakdown: "Ndarja",
|
||||
},
|
||||
mix: { ticket: "Tranzit", subSales: "Abonime", subWindow: "Jashtë orarit" },
|
||||
row: {
|
||||
cash: "Para në dorë",
|
||||
card: "Kartë",
|
||||
closed: "Sesione të mbyllura",
|
||||
medianStay: "Qëndrim mesatar (median)",
|
||||
subActive: "Abonime aktive",
|
||||
subCars: "Makina të mbuluara",
|
||||
},
|
||||
},
|
||||
logs: {
|
||||
title: "Loget e sistemit",
|
||||
refresh: "Rifresko",
|
||||
|
||||
Reference in New Issue
Block a user