Skip to content

Commit f44880b

Browse files
authored
Merge pull request #5998 from bcgov/feat/5957
feat(5957): redesign cost pages
2 parents f4a182b + a39c1d6 commit f44880b

File tree

14 files changed

+683
-296
lines changed

14 files changed

+683
-296
lines changed
Lines changed: 37 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,56 @@
11
'use client';
22

3-
import { Button, Tooltip } from '@mantine/core';
4-
import { MonthPickerInput } from '@mantine/dates';
53
import { useQuery } from '@tanstack/react-query';
64
import { format } from 'date-fns';
75
import { Session } from 'next-auth';
8-
import { useState } from 'react';
9-
import DataTable from '@/components/generic/data-table/DataTable';
10-
import LoadingBox from '@/components/generic/LoadingBox';
11-
import MonthlyCostSummary from '@/components/private-cloud/monthly-cost/MonthlyCostSummary';
12-
import MonthlyCostChart from '@/components/private-cloud/monthly-cost/MonthyCostChart';
13-
import { dailyCostColumns, periodicCostColumns } from '@/constants/private-cloud';
14-
import { downloadPrivateCloudMonthlyCosts, getMonthlyCosts } from '@/services/backend/private-cloud/products';
15-
import { DailyCostMetric, PeriodicCostMetric } from '@/types/private-cloud';
16-
import { getDateFromYyyyMmDd } from '@/utils/js';
17-
18-
export default function Monthly({ licencePlate, session }: { licencePlate: string; session: Session }) {
19-
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
20-
const [downloading, setDownloading] = useState(false);
21-
22-
const { data, isLoading, isError } = useQuery({
6+
import { useEffect } from 'react';
7+
import MonthlyCostChart from '@/components/private-cloud/monthly-cost/MonthlyCostChart';
8+
import { getMonthlyCosts } from '@/services/backend/private-cloud/products';
9+
import { MonthlyCost } from '@/types/private-cloud';
10+
11+
export default function Monthly({
12+
selectedDate,
13+
licencePlate,
14+
session,
15+
onDataLoaded,
16+
forecastEnabled,
17+
onLoadingDone,
18+
}: {
19+
selectedDate: Date;
20+
licencePlate: string;
21+
session: Session;
22+
onDataLoaded: (data: MonthlyCost) => void;
23+
forecastEnabled: boolean;
24+
onLoadingDone: (isLoading: boolean) => void;
25+
}) {
26+
const { data, isLoading } = useQuery({
2327
queryKey: ['costItems', licencePlate, selectedDate ? format(selectedDate, 'yyyy-MM') : null],
2428
queryFn: () => getMonthlyCosts(licencePlate, format(selectedDate!, 'yyyy-MM')),
2529
enabled: !!licencePlate && !!selectedDate,
2630
});
2731

32+
useEffect(() => {
33+
onLoadingDone(isLoading);
34+
}, [isLoading, onLoadingDone]);
35+
36+
useEffect(() => {
37+
if (data) {
38+
onDataLoaded(data);
39+
}
40+
}, [data, onDataLoaded]);
41+
2842
if (!data || !session.previews.costRecovery) {
2943
return null;
3044
}
3145

32-
const handleChange = (date: string | null) => {
33-
setSelectedDate(date ? getDateFromYyyyMmDd(date) : new Date());
34-
};
35-
36-
const dailyCostData = data.days.map((day, idx) => {
37-
const { cpuToDate, storageToDate, cpuToProjected, storageToProjected } = data.dayDetails;
38-
const totalCost = cpuToDate[idx] + storageToDate[idx] + cpuToProjected[idx] + storageToProjected[idx];
39-
40-
return {
41-
day,
42-
dayDetails: {
43-
cpuToDate: cpuToDate[idx],
44-
storageToDate: storageToDate[idx],
45-
cpuToProjected: cpuToProjected[idx],
46-
storageToProjected: storageToProjected[idx],
47-
totalCost,
48-
},
49-
};
50-
});
51-
5246
return (
53-
<div>
54-
<div className="flex items-center gap-4 mb-6">
55-
<Tooltip label="Select a month">
56-
<MonthPickerInput
57-
placeholder="Select a month"
58-
value={selectedDate}
59-
onChange={handleChange}
60-
maw={200}
61-
clearable
62-
/>
63-
</Tooltip>
64-
65-
{data.items.length > 0 && (
66-
<div className="ml-auto">
67-
<Button
68-
loading={downloading}
69-
onClick={async () => {
70-
if (!data) return;
71-
setDownloading(true);
72-
await downloadPrivateCloudMonthlyCosts(licencePlate, format(selectedDate, 'yyyy-MM'));
73-
setDownloading(false);
74-
}}
75-
>
76-
Download PDF
77-
</Button>
78-
</div>
79-
)}
80-
</div>
81-
82-
<MonthlyCostSummary data={data} />
83-
47+
<>
8448
{data.items.length > 0 && (
85-
<div className="my-8">
86-
<MonthlyCostChart data={{ days: data.days, dayDetails: data.dayDetails }} />
87-
</div>
49+
<MonthlyCostChart
50+
data={{ days: data.days, dayDetails: data.dayDetails, billingPeriod: data.billingPeriod }}
51+
isForecastEnabled={forecastEnabled}
52+
/>
8853
)}
89-
90-
<LoadingBox isLoading={isLoading}>
91-
<DataTable<PeriodicCostMetric> data={data.items} columns={periodicCostColumns} defaultPageSize={5} />
92-
<DataTable<DailyCostMetric> data={dailyCostData} columns={dailyCostColumns} defaultPageSize={5} />
93-
</LoadingBox>
94-
</div>
54+
</>
9555
);
9656
}
Lines changed: 38 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,56 @@
11
'use client';
22

3-
import { Button, Tooltip } from '@mantine/core';
4-
import { MonthPickerInput } from '@mantine/dates';
53
import { useQuery } from '@tanstack/react-query';
64
import { Session } from 'next-auth';
7-
import { useState } from 'react';
8-
import DataTable from '@/components/generic/data-table/DataTable';
9-
import LoadingBox from '@/components/generic/LoadingBox';
5+
import { useEffect } from 'react';
106
import QuarterlyCostChart from '@/components/private-cloud/quarterly-cost/QuarterlyCostChart';
11-
import QuarterlyCostSummary from '@/components/private-cloud/quarterly-cost/QuarterlyCostSummary';
12-
import { monthlyCostColumns, periodicCostColumns } from '@/constants/private-cloud';
13-
import { downloadPrivateCloudQuarterlyCosts, getQuarterlyCosts } from '@/services/backend/private-cloud/products';
14-
import { MonthlyCostMetric, PeriodicCostMetric } from '@/types/private-cloud';
15-
import { formatAsYearQuarter, getDateFromYyyyMmDd } from '@/utils/js';
16-
17-
export default function Quarterly({ licencePlate, session }: { licencePlate: string; session: Session }) {
18-
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
19-
const [downloading, setDownloading] = useState(false);
20-
21-
const { data, isLoading, isError } = useQuery({
7+
import { getQuarterlyCosts } from '@/services/backend/private-cloud/products';
8+
import { QuarterlyCost } from '@/types/private-cloud';
9+
import { formatAsYearQuarter } from '@/utils/js';
10+
11+
export default function Quarterly({
12+
selectedDate,
13+
licencePlate,
14+
session,
15+
onDataLoaded,
16+
forecastEnabled,
17+
onLoadingDone,
18+
}: {
19+
selectedDate: Date;
20+
licencePlate: string;
21+
session: Session;
22+
onDataLoaded: (data: QuarterlyCost) => void;
23+
forecastEnabled: boolean;
24+
onLoadingDone: (isLoading: boolean) => void;
25+
}) {
26+
const { data, isLoading } = useQuery({
2227
queryKey: ['costItems', licencePlate, selectedDate ? formatAsYearQuarter(selectedDate) : null],
2328
queryFn: () => getQuarterlyCosts(licencePlate, formatAsYearQuarter(selectedDate)),
2429
enabled: !!licencePlate && !!selectedDate,
2530
});
2631

27-
if (!data || !session?.previews.costRecovery) {
28-
return null;
29-
}
30-
31-
const handleChange = (date: string | null) => {
32-
setSelectedDate(date ? getDateFromYyyyMmDd(date) : new Date());
33-
};
32+
useEffect(() => {
33+
onLoadingDone(isLoading);
34+
}, [isLoading, onLoadingDone]);
3435

35-
const monthlyCostData = data.months.map((month, idx) => {
36-
const { cpuToDate, storageToDate, cpuToProjected, storageToProjected } = data.monthDetails;
37-
const totalCost = cpuToDate[idx] + storageToDate[idx] + cpuToProjected[idx] + storageToProjected[idx];
36+
useEffect(() => {
37+
if (data) {
38+
onDataLoaded(data);
39+
}
40+
}, [data, onDataLoaded]);
3841

39-
return {
40-
month,
41-
monthDetails: {
42-
cpuToDate: cpuToDate[idx],
43-
storageToDate: storageToDate[idx],
44-
cpuToProjected: cpuToProjected[idx],
45-
storageToProjected: storageToProjected[idx],
46-
totalCost,
47-
},
48-
};
49-
});
42+
if (!data || !session.previews.costRecovery) {
43+
return null;
44+
}
5045

5146
return (
52-
<div>
53-
<div className="flex items-center gap-4 mb-6">
54-
<Tooltip label="Select a month within the quarter">
55-
<MonthPickerInput
56-
placeholder="Select a month"
57-
value={selectedDate}
58-
onChange={handleChange}
59-
maw={200}
60-
clearable
61-
/>
62-
</Tooltip>
63-
{data.items.length > 0 && (
64-
<div className="ml-auto">
65-
<Button
66-
loading={downloading}
67-
onClick={async () => {
68-
if (!data) return;
69-
setDownloading(true);
70-
await downloadPrivateCloudQuarterlyCosts(licencePlate, formatAsYearQuarter(selectedDate));
71-
setDownloading(false);
72-
}}
73-
>
74-
Download PDF
75-
</Button>
76-
</div>
77-
)}
78-
</div>
79-
80-
<QuarterlyCostSummary data={data} />
81-
47+
<>
8248
{data.items.length > 0 && (
83-
<div className="my-8">
84-
<QuarterlyCostChart data={{ months: data.months, monthDetails: data.monthDetails }} />
85-
</div>
49+
<QuarterlyCostChart
50+
data={{ months: data.months, monthDetails: data.monthDetails, billingPeriod: data.billingPeriod }}
51+
isForecastEnabled={forecastEnabled}
52+
/>
8653
)}
87-
88-
<LoadingBox isLoading={isLoading}>
89-
<DataTable<PeriodicCostMetric> data={data.items} columns={periodicCostColumns} defaultPageSize={5} />
90-
<DataTable<MonthlyCostMetric> data={monthlyCostData} columns={monthlyCostColumns} defaultPageSize={5} />
91-
</LoadingBox>
92-
</div>
54+
</>
9355
);
9456
}

0 commit comments

Comments
 (0)