AddPaymentMethodForm() — supabase Function Reference
Architecture documentation for the AddPaymentMethodForm() function in AddPaymentMethodForm.tsx from the supabase codebase.
Entity Profile
Relationship Graph
Source Code
apps/studio/components/interfaces/Billing/Payment/AddPaymentMethodForm.tsx lines 29–222
const AddPaymentMethodForm = ({ onCancel, onConfirm }: AddPaymentMethodFormProps) => {
const { data: selectedOrganization } = useSelectedOrganizationQuery()
const { data: customerProfile, isPending: customerProfileLoading } =
useOrganizationCustomerProfileQuery({
slug: selectedOrganization?.slug,
})
const [isSaving, setIsSaving] = useState(false)
const [isDefaultPaymentMethod, setIsDefaultPaymentMethod] = useState(true)
const [isPrimaryBillingAddress, setIsPrimaryBillingAddress] = useState(true)
const queryClient = useQueryClient()
const { mutateAsync: markAsDefault } = useOrganizationPaymentMethodMarkAsDefaultMutation()
const { mutateAsync: updateCustomerProfile } = useOrganizationCustomerProfileUpdateMutation()
const { mutateAsync: updateTaxId } = useOrganizationTaxIdUpdateMutation()
const { data: taxId, isPending: isCustomerTaxIdLoading } = useOrganizationTaxIdQuery({
slug: selectedOrganization?.slug,
})
const paymentRef = useRef<PaymentMethodElementRef | null>(null)
const handleSubmit = async (event: any) => {
event.preventDefault()
setIsSaving(true)
if (document !== undefined) {
// [Joshen] This is to ensure that any 3DS popup from Stripe remains clickable
document.body.classList.add('!pointer-events-auto')
}
const result = await paymentRef.current?.confirmSetup()
if (!result) {
setIsSaving(false)
} else {
if (
isDefaultPaymentMethod &&
selectedOrganization &&
typeof result.setupIntent?.payment_method === 'string'
) {
try {
await markAsDefault({
slug: selectedOrganization.slug,
paymentMethodId: result.setupIntent.payment_method,
})
await queryClient.invalidateQueries({
queryKey: organizationKeys.paymentMethods(selectedOrganization.slug),
})
queryClient.setQueriesData(
{ queryKey: organizationKeys.paymentMethods(selectedOrganization.slug) },
(prev: any) => {
if (!prev) return prev
return {
...prev,
defaultPaymentMethodId: result.setupIntent.payment_method,
data: prev.data.map((pm: any) => ({
...pm,
is_default: pm.id === result.setupIntent.payment_method,
})),
}
}
)
} catch (error) {
toast.error('Failed to set payment method as default')
}
} else {
if (selectedOrganization) {
await queryClient.invalidateQueries({
queryKey: organizationKeys.paymentMethods(selectedOrganization.slug),
})
}
}
if (isPrimaryBillingAddress) {
try {
if (
result.address &&
(!isEqual(result.address, customerProfile?.address) ||
customerProfile?.billing_name !== result.customerName)
) {
await updateCustomerProfile({
slug: selectedOrganization?.slug,
billing_name: result.customerName,
address: result.address,
})
}
if (result.taxId && !isEqual(result.taxId, taxId)) {
await updateTaxId({ taxId: result.taxId, slug: selectedOrganization?.slug })
}
} catch (error) {
toast.error('Failed to update billing address')
}
}
setIsSaving(false)
onConfirm()
}
if (document !== undefined) {
document.body.classList.remove('!pointer-events-auto')
}
}
if (customerProfileLoading || isCustomerTaxIdLoading) {
return (
<Modal.Content>
<div className="space-y-2">
<ShimmeringLoader />
<ShimmeringLoader className="w-3/4" />
<ShimmeringLoader className="w-1/2" />
<ShimmeringLoader />
<ShimmeringLoader />
<ShimmeringLoader />
</div>
</Modal.Content>
)
}
return (
<div>
<Modal.Content
className={`transition ${isSaving ? 'pointer-events-none opacity-75' : 'opacity-100'}`}
>
<NewPaymentMethodElement
readOnly={isSaving}
email={selectedOrganization?.billing_email}
currentAddress={customerProfile?.address}
customerName={customerProfile?.billing_name}
currentTaxId={taxId}
ref={paymentRef}
/>
<div className="flex items-center gap-x-2 mt-4 mb-2">
<Checkbox_Shadcn_
id="save-as-default"
checked={isDefaultPaymentMethod}
onCheckedChange={(checked) => {
if (typeof checked === 'boolean') {
setIsDefaultPaymentMethod(checked)
}
}}
/>
<Label_Shadcn_ htmlFor="save-as-default" className="text-foreground-light">
Save as default payment method
</Label_Shadcn_>
</div>
<div className="flex items-center gap-x-2 mt-4 mb-2">
<Checkbox_Shadcn_
id="is-primary-billing-address"
checked={isPrimaryBillingAddress}
onCheckedChange={(checked) => {
if (typeof checked === 'boolean') {
setIsPrimaryBillingAddress(checked)
}
}}
/>
<Label_Shadcn_ htmlFor="is-primary-billing-address" className="text-foreground-light">
Use the billing address as my organization's primary address
</Label_Shadcn_>
</div>
</Modal.Content>
<Modal.Separator />
<Modal.Content className="flex items-center space-x-2">
<Button
htmlType="button"
size="small"
type="default"
onClick={onCancel}
block
disabled={isSaving}
>
Cancel
</Button>
<Button
block
htmlType="button"
size="small"
type="primary"
loading={isSaving}
disabled={isSaving}
onClick={handleSubmit}
>
Add payment method
</Button>
</Modal.Content>
</div>
)
}
Domain
Subdomains
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free