-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathReportOutputLayout.tsx
More file actions
118 lines (112 loc) · 3.89 KB
/
Copy pathReportOutputLayout.tsx
File metadata and controls
118 lines (112 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { IconCalendar, IconChevronLeft, IconClock } from '@tabler/icons-react';
import { ReportActionButtons } from '@/components/report/ReportActionButtons';
import { SharedReportTag } from '@/components/report/SharedReportTag';
import { Container, Group, Stack, Text, Title } from '@/components/ui';
import { useAppNavigate } from '@/contexts/NavigationContext';
import { colors, spacing, typography } from '@/designTokens';
import { useCurrentCountry } from '@/hooks/useCurrentCountry';
import { getReportTimingDisplay } from '@/utils/reportTiming';
interface ReportOutputLayoutProps {
reportId: string;
reportLabel?: string;
reportYear?: string;
timestamp?: string;
isSharedView?: boolean;
onShare?: () => void;
onSave?: () => void;
onView?: () => void;
onReproduce?: () => void;
children: React.ReactNode;
}
/**
* ReportOutputLayout - Structural chrome for report output pages
*
* Provides consistent layout with:
* - Breadcrumb navigation
* - Header with title and actions
* - Content area (children)
*
* This is a pure presentational component with no data fetching or business logic.
*/
export default function ReportOutputLayout({
reportId,
reportLabel,
reportYear,
timestamp = 'Ran today at 05:23:41',
isSharedView = false,
onShare,
onSave,
onView,
onReproduce,
children,
}: ReportOutputLayoutProps) {
const countryId = useCurrentCountry();
const nav = useAppNavigate();
const timingDisplay = reportYear ? getReportTimingDisplay(reportYear) : null;
return (
<Container size="xl" className="tw:px-xl">
<Stack className="tw:gap-xl">
{/* Back breadcrumb */}
<Group
className="tw:gap-xs tw:items-center tw:cursor-pointer"
style={{ marginBottom: `-${spacing.md}` }}
onClick={() => nav.push(`/${countryId}/reports`)}
>
<IconChevronLeft size={14} color={colors.text.secondary} />
<Text className="tw:text-sm" style={{ color: colors.text.secondary }}>
Back to reports
</Text>
</Group>
{/* Header Section */}
<div>
{/* Title row with actions */}
<Group className="tw:gap-xs tw:items-center tw:mb-xs tw:justify-between tw:flex-nowrap">
<Group className="tw:gap-xs tw:items-center tw:flex-nowrap" style={{ minWidth: 0 }}>
<Title
order={1}
style={{
fontWeight: typography.fontWeight.semibold,
fontSize: typography.fontSize['3xl'],
color: colors.primary[700],
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
>
{reportLabel || reportId}
</Title>
{isSharedView && <SharedReportTag />}
</Group>
<ReportActionButtons
isSharedView={isSharedView}
onShare={onShare}
onSave={onSave}
onView={onView}
onReproduce={onReproduce}
/>
</Group>
{/* Timestamp and year */}
<Group className="tw:gap-xs tw:items-center">
{timingDisplay && (
<>
<IconCalendar size={16} color={colors.text.secondary} />
<Text className="tw:text-sm" style={{ color: colors.text.secondary }}>
{timingDisplay.label}: {timingDisplay.value}
</Text>
<Text className="tw:text-sm" style={{ color: colors.text.secondary }}>
•
</Text>
</>
)}
<IconClock size={16} color={colors.text.secondary} />
<Text className="tw:text-sm" style={{ color: colors.text.secondary }}>
{timestamp}
</Text>
</Group>
</div>
{/* Content */}
{children}
</Stack>
</Container>
);
}