feat(report): visitors by museum, avg ticket price, chart label fix, VAT indicator
Deploy HiHala Dashboard / deploy (push) Successful in 10s

This commit is contained in:
fahed
2026-04-28 14:59:24 +03:00
parent 594321738a
commit 648365348f
3 changed files with 39 additions and 11 deletions
+28 -5
View File
@@ -88,7 +88,7 @@ interface Props { data: ReportData; }
export function ReportDocument({ data }: Props) {
const { config: cfg, metrics, prevMetrics, trendLabels, trendCurrent, trendPrevious,
museumBreakdown, channelBreakdown, pilgrimCapture, generatedAt } = data;
museumBreakdown, museumVisitorBreakdown, channelBreakdown, pilgrimCapture, generatedAt } = data;
const lang = cfg.language;
const color = cfg.accentColor;
@@ -96,6 +96,9 @@ export function ReportDocument({ data }: Props) {
const orientation = cfg.orientation === 'landscape' ? 'landscape' : 'portrait';
const T = lang === 'en' ? LABELS_EN : LABELS_AR;
const avgTicketPrice = metrics.tickets > 0 ? metrics.revenue / metrics.tickets : 0;
const prevAvgTicketPrice = prevMetrics && prevMetrics.tickets > 0 ? prevMetrics.revenue / prevMetrics.tickets : null;
const metricsRows = [
{ label: T.revenue, curr: formatCurrency(metrics.revenue, cfg.includeVAT),
prev: prevMetrics ? formatCurrency(prevMetrics.revenue, cfg.includeVAT) : null,
@@ -109,6 +112,9 @@ export function ReportDocument({ data }: Props) {
{ label: T.avgRev, curr: formatCurrency(metrics.avgRevPerVisitor, false),
prev: prevMetrics ? formatCurrency(prevMetrics.avgRevPerVisitor, false) : null,
chg: prevMetrics ? pctChange(metrics.avgRevPerVisitor, prevMetrics.avgRevPerVisitor) : null },
{ label: T.avgTicketPrice, curr: formatCurrency(avgTicketPrice, false),
prev: prevAvgTicketPrice !== null ? formatCurrency(prevAvgTicketPrice, false) : null,
chg: prevAvgTicketPrice !== null ? pctChange(avgTicketPrice, prevAvgTicketPrice) : null },
...(cfg.showPilgrimCapture && pilgrimCapture ? [{
label: T.capture, curr: `${pilgrimCapture.current}%`,
prev: pilgrimCapture.previous !== null ? `${pilgrimCapture.previous}%` : null,
@@ -152,7 +158,7 @@ export function ReportDocument({ data }: Props) {
{cfg.showMetricsTable && (
<View style={S.sectionGap}>
<SectionHeading title={T.keyMetrics} color={color} />
<SectionHeading title={`${T.keyMetrics}${cfg.includeVAT ? T.inclVAT : T.exclVAT}`} color={color} />
<View style={S.metricsTable}>
<View style={S.metricsHeaderRow}>
<Text style={S.metricsHeaderLabel}> </Text>
@@ -207,13 +213,22 @@ export function ReportDocument({ data }: Props) {
{cfg.showMuseumBreakdown && museumBreakdown.length > 0 && (
<View style={S.sectionGap}>
<SectionHeading title={T.byMuseum} color={color} />
<SectionHeading title={T.byMuseumRevenue} color={color} />
<View style={S.chartWrap}>
<PdfHBarChart items={museumBreakdown} color={color} width={460} />
</View>
</View>
)}
{cfg.showMuseumBreakdown && museumVisitorBreakdown.length > 0 && (
<View style={S.sectionGap}>
<SectionHeading title={T.byMuseumVisitors} color={color} />
<View style={S.chartWrap}>
<PdfHBarChart items={museumVisitorBreakdown} color={color} width={460} />
</View>
</View>
)}
{cfg.showChannelBreakdown && channelBreakdown.length > 0 && (
<View style={S.sectionGap}>
<SectionHeading title={T.byChannel} color={color} />
@@ -238,14 +253,18 @@ const LABELS_EN = {
generated: 'Generated',
execSummary: 'Executive Summary',
keyMetrics: 'Key Metrics',
inclVAT: 'Incl. VAT',
exclVAT: 'Excl. VAT',
change: 'vs Prior Year',
trend: 'Revenue Trend',
byMuseum: 'Revenue by Museum',
byMuseumRevenue: 'Revenue by Museum',
byMuseumVisitors: 'Visitors by Museum',
byChannel: 'Visitors by Channel',
revenue: 'Revenue',
visitors: 'Visitors',
tickets: 'Tickets',
avgRev: 'Avg Rev / Visitor',
avgTicketPrice: 'Avg Ticket Price',
capture: 'Pilgrim Capture Rate',
};
@@ -256,13 +275,17 @@ const LABELS_AR = {
generated: 'تاريخ الإصدار',
execSummary: 'الملخص التنفيذي',
keyMetrics: 'المؤشرات الرئيسية',
inclVAT: 'شامل ضريبة القيمة المضافة',
exclVAT: 'غير شامل ضريبة القيمة المضافة',
change: 'مقابل العام السابق',
trend: 'اتجاه الإيرادات',
byMuseum: 'الإيرادات حسب المتحف',
byMuseumRevenue: 'الإيرادات حسب المتحف',
byMuseumVisitors: 'الزوار حسب المتحف',
byChannel: 'الزوار حسب القناة',
revenue: 'الإيرادات',
visitors: 'الزوار',
tickets: 'التذاكر',
avgRev: 'متوسط الإيراد / زائر',
avgTicketPrice: 'متوسط سعر التذكرة',
capture: 'معدل استيعاب الحجاج',
};