Skip to content

Commit a698821

Browse files
authored
Merge pull request #6019 from bcgov/feat/5795
Feat/5795
2 parents b7f8910 + 8ce3db1 commit a698821

File tree

17 files changed

+300
-305
lines changed

17 files changed

+300
-305
lines changed

app/app/api/private-cloud/products/[licencePlate]/costs/monthly/[year-month]/download/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ export const POST = createApiHandler({
3333

3434
const [year, month] = yearMonth.split('-').map(Number);
3535
const monthlyData = await getMonthlyCosts(licencePlate, year, month);
36+
const selectedDate = monthlyData.startDate;
3637

37-
const pdfBuffer = await generateMonthlyCostPdf({ product, data: monthlyData });
38+
const pdfBuffer = await generateMonthlyCostPdf({ product, data: monthlyData, selectedDate });
3839
return PdfResponse(pdfBuffer, `monthly-costs-${yearMonth}.pdf`);
3940
});

app/app/api/private-cloud/products/[licencePlate]/costs/quarterly/[year-quarter]/download/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ export const POST = createApiHandler({
3333

3434
const [year, quarter] = yearQuarter.split('-').map(Number);
3535
const result = await getQuarterlyCosts(licencePlate, year, quarter);
36+
const selectedDate = result.startDate;
3637

37-
const pdfBuffer = await generateQuarterlyCostPdf({ product, data: result });
38+
const pdfBuffer = await generateQuarterlyCostPdf({ product, data: result, selectedDate });
3839
return PdfResponse(pdfBuffer, `quarterly-costs-${year}-Q${quarter}.pdf`);
3940
});

app/app/api/private-cloud/products/[licencePlate]/costs/yearly/[year]/download/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const POST = createApiHandler({
3232
}
3333

3434
const result = await getYearlyCosts(licencePlate, year);
35-
36-
const pdfBuffer = await generateYearlyCostPdf({ product, data: result });
35+
const selectedDate = result.startDate;
36+
const pdfBuffer = await generateYearlyCostPdf({ product, data: result, selectedDate });
3737
return PdfResponse(pdfBuffer, `yearly-costs-${year}.pdf`);
3838
});

app/app/private-cloud/products/(product)/[licencePlate]/costs/page.tsx

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
'use client';
22

