InvoiceStatusBadge.tsx105 lines · main
| 1 | import { Badge, Tooltip, TooltipContent, TooltipTrigger } from 'ui' |
| 2 | |
| 3 | import { InvoiceStatus } from './Invoices.types' |
| 4 | import { InlineLink } from '@/components/ui/InlineLink' |
| 5 | import { DOCS_URL } from '@/lib/constants' |
| 6 | |
| 7 | interface InvoiceStatusBadgeProps { |
| 8 | status: InvoiceStatus |
| 9 | paymentAttempted: boolean |
| 10 | paymentProcessing: boolean |
| 11 | } |
| 12 | |
| 13 | const invoiceStatusMapping: Record< |
| 14 | InvoiceStatus, |
| 15 | { label: string; badgeVariant: React.ComponentProps<typeof Badge>['variant'] } |
| 16 | > = { |
| 17 | [InvoiceStatus.PAID]: { |
| 18 | label: 'Paid', |
| 19 | badgeVariant: 'success', |
| 20 | }, |
| 21 | [InvoiceStatus.VOID]: { |
| 22 | label: 'Forgiven', |
| 23 | badgeVariant: 'warning', |
| 24 | }, |
| 25 | |
| 26 | // We do not want to overcomplicate it for the user, so we'll treat uncollectible/open/issued the same from a user perspective |
| 27 | // it's an outstanding invoice |
| 28 | [InvoiceStatus.UNCOLLECTIBLE]: { |
| 29 | label: 'Outstanding', |
| 30 | badgeVariant: 'destructive', |
| 31 | }, |
| 32 | [InvoiceStatus.OPEN]: { |
| 33 | label: 'Outstanding', |
| 34 | badgeVariant: 'destructive', |
| 35 | }, |
| 36 | [InvoiceStatus.ISSUED]: { |
| 37 | label: 'Outstanding', |
| 38 | badgeVariant: 'destructive', |
| 39 | }, |
| 40 | } |
| 41 | |
| 42 | const InvoiceStatusBadge = ({ |
| 43 | status, |
| 44 | paymentAttempted, |
| 45 | paymentProcessing, |
| 46 | }: InvoiceStatusBadgeProps) => { |
| 47 | const statusMapping = paymentProcessing |
| 48 | ? { |
| 49 | label: 'Processing', |
| 50 | badgeVariant: 'warning' as React.ComponentProps<typeof Badge>['variant'], |
| 51 | } |
| 52 | : invoiceStatusMapping[status] |
| 53 | |
| 54 | return ( |
| 55 | <Tooltip> |
| 56 | <TooltipTrigger> |
| 57 | <Badge variant={statusMapping?.badgeVariant || 'default'}> |
| 58 | {statusMapping?.label || status} |
| 59 | </Badge> |
| 60 | </TooltipTrigger> |
| 61 | <TooltipContent side="bottom" className="max-w-xs [&>p]:text-center [&>div>p]:text-center"> |
| 62 | {[InvoiceStatus.OPEN, InvoiceStatus.ISSUED, InvoiceStatus.UNCOLLECTIBLE].includes(status) && |
| 63 | (paymentProcessing ? ( |
| 64 | <div className="space-y-1"> |
| 65 | <p> |
| 66 | While most credit card payments get processed instantly, some Indian card providers |
| 67 | may take up to 72 hours to process payments. We’re still waiting for your card |
| 68 | provider to process this payment. |
| 69 | </p> |
| 70 | |
| 71 | <p> |
| 72 | We recommend proactively{' '} |
| 73 | <InlineLink href={`${DOCS_URL}/guides/platform/credits#credit-top-ups`}> |
| 74 | topping up your credits |
| 75 | </InlineLink>{' '} |
| 76 | to avoid this issue in the future. |
| 77 | </p> |
| 78 | </div> |
| 79 | ) : paymentAttempted ? ( |
| 80 | <p> |
| 81 | We were not able to collect the payment. Make sure you have a valid payment method and |
| 82 | enough funds. Outstanding invoices may cause restrictions. You can manually pay the |
| 83 | invoice using the “Pay now” button. |
| 84 | </p> |
| 85 | ) : ( |
| 86 | <p> |
| 87 | The invoice will soon be charged for. Please make sure to pay in a timely manner, |
| 88 | especially if you pay via invoice instead of card. You can pay the invoice using your |
| 89 | card using the “Pay now” button. |
| 90 | </p> |
| 91 | ))} |
| 92 | |
| 93 | {status === InvoiceStatus.PAID && ( |
| 94 | <p>The invoice has been paid successfully. No further action is required on your side.</p> |
| 95 | )} |
| 96 | |
| 97 | {status === InvoiceStatus.VOID && ( |
| 98 | <p>This invoice has been forgiven. No further action is required on your side.</p> |
| 99 | )} |
| 100 | </TooltipContent> |
| 101 | </Tooltip> |
| 102 | ) |
| 103 | } |
| 104 | |
| 105 | export default InvoiceStatusBadge |