import { AddressElement } from '@stripe/react-stripe-js' import type { StripeAddressElement, StripeAddressElementChangeEvent, StripeAddressElementOptions, } from '@stripe/stripe-js' import { Check, ChevronsUpDown, Info, X } from 'lucide-react' import { useEffect, useId, useMemo, useRef, useState } from 'react' import { UseFormReturn } from 'react-hook-form' import { Button, cn, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, FormControl, FormField, FormMessage, Input, Popover, PopoverContent, PopoverTrigger, Tooltip, TooltipContent, TooltipTrigger, } from 'ui' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { z } from 'zod' import { TAX_IDS } from './TaxID.constants' interface BillingCustomerDataFormProps { form: UseFormReturn disabled?: boolean className?: string addressOptions: StripeAddressElementOptions resetKey: number onAddressChange: (evt: StripeAddressElementChangeEvent) => void onAddressReady?: (element: StripeAddressElement) => void addressCountry?: string } export const TaxIdSchema = z.object({ tax_id_type: z.string(), tax_id_value: z.string(), tax_id_name: z.string(), }) export type TaxIdFormValues = z.infer export const BillingCustomerDataForm = ({ form, disabled = false, className, addressOptions, resetKey, onAddressChange, onAddressReady, addressCountry, }: BillingCustomerDataFormProps) => { const [showTaxIDsPopover, setShowTaxIDsPopover] = useState(false) const taxIdListboxId = useId() const onSelectTaxIdType = (name: string) => { const selectedTaxIdOption = TAX_IDS.find((option) => option.name === name) if (!selectedTaxIdOption) return form.setValue('tax_id_type', selectedTaxIdOption.type, { shouldDirty: true }) form.setValue('tax_id_value', '', { shouldDirty: true }) form.setValue('tax_id_name', name, { shouldDirty: true }) } const onRemoveTaxId = () => { form.setValue('tax_id_name', '', { shouldDirty: true }) form.setValue('tax_id_type', '', { shouldDirty: true }) form.setValue('tax_id_value', '', { shouldDirty: true }) } const { tax_id_name } = form.watch() const selectedTaxId = TAX_IDS.find((option) => option.name === tax_id_name) const availableTaxIds = useMemo(() => { return TAX_IDS.filter((taxId) => !addressCountry || taxId.countryIso2 === addressCountry).sort( (a, b) => a.country.localeCompare(b.country) ) }, [addressCountry]) // Clear tax ID fields when the billing country changes so a stale tax ID // from the previous country doesn't persist under the new one. const prevCountryRef = useRef(addressCountry) useEffect(() => { if (!addressCountry) return const isCountryChange = prevCountryRef.current !== undefined && prevCountryRef.current !== addressCountry prevCountryRef.current = addressCountry if (isCountryChange) { form.setValue('tax_id_type', '', { shouldDirty: true }) form.setValue('tax_id_value', '', { shouldDirty: true }) form.setValue('tax_id_name', '', { shouldDirty: true }) } }, [addressCountry, form]) return (
{disabled &&
}
( If you are an individual, no need to add a Tax ID. If you are a business below your country's income threshold and don't have a Tax ID, you can leave this blank. Taxes will be added to your invoice according to your country's tax laws in the near future. } > No tax ID found. {availableTaxIds.map((option) => ( { onSelectTaxIdType(option.name) setShowTaxIDsPopover(false) }} > {option.country} - {option.name} ))} )} /> {selectedTaxId && (
( )} />
)}
) }