33
import { Box, Button, LoadingOverlay, Tabs } from '@mantine/core';
4+
import { format } from 'date-fns';
45
import { useEffect, useState } from 'react';
56
import { z } from 'zod';
67
import DataTable from '@/components/generic/data-table/DataTable';
78
import CostSummary from '@/components/private-cloud/CostSummary';
89
import DateSelector from '@/components/private-cloud/DateSelector';
9-
import { dailyCostColumns, getDailyCostData, getMonthlyCostData, GlobalRole, monthlyCostColumns } from '@/constants';
10+
import {
11+
calculateTotalCost,
12+
dailyCostColumns,
13+
getDailyCostData,
14+
getMonthlyCostData,
15+
GlobalRole,
16+
monthlyCostColumns,
17+
} from '@/constants';
1018
import createClientPage from '@/core/client-page';
19+
import {
20+
downloadPrivateCloudMonthlyCosts,
21+
downloadPrivateCloudQuarterlyCosts,
22+
downloadPrivateCloudYearlyCosts,
23+
} from '@/services/backend/private-cloud/products';
1124
import {
1225
DailyCostMetric,
1326
MonthlyCost,
@@ -16,7 +29,7 @@ import {
1629
TimeView,
1730
YearlyCost,
1831
} from '@/types/private-cloud';
19-
import { formatCurrency, getDateFromYyyyMmDd, getMonthNameFromNumber } from '@/utils/js';
32+
import { formatAsYearQuarter, formatCurrency, getDateFromYyyyMmDd, getMonthNameFromNumber } from '@/utils/js';
2033
import Monthly from './Monthly';
2134
import Quarterly from './Quarterly';
2235
import Yearly from './Yearly';
@@ -37,15 +50,6 @@ const privateCloudProductCosts = createClientPage({
3750
validations: { pathParams: pathParamSchema },
3851
});
3952

40-
const calculateTotalCost = <T extends { dayDetails?: { totalCost: number }; monthDetails?: { totalCost: number } }>(
41-
data: T[],
42-
): number => {
43-
return data.reduce((sum, item) => {
44-
const cost = item.dayDetails?.totalCost ?? item.monthDetails?.totalCost ?? 0;
45-
return sum + cost;
46-
}, 0);
47-
};
48-
4953
function TableFooter({ label, totalCost }: { label?: string; totalCost: number }) {
5054
return (
5155
<tr>
@@ -65,6 +69,7 @@ export default privateCloudProductCosts(({ getPathParams, session }) => {
6569
const [costData, setCostData] = useState<MonthlyCost | QuarterlyCost | YearlyCost>();
6670
const [forecastEnabled, setForecastEnabled] = useState(false);
6771
const [selectedDate, setSelectedDate] = useState(new Date());
72+
const [downloading, setDownloading] = useState(false);
6873
const [viewMode, setViewMode] = useState<TimeView>(TimeView.Monthly);
6974
const [isLoading, setIsLoading] = useState(true);
7075

@@ -162,6 +167,18 @@ export default privateCloudProductCosts(({ getPathParams, session }) => {
162167
}
163168
};
164169

170+
async function handleDownloadCostPdf() {
171+
if (!costData) return;
172+
setDownloading(true);
173+
const downloadPDF =
174+
{
175+
[TimeView.Monthly]: () => downloadPrivateCloudMonthlyCosts(licencePlate, format(selectedDate, 'yyyy-MM')),
176+
[TimeView.Quarterly]: () => downloadPrivateCloudQuarterlyCosts(licencePlate, formatAsYearQuarter(selectedDate)),
177+
}[viewMode] || (() => downloadPrivateCloudYearlyCosts(licencePlate, selectedDate.getFullYear().toString()));
178+
await downloadPDF();
179+
setDownloading(false);
180+
}
181+
165182
return (
166183
<div className="space-y-5">
167184
<Box pos="relative">
@@ -175,7 +192,13 @@ export default privateCloudProductCosts(({ getPathParams, session }) => {
175192
{costData && (
176193
<>
177194
<CostSummary data={costData} selectedDate={selectedDate} viewMode={viewMode} />
178-
<Button onClick={async () => {}} className="absolute right-0 top-[10px]">
195+
<Button
196+
loading={downloading}
197+
onClick={async () => {
198+
handleDownloadCostPdf();
199+
}}
200+
className="absolute right-0 top-[10px]"
201+
>
179202
Download PDF
180203
</Button>
181204
</>

app/components/private-cloud/CostSummary.tsx

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ export default function CostSummary({
66
data,
77
selectedDate,
88
viewMode,
9+
isFromPDFDownloader = false,
910
}: {
1011
data: MonthlyCost | YearlyCost | QuarterlyCost;
1112
selectedDate: Date;
1213
viewMode: TimeView;
14+
isFromPDFDownloader?: boolean;
1315
}) {
1416
if (!data) return null;
1517

@@ -64,63 +66,72 @@ export default function CostSummary({
6466
<div className="space-y-8 mb-10">
6567
<div className="flex items-center">
6668
<div>
67-
<h1 className="text-3xl font-bold mb-4">Summary</h1>
68-
<p className="mb-1">
69+
<div className="text-3xl font-bold mb-4">Summary</div>
70+
<div className="mb-1">
6971
<strong>Current billing period:</strong> {data.billingPeriod}
70-
</p>
71-
<p className="mb-16">
72+
</div>
73+
<div className="mb-16">
7274
<strong>Account coding:</strong> {data.accountCoding}
73-
</p>
75+
</div>
7476
</div>
7577
</div>
76-
<div className="relative">
77-
{
78-
<div className="flex items-center gap-4 gap-x-20">
79-
<p className="text-md flex-shrink-0">
80-
Current billing period
81-
<br />
82-
starts at <strong>{startDate}</strong>
83-
</p>
84-
85-
<div className="flex-1 relative">
86-
<div className="w-full bg-gray-100 rounded-full h-4 mb-2 border border-gray-200 overflow-hidden">
87-
<div
88-
className="bg-blue-500 h-full rounded-full transition-all duration-500"
89-
style={{ width: `${percentageProgress}%` }}
90-
></div>
91-
</div>
78+
<div>
79+
<div className="flex items-center gap-4 gap-x-20">
80+
<div className="text-md flex-shrink-0">
81+
Current billing period
82+
<br />
83+
starts at <strong>{startDate}</strong>
84+
</div>
9285

86+
<div className="flex-1 relative ml-9 mr-9">
87+
{hasCurrentTotal && (
9388
<div
94-
className="absolute top-0 transition-all duration-500"
89+
className="absolute top-0 duration-500 z-10"
9590
style={{
9691
left: `${percentageProgress}%`,
9792
transform: 'translateX(-50%)',
9893
marginTop: '-100px',
9994
}}
10095
>
101-
{hasCurrentTotal && (
102-
<div className="relative p-3 w-64 max-w-xs text-center bg-transparent">
103-
<p className="text-2xl font-bold mb-1">{formatCurrency(data.currentTotal)}</p>
104-
<p className="text-xs text-gray-600 whitespace-nowrap overflow-hidden text-ellipsis">
105-
Cost to date at{' '}
106-
<strong className="text-gray-800">
107-
{currentMonth} {currentMonthDay}
108-
</strong>
109-
</p>
96+
<div
97+
className={`relative text-center bg-transparent ${isFromPDFDownloader ? `-mt-20` : `mt-4`} ${
98+
isFromPDFDownloader ? `ml-[${(percentageProgress * 450) / 100}px]` : ''
99+
}`}
100+
>
101+
<div className="text-2xl font-bold">{formatCurrency(data.currentTotal)}</div>
102+
<div className="text-md text-gray-600 whitespace-nowrap overflow-hidden text-ellipsis">
103+
Cost to date at{' '}
104+
<strong className="text-gray-800">
105+
{currentMonth} {currentMonthDay}
106+
</strong>
110107
</div>
111-
)}
108+
</div>
112109
</div>
113-
</div>
110+
)}
114111

115-
<div className="mb-4 gap-x-20">
116-
{hasEstimatedTotal && <p className="text-2xl font-bold">{projectedCost}</p>}
117-
{hasGrandTotal && <p className="text-2xl font-bold">{projectedCost}</p>}
118-
<p className="text-md">
112+
<div
113+
className={`w-full bg-gray-100 rounded-full ${
114+
isFromPDFDownloader ? 'h-2' : 'h-4'
115+
} mb-2 border border-gray-200 overflow-hidden`}
116+
>
117+
<div
118+
className={`bg-blue-500 h-full rounded-full transition-all duration-500 ${
119+
isFromPDFDownloader ? `w-[${percentageProgress}%]` : ''
120+
}`}
121+
style={isFromPDFDownloader ? undefined : { width: `${percentageProgress}%` }}
122+
/>
123+
</div>
124+
</div>
125+
<div className="mb-4 gap-x-20">
126+
<div>
127+
{hasEstimatedTotal && <div className="text-2xl font-bold">{projectedCost}</div>}
128+
{hasGrandTotal && <div className="text-2xl font-bold">{projectedCost}</div>}
129+
<div className="text-md">
119130
Projected cost at <strong>{endDate}</strong>
120-
</p>
131+
</div>
121132
</div>
122133
</div>
123-
}
134+
</div>
124135
</div>
125136
</div>
126137
);

app/components/private-cloud/monthly-cost/MonthlyCostSummary.tsx

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)