Skip to content

Commit

Permalink
feat(pci-billing): add history billing section
Browse files Browse the repository at this point in the history
ref: DTCORE-2797

Signed-off-by: LIDRISSI Hamid <[email protected]>
  • Loading branch information
seven-amid committed Nov 25, 2024
1 parent 38775ec commit 72072c3
Show file tree
Hide file tree
Showing 22 changed files with 449 additions and 20 deletions.
1 change: 1 addition & 0 deletions packages/manager/apps/pci-billing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"@ovh-ux/manager-config": "^0.4.0",
"@ovh-ux/manager-core-api": "^0.9.0-alpha.0",
"@ovh-ux/manager-core-utils": "^0.3.0",
"@ovh-ux/manager-pci-common": "^0.8.0-alpha.0",
"@ovh-ux/manager-react-components": "^1.41.0-alpha.0",
"@ovh-ux/manager-react-core-application": "0.10.8-alpha.0",
Expand Down
36 changes: 36 additions & 0 deletions packages/manager/apps/pci-billing/src/api/data/history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { v6 } from '@ovh-ux/manager-core-api';
import { TCurrentUsage } from './consumption';

export type TUsageHistoryPeriod = {
id: string;
lastUpdate: string;
period: {
from: string;
to: string;
};
};

export const getUsageHistoryPeriod = async (
projectId: string,
from: string,
to: string,
): Promise<TUsageHistoryPeriod[]> => {
const { data } = await v6.get<TUsageHistoryPeriod[]>(
`/cloud/project/${projectId}/usage/history?from=${from}&to=${to}`,
);

return data;
};

export type THistoryUsage = TCurrentUsage;

export const getUsageHistory = async (
projectId: string,
usageId: string,
): Promise<THistoryUsage> => {
const { data } = await v6.get<THistoryUsage>(
`/cloud/project/${projectId}/usage/history/${usageId}`,
);

return data;
};
43 changes: 29 additions & 14 deletions packages/manager/apps/pci-billing/src/api/hook/useConsumption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ const sumPrices = <T,>(items: T[], key: string) =>

