Skip to content

Commit a70d8c2

Browse files
committed
feat(5957): update cc table and cost charts for new design
1 parent 15c2cee commit a70d8c2

File tree

8 files changed

+183
-110
lines changed

8 files changed

+183
-110
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ export default function Yearly({ licencePlate, session }: { licencePlate: string
2828
return null;
2929
}
3030

31-
const handleChange = (year: string | null) => {
32-
setSelectedYear(year ? new Date(Number(year)) : new Date());
31+
const handleChange = (value: string | null) => {
32+
setSelectedYear(value ? new Date(parseInt(value, 10), 0, 1) : new Date());
3333
};
3434

3535
const monthlyCostData = data.months.map((month, idx) => {

app/components/generic/data-table/DataTable.tsx

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import _get from 'lodash-es/get';
1212
import _isString from 'lodash-es/isString';
1313
import _startCase from 'lodash-es/startCase';
14-
import { useMemo, useState } from 'react';
14+
import { useEffect, useMemo, useState } from 'react';
1515
import Pagination from './Pagination';
1616

1717
interface ColumnDefinition<TData> {
@@ -24,19 +24,30 @@ interface TableProps<TData> {
2424
columns?: ColumnDefinition<TData>[];
2525
data: TData[];
2626
defaultPageSize?: number;
27+
disablePagination?: boolean;
28+
footer?: React.ReactNode;
2729
}
2830

2931
export default function DataTable<TData extends object>({
3032
columns: _columns,
3133
data,
3234
defaultPageSize = 10,
35+
disablePagination = false,
36+
footer,
3337
}: TableProps<TData>) {
3438
const columnHelper = createColumnHelper<TData>();
3539
const [pagination, setPagination] = useState({
3640
pageIndex: 0,
37-
pageSize: defaultPageSize,
41+
pageSize: disablePagination ? data.length : defaultPageSize,
3842
});
3943

44+
useEffect(() => {
45+
setPagination(() => ({
46+
pageIndex: 0,
47+
pageSize: disablePagination ? data.length : defaultPageSize,
48+
}));
49+
}, [disablePagination, data.length, defaultPageSize]);
50+
4051
const columnDefs = useMemo(() => {
4152
const cols =
4253
_columns ||
@@ -89,39 +100,44 @@ export default function DataTable<TData extends object>({
89100

90101
return (
91102
<>
92-
<table className="w-full text-sm border-collapse border mt-5">
93-
<thead>
94-
{table.getHeaderGroups().map((headerGroup) => (
95-
<tr key={headerGroup.id}>
96-
{headerGroup.headers.map((header) => (
97-
<th className="text-left p-2 border" key={header.id}>
98-
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
99-
</th>
103+
<div className="border border-gray-200 overflow-hidden mt-5">
104+
<div className="overflow-x-auto">
105+
<table className="w-full text-sm border-collapse">
106+
<thead>
107+
{table.getHeaderGroups().map((headerGroup) => (
108+
<tr key={headerGroup.id}>
109+
{headerGroup.headers.map((header) => (
110+
<th className="text-left p-2 border-b border-gray-200 bg-gray-100" key={header.id}>
111+
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
112+
</th>
113+
))}
114+
</tr>
100115
))}
101-
</tr>
102-
))}
103-
</thead>
104-
<tbody>
105-
{table.getRowModel().rows.length > 0 ? (
106-
table.getRowModel().rows.map((row) => (
107-
<tr key={row.id} className="bg-white odd:bg-gray-50">
108-
{row.getVisibleCells().map((cell) => (
109-
<td key={cell.id} className="p-2 border align-center">
110-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
116+
</thead>
117+
<tbody>
118+
{table.getRowModel().rows.length > 0 ? (
119+
table.getRowModel().rows.map((row) => (
120+
<tr key={row.id} className="bg-white even:bg-gray-50">
121+
{row.getVisibleCells().map((cell) => (
122+
<td key={cell.id} className="p-2 border-b border-gray-200 align-center">
123+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
124+
</td>
125+
))}
126+
</tr>
127+
))
128+
) : (
129+
<tr>
130+
<td colSpan={6} className="p-2 border-b border-gray-200 italic text-center">
131+
No data available.
111132
</td>
112-
))}
113-
</tr>
114-
))
115-
) : (
116-
<tr>
117-
<td colSpan={6} className="p-2 border italic text-center">
118-
No data available.
119-
</td>
120-
</tr>
121-
)}
122-
</tbody>
123-
</table>
124-
{data.length > 0 && <Pagination table={table} />}
133+
</tr>
134+
)}
135+
</tbody>
136+
{footer && <tfoot>{footer}</tfoot>}
137+
</table>
138+
</div>
139+
</div>
140+
{data.length > 0 && !disablePagination && <Pagination table={table} />}
125141
</>
126142
);
127143
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ import { Bar } from 'react-chartjs-2';
33
import { MonthlyCost } from '@/types/private-cloud';
44
import { getMonthlyCostChartConfig } from './monthly-cost-chart-data';
55

6-
export default function MonthlyCostChart({ data }: { data: Pick<MonthlyCost, 'days' | 'dayDetails'> }) {
7-
const { options, data: chartData } = getMonthlyCostChartConfig({ data });
6+
export default function MonthlyCostChart({
7+
data,
8+
isForecastEnabled = true,
9+
}: {
10+
data: Pick<MonthlyCost, 'days' | 'dayDetails'>;
11+
isForecastEnabled?: boolean;
12+
}) {
13+
const { options, data: chartData } = getMonthlyCostChartConfig({ data, isForecastEnabled });
814

915
return (
1016
<Card shadow="sm" padding="lg" radius="md" withBorder>

app/components/private-cloud/monthly-cost/monthly-cost-chart-data.tsx

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import { TooltipItem } from 'chart.js';
22
import { MonthlyCost } from '@/types/private-cloud';
33
import { formatCurrency } from '@/utils/js';
44

5-
export function getMonthlyCostChartConfig({ data }: { data: Pick<MonthlyCost, 'days' | 'dayDetails'> }) {
5+
export function getMonthlyCostChartConfig({
6+
data,
7+
isForecastEnabled,
8+
}: {
9+
data: Pick<MonthlyCost, 'days' | 'dayDetails'>;
10+
isForecastEnabled: boolean;
11+
}) {
612
const options = {
713
plugins: {
814
title: {
@@ -49,30 +55,37 @@ export function getMonthlyCostChartConfig({ data }: { data: Pick<MonthlyCost, 'd
4955
},
5056
};
5157

58+
const updatedChartData = [
59+
{
60+
label: 'CPU Cost (CA$)',
61+
data: data.dayDetails.cpuToDate,
62+
backgroundColor: '#4CAF50',
63+
},
64+
{
65+
label: 'Storage Cost (CA$)',
66+
data: data.dayDetails.storageToDate,
67+
backgroundColor: '#00CAFF',
68+
},
69+
{
70+
label: 'CPU Cost - Projected (CA$)',
71+
data: data.dayDetails.cpuToProjected,
72+
backgroundColor: '#E0F7E1',
73+
},
74+
{
75+
label: 'Storage Cost - Projected (CA$)',
76+
data: data.dayDetails.storageToProjected,
77+
backgroundColor: '#CCF2FF',
78+
},
79+
];
80+
81+
if (!isForecastEnabled) {
82+
updatedChartData.pop();
83+
updatedChartData.pop();
84+
}
85+
5286
const chartData = {
5387
labels: data.days,
54-
datasets: [
55-
{
56-
label: 'CPU Cost (CA$)',
57-
data: data.dayDetails.cpuToDate,
58-
backgroundColor: '#1E3A8A',
59-
},
60-
{
61-
label: 'Storage Cost (CA$)',
62-
data: data.dayDetails.storageToDate,
63-
backgroundColor: '#047857',
64-
},
65-
{
66-
label: 'CPU Cost - Projected (CA$)',
67-
data: data.dayDetails.cpuToProjected,
68-
backgroundColor: '#A7C7E7',
69-
},
70-
{
71-
label: 'Storage Cost - Projected (CA$)',
72-
data: data.dayDetails.storageToProjected,
73-
backgroundColor: '#A8D5BA',
74-
},
75-
],
88+
datasets: updatedChartData,
7689
};
7790

7891
return { options, data: chartData };

app/components/private-cloud/quarterly-cost/QuarterlyCostChart.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ import { Bar } from 'react-chartjs-2';
33
import { QuarterlyCost } from '@/types/private-cloud';
44
import { getQuarterlyCostChartConfig } from './quarterly-cost-chart-data';
55

6-
export default function QuarterlyCostChart({ data }: { data: Pick<QuarterlyCost, 'months' | 'monthDetails'> }) {
7-
const { options, data: chartData } = getQuarterlyCostChartConfig({ data });
6+
export default function QuarterlyCostChart({
7+
data,
8+
isForecastEnabled = true,
9+
}: {
10+
data: Pick<QuarterlyCost, 'months' | 'monthDetails'>;
11+
isForecastEnabled?: boolean;
12+
}) {
13+
const { options, data: chartData } = getQuarterlyCostChartConfig({ data, isForecastEnabled });
814

915
return (
1016
<Card shadow="sm" padding="lg" radius="md" withBorder>

app/components/private-cloud/quarterly-cost/quarterly-cost-chart-data.tsx

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import { TooltipItem } from 'chart.js';
22
import { QuarterlyCost } from '@/types/private-cloud';
33
import { formatCurrency, getMonthNameFromNumber } from '@/utils/js';
44

5-
export function getQuarterlyCostChartConfig({ data }: { data: Pick<QuarterlyCost, 'months' | 'monthDetails'> }) {
5+
export function getQuarterlyCostChartConfig({
6+
data,
7+
isForecastEnabled,
8+
}: {
9+
data: Pick<QuarterlyCost, 'months' | 'monthDetails'>;
10+
isForecastEnabled: boolean;
11+
}) {
612
const options = {
713
plugins: {
814
title: {
@@ -49,30 +55,37 @@ export function getQuarterlyCostChartConfig({ data }: { data: Pick<QuarterlyCost
4955
},
5056
};
5157

58+
const updatedChartData = [
59+
{
60+
label: 'CPU Cost (CA$)',
61+
data: data.monthDetails.cpuToDate,
62+
backgroundColor: '#4CAF50',
63+
},
64+
{
65+
label: 'Storage Cost (CA$)',
66+
data: data.monthDetails.storageToDate,
67+
backgroundColor: '#00CAFF',
68+
},
69+
{
70+
label: 'CPU Cost - Projected (CA$)',
71+
data: data.monthDetails.cpuToProjected,
72+
backgroundColor: '#E0F7E1',
73+
},
74+
{
75+
label: 'Storage Cost - Projected (CA$)',
76+
data: data.monthDetails.storageToProjected,
77+
backgroundColor: '#CCF2FF',
78+
},
79+
];
80+
81+
if (!isForecastEnabled) {
82+
updatedChartData.pop();
83+
updatedChartData.pop();
84+
}
85+
5286
const chartData = {
5387
labels: data.months.map(getMonthNameFromNumber),
54-
datasets: [
55-
{
56-
label: 'CPU Cost (CA$)',
57-
data: data.monthDetails.cpuToDate,
58-
backgroundColor: '#1E3A8A',
59-
},
60-
{
61-
label: 'Storage Cost (CA$)',
62-
data: data.monthDetails.storageToDate,
63-
backgroundColor: '#047857',
64-
},
65-
{
66-
label: 'CPU Cost - Projected (CA$)',
67-
data: data.monthDetails.cpuToProjected,
68-
backgroundColor: '#A7C7E7',
69-
},
70-
{
71-
label: 'Storage Cost - Projected (CA$)',
72-
data: data.monthDetails.storageToProjected,
73-
backgroundColor: '#A8D5BA',
74-
},
75-
],
88+
datasets: updatedChartData,
7689
};
7790

7891
return { options, data: chartData };

app/components/private-cloud/yearly-cost/YearlyCostChart.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ import { Bar } from 'react-chartjs-2';
33
import { YearlyCost } from '@/types/private-cloud';
44
import { getYearlyCostChartConfig } from './yearly-cost-chart-data';
55

6-
export default function YearlyCostChart({ data }: { data: Pick<YearlyCost, 'months' | 'monthDetails'> }) {
7-
const { options, data: chartData } = getYearlyCostChartConfig({ data });
6+
export default function YearlyCostChart({
7+
data,
8+
isForecastEnabled = true,
9+
}: {
10+
data: Pick<YearlyCost, 'months' | 'monthDetails'>;
11+
isForecastEnabled?: boolean;
12+
}) {
13+
const { options, data: chartData } = getYearlyCostChartConfig({ data, isForecastEnabled });
814

915
return (
1016
<Card shadow="sm" padding="lg" radius="md" withBorder>

0 commit comments

Comments
 (0)