mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-27 11:02:16 +01:00
feat: add new dates and plan price (#10774)
<img width="2159" height="1617" alt="image" src="https://github.com/user-attachments/assets/478ea289-dc0f-439e-92e4-a22fa44a0650" />
This commit is contained in:
parent
8879cc4b46
commit
0d252558c4
@ -5,6 +5,8 @@ import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstan
|
|||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import { InstanceState } from 'interfaces/instance';
|
import { InstanceState } from 'interfaces/instance';
|
||||||
import { formatApiPath } from 'utils/formatPath';
|
import { formatApiPath } from 'utils/formatPath';
|
||||||
|
import { useDetailedInvoices } from 'hooks/api/getters/useDetailedInvoices/useDetailedInvoices';
|
||||||
|
import { formatCurrency } from '../BillingInvoices/BillingInvoice/formatCurrency.js';
|
||||||
const PORTAL_URL = formatApiPath('api/admin/invoices');
|
const PORTAL_URL = formatApiPath('api/admin/invoices');
|
||||||
|
|
||||||
type BillingInfoProps = {};
|
type BillingInfoProps = {};
|
||||||
@ -63,6 +65,7 @@ export const BillingInfo: FC<BillingInfoProps> = () => {
|
|||||||
const {
|
const {
|
||||||
uiConfig: { billing },
|
uiConfig: { billing },
|
||||||
} = useUiConfig();
|
} = useUiConfig();
|
||||||
|
const { planPrice, planCurrency } = useDetailedInvoices();
|
||||||
|
|
||||||
if (!instanceStatus) {
|
if (!instanceStatus) {
|
||||||
return (
|
return (
|
||||||
@ -105,8 +108,13 @@ export const BillingInfo: FC<BillingInfoProps> = () => {
|
|||||||
</StyledRow>
|
</StyledRow>
|
||||||
<StyledRow>
|
<StyledRow>
|
||||||
<StyledItemTitle>Plan price</StyledItemTitle>{' '}
|
<StyledItemTitle>Plan price</StyledItemTitle>{' '}
|
||||||
{/* FIXME: where to take data from? */}
|
<StyledItemValue>
|
||||||
<StyledItemValue>$450 / month</StyledItemValue>
|
{planPrice !== undefined
|
||||||
|
? `${formatCurrency(planPrice, planCurrency)} ${
|
||||||
|
isPAYG ? 'per seat' : '/ month'
|
||||||
|
}`
|
||||||
|
: '-'}
|
||||||
|
</StyledItemValue>
|
||||||
</StyledRow>
|
</StyledRow>
|
||||||
<StyledDivider />
|
<StyledDivider />
|
||||||
<StyledButton
|
<StyledButton
|
||||||
|
|||||||
@ -5,7 +5,10 @@ import {
|
|||||||
Accordion,
|
Accordion,
|
||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
|
Button,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
import ReceiptLongOutlinedIcon from '@mui/icons-material/ReceiptLongOutlined';
|
||||||
|
import DownloadOutlinedIcon from '@mui/icons-material/DownloadOutlined';
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
import { formatCurrency } from './formatCurrency.ts';
|
import { formatCurrency } from './formatCurrency.ts';
|
||||||
import { Badge } from 'component/common/Badge/Badge.tsx';
|
import { Badge } from 'component/common/Badge/Badge.tsx';
|
||||||
@ -84,6 +87,13 @@ const StyledTableRow = styled('div')(({ theme }) => ({
|
|||||||
padding: theme.spacing(1, 0),
|
padding: theme.spacing(1, 0),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const CardActions = styled('div')(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
padding: theme.spacing(1.5, 2, 2),
|
||||||
|
}));
|
||||||
|
|
||||||
export const BillingInvoice = ({
|
export const BillingInvoice = ({
|
||||||
status,
|
status,
|
||||||
invoiceDate,
|
invoiceDate,
|
||||||
@ -93,20 +103,20 @@ export const BillingInvoice = ({
|
|||||||
mainLines,
|
mainLines,
|
||||||
usageLines,
|
usageLines,
|
||||||
}: DetailedInvoicesSchemaInvoicesItem) => {
|
}: DetailedInvoicesSchemaInvoicesItem) => {
|
||||||
const title = invoiceDate
|
const currency = mainLines[0]?.currency || usageLines?.[0]?.currency;
|
||||||
|
|
||||||
|
const formattedTitle = invoiceDate
|
||||||
? new Date(invoiceDate).toLocaleDateString(undefined, {
|
? new Date(invoiceDate).toLocaleDateString(undefined, {
|
||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
})
|
})
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
const currency = mainLines[0]?.currency || usageLines?.[0]?.currency;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardLikeAccordion defaultExpanded>
|
<CardLikeAccordion defaultExpanded>
|
||||||
<HeaderRoot
|
<HeaderRoot
|
||||||
expandIcon={<ExpandMoreIcon />}
|
expandIcon={<ExpandMoreIcon />}
|
||||||
id={`billing-invoice-${title}-header`}
|
id={`billing-invoice-${formattedTitle}-header`}
|
||||||
>
|
>
|
||||||
<HeaderLeft>
|
<HeaderLeft>
|
||||||
<Typography
|
<Typography
|
||||||
@ -114,7 +124,7 @@ export const BillingInvoice = ({
|
|||||||
component='h3'
|
component='h3'
|
||||||
sx={{ fontWeight: 700 }}
|
sx={{ fontWeight: 700 }}
|
||||||
>
|
>
|
||||||
{title}
|
{formattedTitle}
|
||||||
</Typography>
|
</Typography>
|
||||||
</HeaderLeft>
|
</HeaderLeft>
|
||||||
<HeaderRight>
|
<HeaderRight>
|
||||||
@ -170,6 +180,30 @@ export const BillingInvoice = ({
|
|||||||
currency={currency}
|
currency={currency}
|
||||||
/>
|
/>
|
||||||
</StyledInvoiceGrid>
|
</StyledInvoiceGrid>
|
||||||
|
<CardActions>
|
||||||
|
{invoiceURL ? (
|
||||||
|
<Button
|
||||||
|
variant='outlined'
|
||||||
|
href={invoiceURL}
|
||||||
|
target='_blank'
|
||||||
|
rel='noreferrer'
|
||||||
|
startIcon={<ReceiptLongOutlinedIcon />}
|
||||||
|
>
|
||||||
|
View invoice
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
{invoicePDF ? (
|
||||||
|
<Button
|
||||||
|
variant='outlined'
|
||||||
|
href={invoicePDF}
|
||||||
|
target='_blank'
|
||||||
|
rel='noreferrer'
|
||||||
|
startIcon={<DownloadOutlinedIcon />}
|
||||||
|
>
|
||||||
|
Download PDF
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</CardActions>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</CardLikeAccordion>
|
</CardLikeAccordion>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { formatLargeNumbers } from 'component/impact-metrics/metricsFormatters.ts';
|
import { formatLargeNumbers } from 'component/impact-metrics/metricsFormatters.ts';
|
||||||
import { formatCurrency } from '../formatCurrency.ts';
|
import { formatCurrency } from '../formatCurrency.ts';
|
||||||
import { ConsumptionIndicator } from '../ConsumptionIndicator/ConsumptionIndicator.tsx';
|
import { ConsumptionIndicator } from '../ConsumptionIndicator/ConsumptionIndicator.tsx';
|
||||||
import { styled } from '@mui/material';
|
import { styled, Typography } from '@mui/material';
|
||||||
import type { DetailedInvoicesLineSchema } from 'openapi';
|
import type { DetailedInvoicesLineSchema } from 'openapi';
|
||||||
import { StyledAmountCell } from '../BillingInvoice.styles.tsx';
|
import { StyledAmountCell } from '../BillingInvoice.styles.tsx';
|
||||||
|
|
||||||
@ -19,6 +19,17 @@ type BillingInvoiceRowProps = {
|
|||||||
usage?: number;
|
usage?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const StyledDescriptionCell = styled('div')(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: theme.spacing(0.5),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledSubText = styled(Typography)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
fontSize: theme.typography.body2.fontSize,
|
||||||
|
}));
|
||||||
|
|
||||||
export const BillingInvoiceRow = ({
|
export const BillingInvoiceRow = ({
|
||||||
quantity,
|
quantity,
|
||||||
consumption,
|
consumption,
|
||||||
@ -26,15 +37,37 @@ export const BillingInvoiceRow = ({
|
|||||||
description,
|
description,
|
||||||
currency,
|
currency,
|
||||||
totalAmount,
|
totalAmount,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
}: DetailedInvoicesLineSchema) => {
|
}: DetailedInvoicesLineSchema) => {
|
||||||
const percentage =
|
const percentage =
|
||||||
limit && limit > 0
|
limit && limit > 0
|
||||||
? Math.min(100, Math.round(((consumption || 0) / limit) * 100))
|
? Math.min(100, Math.round(((consumption || 0) / limit) * 100))
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const formattedStart = startDate
|
||||||
|
? new Date(startDate).toLocaleDateString(undefined, {
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
const formattedEnd = endDate
|
||||||
|
? new Date(endDate).toLocaleDateString(undefined, {
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>{description}</div>
|
<StyledDescriptionCell>
|
||||||
|
<div>{description}</div>
|
||||||
|
{formattedStart || formattedEnd ? (
|
||||||
|
<StyledSubText>
|
||||||
|
{formattedStart} - {formattedEnd}
|
||||||
|
</StyledSubText>
|
||||||
|
) : null}
|
||||||
|
</StyledDescriptionCell>
|
||||||
<StyledCellWithIndicator>
|
<StyledCellWithIndicator>
|
||||||
<ConsumptionIndicator percentage={percentage || 0} />
|
<ConsumptionIndicator percentage={percentage || 0} />
|
||||||
{limit !== undefined ? formatLargeNumbers(limit) : '–'}
|
{limit !== undefined ? formatLargeNumbers(limit) : '–'}
|
||||||
|
|||||||
@ -20,6 +20,8 @@ export const useDetailedInvoices = (options: SWRConfiguration = {}) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const invoices = useMemo(() => data?.invoices ?? [], [data]);
|
const invoices = useMemo(() => data?.invoices ?? [], [data]);
|
||||||
|
const planPrice = data?.planPrice;
|
||||||
|
const planCurrency = data?.planCurrency;
|
||||||
|
|
||||||
return { invoices, error, loading: isLoading };
|
return { invoices, planPrice, planCurrency, error, loading: isLoading };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,4 +11,8 @@ import type { DetailedInvoicesSchemaInvoicesItem } from './detailedInvoicesSchem
|
|||||||
export interface DetailedInvoicesSchema {
|
export interface DetailedInvoicesSchema {
|
||||||
/** List of invoices with their line items */
|
/** List of invoices with their line items */
|
||||||
invoices: DetailedInvoicesSchemaInvoicesItem[];
|
invoices: DetailedInvoicesSchemaInvoicesItem[];
|
||||||
|
/** The currency code for the plan price */
|
||||||
|
planCurrency?: string;
|
||||||
|
/** The plan price in minor currency units */
|
||||||
|
planPrice?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user