mirror of
https://github.com/supabase/supabase.git
synced 2026-10-13 05:09:12 +03:00
### Summary This PR adds a dismissable modal that prompts paid org users to fill in their billing address. We need billing addresses for tax compliance and the existing banner hasn't been as effective (~10k orgs still missing). The modal shows on page load when all of these are true: - ConfigCat flag `enableBillingAddressModal` is on - Org is on a paid plan (not free) - Org does not have billing address set - Org is not partner-managed - User has BILLING_WRITE permission on stripe.customer The modal can be dismissed via the close button, but re-opens on every page navigation. Once the user saves a valid address, the organizations query is invalidated and organization_missing_address flips to false - the modal stops appearing permanently. <img width="1256" height="703" alt="Screenshot 2026-03-05 at 4 22 11 PM" src="https://github.com/user-attachments/assets/57e7d1b8-b3b6-4366-ad23-60910a0defe8" /> ### Testing #### Automated Tests I've added unit tests in this PR #### Manual testing Manual test cases: - Free org - modal does not appear - Partner-managed org - modal does not appear - User with "developer role" modal does not appear - Configcat Flag disabled - modal does not appear - Dismiss modal, navigate to another page - modal re-opens - Fill form and save - modal closes and does not reappear - API failure loading billing data - shows error state with Retry button --------- Co-authored-by: Ignacio Dobronich <ignacio@dobronich.com>
52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import { type ReactNode } from 'react'
|
|
|
|
import { InlineLink } from 'components/ui/InlineLink'
|
|
|
|
export const RESTRICTION_MESSAGES = {
|
|
GRACE_PERIOD: {
|
|
title: 'Organization plan has exceeded its quota',
|
|
description: (date: string, slug: string): ReactNode => (
|
|
<>
|
|
You have been given a grace period until {date}.{' '}
|
|
<InlineLink href={`/org/${slug}/usage`}>Review usage</InlineLink>
|
|
</>
|
|
),
|
|
},
|
|
GRACE_PERIOD_OVER: {
|
|
title: 'Grace period is over',
|
|
description: (slug: string): ReactNode => (
|
|
<>
|
|
Your projects will not be able to serve requests when you use up your quota.{' '}
|
|
<InlineLink href={`/org/${slug}/billing`}>Review billing</InlineLink>
|
|
</>
|
|
),
|
|
},
|
|
RESTRICTED: {
|
|
title: 'Services restricted',
|
|
description: (slug: string): ReactNode => (
|
|
<>
|
|
Your projects are unable to serve requests as your organization has used up its quota.{' '}
|
|
<InlineLink href={`/org/${slug}/billing`}>Resolve billing issues</InlineLink>
|
|
</>
|
|
),
|
|
},
|
|
OVERDUE_INVOICES: {
|
|
title: 'Outstanding invoices',
|
|
description: (slug: string): ReactNode => (
|
|
<>
|
|
Please <InlineLink href={`/org/${slug}/billing#invoices`}>pay your invoices</InlineLink> to
|
|
avoid service disruption
|
|
</>
|
|
),
|
|
},
|
|
OVERDUE_INVOICES_FROM_OTHER_ORGS: {
|
|
title: 'Outstanding invoices in other organization',
|
|
description: (slug: string): ReactNode => (
|
|
<>
|
|
Please <InlineLink href={`/org/${slug}/billing#invoices`}>pay invoices</InlineLink> for
|
|
other organizations to avoid service disruption
|
|
</>
|
|
),
|
|
},
|
|
}
|