Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [SIG-557]: added Billing usage graph - daily and weekly #4686

Merged
merged 14 commits into from
Mar 13, 2024
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
.billing-container {
padding: 16px 0;
width: 100%;
padding-top: 36px;
width: 65%;

.billing-summary {
margin: 24px 8px;
}

.billing-details {
margin: 36px 8px;
margin: 24px 0px;

.ant-table-title {
color: var(--bg-vanilla-400);
background-color: rgb(27, 28, 32);
}

.ant-table-cell {
background-color: var(--bg-ink-400);
border-color: var(--bg-slate-500);
}

.ant-table-tbody {
td {
border-color: var(--bg-slate-500);
}
}
}

.upgrade-plan-benefits {
Expand All @@ -34,3 +50,20 @@
.ant-skeleton.ant-skeleton-element .ant-skeleton-input {
min-width: 100% !important;
}

.lightMode {
.billing-container {
.billing-details {
.ant-table-cell {
background: var(--bg-vanilla-100);
border-color: var(--bg-vanilla-200);
}

.ant-table-tbody {
td {
border-color: var(--bg-vanilla-200);
}
}
}
}
}
156 changes: 76 additions & 80 deletions frontend/src/container/BillingContainer/BillingContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,19 @@
import './BillingContainer.styles.scss';

import { CheckCircleOutlined } from '@ant-design/icons';
import { Button, Col, Row, Skeleton, Table, Tag, Typography } from 'antd';
import { Color } from '@signozhq/design-tokens';
import {
Alert,
Button,
Card,
Col,
Flex,
Row,
Skeleton,
Table,
Tag,
Typography,
} from 'antd';
import { ColumnsType } from 'antd/es/table';
import updateCreditCardApi from 'api/billing/checkout';
import getUsage from 'api/billing/getUsage';
Expand All @@ -24,6 +36,9 @@ import { License } from 'types/api/licenses/def';
import AppReducer from 'types/reducer/app';
import { getFormattedDate, getRemainingDays } from 'utils/timeUtils';

import billingPageRes from './billingResponse.json';
import { BillingUsageGraph } from './BillingUsageGraph/BillingUsageGraph';

interface DataType {
key: string;
name: string;
Expand Down Expand Up @@ -104,12 +119,11 @@ export default function BillingContainer(): JSX.Element {
const daysRemainingStr = 'days remaining in your billing period.';
const [headerText, setHeaderText] = useState('');
const [billAmount, setBillAmount] = useState(0);
const [totalBillAmount, setTotalBillAmount] = useState(0);
const [activeLicense, setActiveLicense] = useState<License | null>(null);
const [daysRemaining, setDaysRemaining] = useState(0);
const [isFreeTrial, setIsFreeTrial] = useState(false);
const [data, setData] = useState<any[]>([]);
const billCurrency = '$';
const [apiResponse, setApiResponse] = useState<any>({});

const { trackEvent } = useAnalytics();

Expand All @@ -121,12 +135,14 @@ export default function BillingContainer(): JSX.Element {
const handleError = useAxiosError();

const processUsageData = useCallback(
(data: any): void => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
SagarRajput-7 marked this conversation as resolved.
Show resolved Hide resolved
(_data: any): void => {
const { data } = billingPageRes;
const {
details: { breakdown = [], total, billTotal },
details: { breakdown = [], billTotal },
billingPeriodStart,
billingPeriodEnd,
} = data?.payload || {};
} = data || {}; // todo - inserting mock data
const formattedUsageData: any[] = [];

if (breakdown && Array.isArray(breakdown)) {
Expand All @@ -141,8 +157,7 @@ export default function BillingContainer(): JSX.Element {
formattedUsageData.push({
key: `${index}${i}`,
name: i === 0 ? element?.type : '',
unit: element?.unit,
dataIngested: tier.quantity,
dataIngested: `${tier.quantity} ${element?.unit}`,
vikrantgupta25 marked this conversation as resolved.
Show resolved Hide resolved
pricePerUnit: tier.unitPrice,
cost: `$ ${tier.tierCost}`,
vikrantgupta25 marked this conversation as resolved.
Show resolved Hide resolved
});
Expand All @@ -152,7 +167,6 @@ export default function BillingContainer(): JSX.Element {
}

setData(formattedUsageData);
setTotalBillAmount(total);

if (!licensesData?.payload?.onTrial) {
const remainingDays = getRemainingDays(billingPeriodEnd) - 1;
Expand All @@ -165,6 +179,9 @@ export default function BillingContainer(): JSX.Element {
setDaysRemaining(remainingDays > 0 ? remainingDays : 0);
setBillAmount(billTotal);
}

// setApiResponse(data?.payload || {});
setApiResponse(billingPageRes.data || {}); // todo - inserting mock data
},
[licensesData?.payload?.onTrial],
);
Expand Down Expand Up @@ -208,11 +225,6 @@ export default function BillingContainer(): JSX.Element {
key: 'name',
render: (text): JSX.Element => <div>{text}</div>,
},
{
title: 'Unit',
dataIndex: 'unit',
key: 'unit',
},
{
title: 'Data Ingested',
dataIndex: 'dataIngested',
Expand All @@ -230,24 +242,6 @@ export default function BillingContainer(): JSX.Element {
},
];

const renderSummary = (): JSX.Element => (
<Table.Summary.Row>
<Table.Summary.Cell index={0}>
<Typography.Title level={3} style={{ fontWeight: 500, margin: ' 0px' }}>
Total
</Typography.Title>
</Table.Summary.Cell>
<Table.Summary.Cell index={1}> &nbsp; </Table.Summary.Cell>
<Table.Summary.Cell index={2}> &nbsp;</Table.Summary.Cell>
<Table.Summary.Cell index={3}> &nbsp; </Table.Summary.Cell>
<Table.Summary.Cell index={4}>
<Typography.Title level={3} style={{ fontWeight: 500, margin: ' 0px' }}>
${totalBillAmount}
</Typography.Title>
</Table.Summary.Cell>
</Table.Summary.Row>
);

const renderTableSkeleton = (): JSX.Element => (
<Table
dataSource={dummyData}
Expand Down Expand Up @@ -336,35 +330,37 @@ export default function BillingContainer(): JSX.Element {
updateCreditCard,
]);

const BillingUsageGraphCallback = useCallback(
() => <BillingUsageGraph data={apiResponse} billAmount={billAmount} />,
[apiResponse, billAmount],
);

return (
<div className="billing-container">
<Row
justify="space-between"
align="middle"
gutter={[16, 16]}
style={{
margin: 0,
}}
<Flex vertical style={{ marginBottom: 16 }}>
<Typography.Text style={{ fontWeight: 500, fontSize: 18 }}>
Billing
</Typography.Text>
<Typography.Text color={Color.BG_VANILLA_400}>
Manage your billing information, invoices, and monitor costs.
</Typography.Text>
</Flex>

<Card
bordered={false}
style={{ minHeight: 150, marginBottom: 16 }}
className="page-info"
>
<Col span={20}>
<Typography.Title level={4} ellipsis style={{ fontWeight: '300' }}>
{headerText}
</Typography.Title>

{licensesData?.payload?.onTrial &&
licensesData?.payload?.trialConvertedToSubscription && (
<Typography.Title
level={5}
ellipsis
style={{ fontWeight: '300', color: '#49aa19' }}
>
We have received your card details, your billing will only start after
the end of your free trial period.
</Typography.Title>
)}
</Col>

<Col span={4} style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Flex justify="space-between" align="center">
<Flex vertical>
<Typography.Title level={5} style={{ marginTop: 2, fontWeight: 500 }}>
Enterprise Cloud{' '}
SagarRajput-7 marked this conversation as resolved.
Show resolved Hide resolved
{isFreeTrial ? <Tag color="success"> Free Trial </Tag> : ''}
</Typography.Title>
<Typography.Text style={{ fontSize: 12, color: Color.BG_VANILLA_400 }}>
{daysRemaining} {daysRemainingStr}
</Typography.Text>
</Flex>
<Button
type="primary"
size="middle"
Expand All @@ -375,35 +371,35 @@ export default function BillingContainer(): JSX.Element {
? 'Upgrade Plan'
: 'Manage Billing'}
</Button>
</Col>
</Row>

<div className="billing-summary">
<Typography.Title level={4} style={{ margin: '16px 0' }}>
Current bill total
</Typography.Title>

<Typography.Title
level={3}
style={{ margin: '16px 0', display: 'flex', alignItems: 'center' }}
>
{billCurrency}
{billAmount} &nbsp;
{isFreeTrial ? <Tag color="success"> Free Trial </Tag> : ''}
</Typography.Title>

<Typography.Paragraph style={{ margin: '16px 0' }}>
{daysRemaining} {daysRemainingStr}
</Typography.Paragraph>
</div>
</Flex>

{licensesData?.payload?.onTrial &&
licensesData?.payload?.trialConvertedToSubscription && (
<Typography.Text
ellipsis
style={{ fontWeight: '300', color: '#49aa19', fontSize: 12 }}
>
We have received your card details, your billing will only start after
vikrantgupta25 marked this conversation as resolved.
Show resolved Hide resolved
the end of your free trial period.
</Typography.Text>
)}
<Alert
message={headerText}
type="info"
showIcon
style={{ marginTop: 12 }}
/>
</Card>

{!isLoading ? <BillingUsageGraphCallback /> : null}

<div className="billing-details">
{!isLoading && (
<Table
columns={columns}
dataSource={data}
pagination={false}
summary={renderSummary}
bordered={false}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.billing-graph-card {
.ant-card-body {
height: 40vh;
.uplot-graph-container {
padding: 8px;
}
}
.total-spent {
font-family: 'SF Mono' monospace;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 24px;
}

.total-spent-title {
font-size: 12px;
font-weight: 500;
line-height: 22px;
letter-spacing: 0.48px;
color: rgba(255, 255, 255, 0.5);
}
}

.selectStyles {
min-width: 120px;

.ant-select-selector {
border-radius: 2px;
border: 1px solid var(--bg-slate-500) !important;
background: var(--bg-ink-300);
background-color: var(--bg-slate-500) !important;
}
}

.lightMode {
.selectStyles {
.ant-select-selector {
border: 1px solid var(--bg-vanilla-200) !important;
background-color: var(--bg-vanilla-200) !important;
}
}
.total-spent-title {
color: var(--bg-ink-100);
}
}
Loading
Loading