mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
- Call the new `POST /platform/organizations/preview-creation` endpoint when creating an organization on a paid plan to show a tax breakdown before submission - Preview is triggered reactively when the user completes the billing address in the Stripe AddressElement (debounced, same pattern as subscription upgrades) - Displays plan price, tax line (with percentage), and total due today - hides the plan price row when there's no tax adjustment ## Test plan - [ ] Create a new org on the Free plan - no preview should appear - [ ] Create a new org on Pro/Team - fill in billing address with all fields including name - [ ] Verify tax preview appears after address is complete (1s debounce) - [ ] Verify tax line shows for taxable jurisdictions (NY Zip Code 10001), hidden for non-taxable - [ ] Verify plan price row is hidden when total equals plan price (no tax) - [ ] Change address country - verify preview updates - [ ] Add a tax ID - verify preview updates <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Pricing preview during organization signup that shows plan price differences, tax details (rate/amount or estimation failure), and “Total due today.” * Preview updates reactively based on selected plan and spend cap (PRO without spend cap treated as PAYG) and appears only for paid plans after preview initialization. * Debounced billing address and tax ID input collection for accurate previews; panel opacity reduced while fetching. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
import { keepPreviousData, useQuery } from '@tanstack/react-query'
|
|
|
|
import { organizationKeys } from './keys'
|
|
import type { CustomerAddress, CustomerTaxId } from './types'
|
|
import { handleError, post } from '@/data/fetchers'
|
|
import type { ResponseError, UseCustomQueryOptions } from '@/types'
|
|
|
|
export type OrganizationCreationPreviewVariables = {
|
|
tier?: string
|
|
address?: CustomerAddress
|
|
taxId?: CustomerTaxId
|
|
}
|
|
|
|
export type OrganizationCreationPreviewResponse = {
|
|
currency: string
|
|
plan_price: number
|
|
tax: {
|
|
currency: string
|
|
tax_amount: number
|
|
tax_rate_percentage: number
|
|
total_amount_excluding_tax: number
|
|
total_amount_including_tax: number
|
|
} | null
|
|
tax_status: 'calculated' | 'not_applicable' | 'failed'
|
|
total: number
|
|
}
|
|
|
|
export async function previewOrganizationCreation({
|
|
tier,
|
|
address,
|
|
taxId,
|
|
}: OrganizationCreationPreviewVariables) {
|
|
if (!tier) throw new Error('tier is required')
|
|
|
|
const { data, error } = await post(`/platform/organizations/preview-creation`, {
|
|
body: {
|
|
tier: tier as 'tier_pro' | 'tier_payg' | 'tier_team',
|
|
...(address && { address }),
|
|
...(taxId && { tax_id: taxId }),
|
|
},
|
|
})
|
|
|
|
if (error) handleError(error)
|
|
|
|
return data as OrganizationCreationPreviewResponse
|
|
}
|
|
|
|
export type OrganizationCreationPreviewData = Awaited<
|
|
ReturnType<typeof previewOrganizationCreation>
|
|
>
|
|
|
|
export const useOrganizationCreationPreview = <TData = OrganizationCreationPreviewData>(
|
|
{ tier, address, taxId }: OrganizationCreationPreviewVariables,
|
|
{
|
|
enabled = true,
|
|
...options
|
|
}: UseCustomQueryOptions<OrganizationCreationPreviewData, ResponseError, TData> = {}
|
|
) =>
|
|
useQuery<OrganizationCreationPreviewData, ResponseError, TData>({
|
|
queryKey: organizationKeys.creationPreview(tier, {
|
|
address: address as Record<string, unknown> | undefined,
|
|
taxId: taxId as Record<string, unknown> | undefined,
|
|
}),
|
|
queryFn: () => previewOrganizationCreation({ tier, address, taxId }),
|
|
enabled: enabled && typeof tier !== 'undefined',
|
|
placeholderData: keepPreviousData,
|
|
...options,
|
|
})
|