const initMonthlyInstanceList = (data: TCurrentUsage) => {
if (!data?.monthlyUsage) {
return {};
return {
monthlyInstanceList: [],
monthlyInstanceTotalPrice: 0,
};
}

const monthlyInstanceList = data.monthlyUsage.instance.flatMap((instance) =>
Expand All @@ -43,7 +46,7 @@ const initMonthlyInstanceList = (data: TCurrentUsage) => {

const initHourlyInstanceList = (data: TCurrentUsage) => {
if (!data?.hourlyUsage) {
return {};
return { hourlyInstanceList: [], hourlyInstanceTotalPrice: 0 };
}

const hourlyInstanceList = data.hourlyUsage.instance.flatMap((instance) =>
Expand All @@ -70,7 +73,10 @@ const initHourlyInstanceList = (data: TCurrentUsage) => {

const initObjectStorageList = (data: TCurrentUsage) => {
if (!data?.hourlyUsage) {
return {};
return {
objectStorageList: [],
objectStorageTotalPrice: 0,
};
}

const objectStorageList = data.hourlyUsage.storage?.filter(
Expand All @@ -87,7 +93,10 @@ const initObjectStorageList = (data: TCurrentUsage) => {

const initArchiveStorageList = (data: TCurrentUsage) => {
if (!data?.hourlyUsage) {
return {};
return {
archiveStorageList: [],
archiveStorageTotalPrice: 0,
};
}

const archiveStorageList = data.hourlyUsage.storage?.filter(
Expand All @@ -104,7 +113,10 @@ const initArchiveStorageList = (data: TCurrentUsage) => {

const initSnapshotList = (data: TCurrentUsage) => {
if (!data?.hourlyUsage) {
return {};
return {
snapshotList: [],
snapshotsTotalPrice: 0,
};
}

const snapshotList = data.hourlyUsage.snapshot.map((snapshot) => ({
Expand All @@ -122,7 +134,10 @@ const initSnapshotList = (data: TCurrentUsage) => {

const initVolumeList = (data: TCurrentUsage) => {
if (!data?.hourlyUsage) {
return {};
return {
volumeList: [],
volumesTotalPrice: 0,
};
}

const volumeList = data.hourlyUsage.volume.flatMap((volume) =>
Expand All @@ -149,7 +164,10 @@ const initVolumeList = (data: TCurrentUsage) => {

const initInstanceBandwidth = (data: TCurrentUsage) => {
if (!data?.hourlyUsage) {
return {};
return {
bandwidthList: [],
bandwidthTotalPrice: 0,
};
}

const bandwidthList = data.hourlyUsage.instanceBandwidth.map(
Expand Down Expand Up @@ -318,8 +336,6 @@ export type TSnapshot = {
};

export type TConsumptionDetail = {
hourlyBilling: TCurrentUsage;
monthlyBilling: TCurrentUsage;
hourlyInstances: TInstance[];
monthlyInstances: TInstance[];
objectStorages: TStorage[];
Expand Down Expand Up @@ -370,7 +386,7 @@ export type TConsumptionDetail = {
};
};

const getConsumptionDetails = (usage: TCurrentUsage) => {
export const getConsumptionDetails = (usage: TCurrentUsage) => {
const resourceMap = [
{ type: 'registry', key: 'privateRegistry' },
{ type: 'loadbalancer', key: 'kubernetesLoadBalancer' },
Expand Down Expand Up @@ -445,8 +461,6 @@ const getConsumptionDetails = (usage: TCurrentUsage) => {
const finalTotal = roundPrice(totals.hourly.total + totals.monthly.total);

return {
hourlyBilling: usage,
monthlyBilling: usage,
hourlyInstances: hourlyInstanceList,
monthlyInstances: monthlyInstanceList,
objectStorages: objectStorageList,
Expand All @@ -466,9 +480,10 @@ export const useGeTCurrentUsage = (projectId: string) =>
useQuery({
queryKey: [projectId, 'current', 'usage'],
queryFn: async () => {
const usageData = await getCurrentUsage(projectId);
return getConsumptionDetails(usageData);
const currentUsage = await getCurrentUsage(projectId);
return currentUsage;
},
select: (data) => getConsumptionDetails(data),
});

type ActivateMonthlyBillingProps = {
Expand Down
54 changes: 54 additions & 0 deletions packages/manager/apps/pci-billing/src/api/hook/useHistory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useQuery } from '@tanstack/react-query';
import { isSameMonth } from 'date-fns';
import { useComputeDate } from '@/components/history/useComputeDate.hook';
import { getCurrentUsage } from '../data/consumption';
import {
getUsageHistory,
getUsageHistoryPeriod,
TUsageHistoryPeriod,
} from '../data/history';
import { getConsumptionDetails } from './useConsumption';

export const useUsageHistoryPeriod = (
projectId: string,
from: string,
to: string,
) =>
useQuery({
queryKey: [projectId, from, to, 'history', 'usage'],
queryFn: async () => {
const historyPeriod = await getUsageHistoryPeriod(projectId, from, to);
return historyPeriod?.length
? historyPeriod[0]
: ({} as TUsageHistoryPeriod);
},
});

export const useGetUsageHistory = (
projectId: string,
periodDetail: TUsageHistoryPeriod,
) => {
const { billingDate } = useComputeDate();

return useQuery({
queryKey: [projectId, periodDetail?.id, 'history', 'usage'],
queryFn: async () => {
const historyUsage = await getUsageHistory(projectId, periodDetail?.id);
let monthlyDetails;

if (isSameMonth(new Date(), billingDate)) {
const currentUsage = await getCurrentUsage(projectId);
monthlyDetails = currentUsage?.monthlyUsage;
} else if (
new Date(periodDetail.period.to).getUTCMonth() ===
billingDate.getMonth()
) {
monthlyDetails = historyUsage?.monthlyUsage;
}

return { ...historyUsage, monthlyUsage: monthlyDetails };
},
enabled: !!periodDetail?.id,
select: (data) => getConsumptionDetails(data),
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default function ColdArchiveList({
const sortedColdArchives = coldArchives?.sort((a, b) =>
a.region.localeCompare(b.region),
);

return paginateResults(sortedColdArchives || [], pagination);
}, [coldArchives, pagination, setPagination]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function SnapshotList({
const { pagination, setPagination } = useDataGrid();

const getSnapshotPriceInfoTooltip = (snapshot: TSnapshot) =>
`${t('cpbc_snapshot_col_usage_info_part1')}${t(
`${t('cpbc_snapshot_col_usage_info_part1')} ${t(
'cpbc_snapshot_col_usage_info_part2',
{
amount: (snapshot.instance?.quantity?.value || 0).toFixed(2),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default function TooltipIcon({
size={ODS_TEXT_SIZE._100}
level={ODS_TEXT_LEVEL.body}
color={ODS_THEME_COLOR_INTENT.text}
className="break-normal"
>
{content}
</OsdsText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export default function VolumeList({ volumes }: Readonly<VolumeListProps>) {
);

const getVolumePriceInfoTooltip = (volume: TMappedVolume) =>
`${t('cpbc_volume_consumption_tooltip_part1')}${t(
`${t('cpbc_volume_consumption_tooltip_part1')} ${t(
'cpbc_volume_consumption_tooltip_part2',
{
amount: volume.amount,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import {
ODS_BUTTON_SIZE,
ODS_BUTTON_TYPE,
ODS_BUTTON_VARIANT,
ODS_ICON_NAME,
ODS_ICON_SIZE,
ODS_TEXT_LEVEL,
ODS_TEXT_SIZE,
} from '@ovhcloud/ods-components';
import { OsdsButton, OsdsIcon, OsdsText } from '@ovhcloud/ods-components/react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { isSameDay, startOfMonth } from 'date-fns';
import { useComputeDate } from './useComputeDate.hook';

export default function HistoryHeader() {
const { t } = useTranslation('history');

const {
billingDate,
prevMonthDate,
nextMonthDate,
translationValues,
} = useComputeDate();

const isLimitReached = isSameDay(billingDate, startOfMonth(new Date()));

const navigate = useNavigate();
const navigateToMonth = (date: Date) => {
navigate(`../history/${date.getFullYear()}/${date.getMonth() + 1}`);
};

return (
<div className="mb-5 flex justify-between items-center">
<OsdsButton
color={ODS_THEME_COLOR_INTENT.primary}
type={ODS_BUTTON_TYPE.button}
size={ODS_BUTTON_SIZE.sm}
variant={ODS_BUTTON_VARIANT.ghost}
onClick={() => navigateToMonth(prevMonthDate)}
className="flex"
>
<OsdsIcon
name={ODS_ICON_NAME.CHEVRON_LEFT}
size={ODS_ICON_SIZE.xxs}
color={ODS_THEME_COLOR_INTENT.primary}
className="mr-4"
/>
{t('cpbh_previous_month')}
</OsdsButton>

<OsdsText
size={ODS_TEXT_SIZE._500}
level={ODS_TEXT_LEVEL.heading}
color={ODS_THEME_COLOR_INTENT.text}
slot="summary"
>
{t('cpbh_current_month', { ...translationValues })}
</OsdsText>

<OsdsButton
color={ODS_THEME_COLOR_INTENT.primary}
type={ODS_BUTTON_TYPE.button}
size={ODS_BUTTON_SIZE.sm}
variant={ODS_BUTTON_VARIANT.ghost}
onClick={() => navigateToMonth(nextMonthDate)}
disabled={isLimitReached || undefined}
className="flex"
>
{t('cpbh_next_month')}
<OsdsIcon
name={ODS_ICON_NAME.CHEVRON_RIGHT}
size={ODS_ICON_SIZE.xxs}
color={ODS_THEME_COLOR_INTENT.primary}
className="ml-4"
/>
</OsdsButton>
</div>
);
}
Loading

0 comments on commit 72072c3

Please sign in to comment.