/* eslint-disable @typescript-eslint/no-loop-func */ import './BillingContainer.styles.scss'; import { CheckCircleOutlined } from '@ant-design/icons'; import { Button, Col, 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'; import { SOMETHING_WENT_WRONG } from 'constants/api'; import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; import useAxiosError from 'hooks/useAxiosError'; import useLicense from 'hooks/useLicense'; import { useNotifications } from 'hooks/useNotifications'; import { useCallback, useEffect, useState } from 'react'; import { useMutation, useQuery } from 'react-query'; import { useSelector } from 'react-redux'; import { AppState } from 'store/reducers'; import { License } from 'types/api/licenses/def'; import AppReducer from 'types/reducer/app'; import { getFormattedDate } from 'utils/timeUtils'; interface DataType { key: string; name: string; unit: string; dataIngested: string; pricePerUnit: string; cost: string; } const renderSkeletonInput = (): JSX.Element => ( ); const dummyData: DataType[] = [ { key: '1', name: 'Logs', unit: '', dataIngested: '', pricePerUnit: '', cost: '', }, { key: '2', name: 'Traces', unit: '', dataIngested: '', pricePerUnit: '', cost: '', }, { key: '3', name: 'Metrics', unit: '', dataIngested: '', pricePerUnit: '', cost: '', }, ]; const dummyColumns: ColumnsType = [ { title: '', dataIndex: 'name', key: 'name', render: renderSkeletonInput, }, { title: 'Unit', dataIndex: 'unit', key: 'unit', render: renderSkeletonInput, }, { title: 'Data Ingested', dataIndex: 'dataIngested', key: 'dataIngested', render: renderSkeletonInput, }, { title: 'Price per Unit', dataIndex: 'pricePerUnit', key: 'pricePerUnit', render: renderSkeletonInput, }, { title: 'Cost (Billing period to date)', dataIndex: 'cost', key: 'cost', render: renderSkeletonInput, }, ]; export const getRemainingDays = (billingEndDate: number): number => { // Convert Epoch timestamps to Date objects const startDate = new Date(); // Convert seconds to milliseconds const endDate = new Date(billingEndDate * 1000); // Convert seconds to milliseconds // Calculate the time difference in milliseconds // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const timeDifference = endDate - startDate; return Math.ceil(timeDifference / (1000 * 60 * 60 * 24)); }; 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(null); const [daysRemaining, setDaysRemaining] = useState(0); const [isFreeTrial, setIsFreeTrial] = useState(false); const [data, setData] = useState([]); const billCurrency = '$'; const { isFetching, data: licensesData, error: licenseError } = useLicense(); const { user } = useSelector((state) => state.app); const { notifications } = useNotifications(); const handleError = useAxiosError(); const processUsageData = useCallback( (data: any): void => { const { details: { breakdown = [], total, billTotal }, billingPeriodStart, billingPeriodEnd, } = data?.payload || {}; const formattedUsageData: any[] = []; if (breakdown && Array.isArray(breakdown)) { for (let index = 0; index < breakdown.length; index += 1) { const element = breakdown[index]; element?.tiers.forEach( ( tier: { quantity: number; unitPrice: number; tierCost: number }, i: number, ) => { formattedUsageData.push({ key: `${index}${i}`, name: i === 0 ? element?.type : '', unit: element?.unit, dataIngested: tier.quantity, pricePerUnit: tier.unitPrice, cost: `$ ${tier.tierCost}`, }); }, ); } } setData(formattedUsageData); setTotalBillAmount(total); if (!licensesData?.payload?.onTrial) { const remainingDays = getRemainingDays(billingPeriodEnd) - 1; setHeaderText( `Your current billing period is from ${getFormattedDate( billingPeriodStart, )} to ${getFormattedDate(billingPeriodEnd)}`, ); setDaysRemaining(remainingDays > 0 ? remainingDays : 0); setBillAmount(billTotal); } }, [licensesData?.payload?.onTrial], ); const { isLoading } = useQuery( [REACT_QUERY_KEY.GET_BILLING_USAGE, user?.userId], { queryFn: () => getUsage(activeLicense?.key || ''), onError: handleError, enabled: activeLicense !== null, onSuccess: processUsageData, }, ); useEffect(() => { const activeValidLicense = licensesData?.payload?.licenses?.find( (license) => license.isCurrent === true, ) || null; setActiveLicense(activeValidLicense); if (!isFetching && licensesData?.payload?.onTrial && !licenseError) { const remainingDays = getRemainingDays(licensesData?.payload?.trialEnd); setIsFreeTrial(true); setBillAmount(0); setDaysRemaining(remainingDays > 0 ? remainingDays : 0); setHeaderText( `You are in free trial period. Your free trial will end on ${getFormattedDate( licensesData?.payload?.trialEnd, )}`, ); } }, [isFetching, licensesData?.payload, licenseError]); const columns: ColumnsType = [ { title: '', dataIndex: 'name', key: 'name', render: (text): JSX.Element =>
{text}
, }, { title: 'Unit', dataIndex: 'unit', key: 'unit', }, { title: 'Data Ingested', dataIndex: 'dataIngested', key: 'dataIngested', }, { title: 'Price per Unit', dataIndex: 'pricePerUnit', key: 'pricePerUnit', }, { title: 'Cost (Billing period to date)', dataIndex: 'cost', key: 'cost', }, ]; const renderSummary = (): JSX.Element => ( Total       ${totalBillAmount} ); const renderTableSkeleton = (): JSX.Element => ( ( )), }} /> ); const { mutate: updateCreditCard, isLoading: isLoadingBilling } = useMutation( updateCreditCardApi, { onSuccess: (data) => { if (data.payload?.redirectURL) { const newTab = document.createElement('a'); newTab.href = data.payload.redirectURL; newTab.target = '_blank'; newTab.rel = 'noopener noreferrer'; newTab.click(); } }, onError: () => notifications.error({ message: SOMETHING_WENT_WRONG, }), }, ); const handleBilling = useCallback(async () => { updateCreditCard({ licenseKey: activeLicense?.key || '', successURL: window.location.href, cancelURL: window.location.href, }); }, [activeLicense?.key, updateCreditCard]); return (
{headerText} {licensesData?.payload?.onTrial && licensesData?.payload?.trialConvertedToSubscription && ( We have received your card details, your billing will only start after the end of your free trial period. )}
Current bill total {billCurrency} {billAmount}   {isFreeTrial ? Free Trial : ''} {daysRemaining} {daysRemainingStr}
{!isLoading && (
)} {isLoading && renderTableSkeleton()} {isFreeTrial && !licensesData?.payload?.trialConvertedToSubscription && (
Upgrade now to have uninterrupted access Your billing will start only after the trial period Check out features in paid plans   here )} ); }