Files
supabase/apps/studio/components/interfaces/App/IndirectTaxDeclarationModal.tsx
T
Danny White 1131e3e2ce fix(ui): default Button variant to default instead of primary (#50160)
## What kind of change does this PR introduce?

Bug fix / design-system alignment for the legacy `Button` from `ui`.

## What is the current behavior?

Omitting `variant` on the legacy `Button` falls back to brand-green
`primary`. That makes accidental greens easy, and it is hard to spot the
real main action on busy pages.

## What is the new behavior?

- Legacy `Button` now defaults to neutral `default`
- Intentional primary CTAs (create, save, submit, marketing CTAs, and
matching `ButtonTooltip` usages) now set `variant="primary"` so their
appearance is unchanged
- Neutral actions that previously relied on the old fallback (cancel,
close, back, dashboard nav, and similar) become grey/white
- Design-system docs updated; regression tests cover the new default

`Button_Shadcn_` is unchanged. It already uses its own CVA default.

This is PR 1 of 2 in a stack. PR 2 drops now-redundant
`variant="default"` props.

## To test

Studio (http://localhost:8082):

- `/sign-in`: Sign in stays green
- Open a project → Database → Tables: New table stays green
- Auth → Users → Invite: Invite user stays green; Cancel / dismiss
controls stay neutral
- Project Settings → General: edit a field so Cancel and Save appear.
Cancel is neutral, Save is green

Design system (http://localhost:3003):

- Components → Button: default demo is neutral; primary demo is green;
featured preview is the default variant

Marketing (optional):

- www header: Start your project stays green; logged-in Dashboard is
neutral

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Style**
- Buttons now default to a neutral style, while primary actions across
Studio, documentation, marketing pages, forms, dialogs, and error states
use prominent primary styling.
- Updated button examples and previews clarify the distinction between
default and primary variants.
  - Event registration now includes a directional arrow icon.

- **Tests**
- Added coverage confirming default button styling and explicit primary
styling behave as expected.
- Updated related test fixtures to use primary styling where
appropriate.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-10 11:23:17 +10:00

171 lines
5.6 KiB
TypeScript

import { PermissionAction } from '@supabase/shared-types/out/constants'
import { parseAsBoolean, useQueryState } from 'nuqs'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
import {
Button,
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogSection,
DialogSectionSeparator,
DialogTitle,
RadioGroupStacked,
RadioGroupStackedItem,
} from 'ui'
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import { useOrganizationCustomerProfileUpdateMutation } from '@/data/organizations/organization-customer-profile-update-mutation'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
import { IS_PLATFORM } from '@/lib/constants'
type IndirectTaxDeclaration = 'yes' | 'no'
type DeclarationModal = 'declaration-form' | 'submission-confirmation' | null
export const IndirectTaxDeclarationModal = () => {
const { data: organization } = useSelectedOrganizationQuery({ enabled: IS_PLATFORM })
const [response, setResponse] = useState<IndirectTaxDeclaration | ''>('')
const [failedSubmissionSlug, setFailedSubmissionSlug] = useState<string>()
const [shouldShowDeclarationConfirmation, setShouldShowDeclarationConfirmation] = useQueryState(
'submit_indirect_tax_declaration',
parseAsBoolean.withDefault(false)
)
useEffect(() => {
setResponse('')
}, [organization?.slug])
const { can: canUpdateBillingInfo, isSuccess: permissionsLoaded } = useAsyncCheckPermissions(
PermissionAction.BILLING_WRITE,
'stripe.customer'
)
const { mutate: updateCustomerProfile, isPending } = useOrganizationCustomerProfileUpdateMutation(
{
onSuccess: () => {
if (!shouldShowDeclarationConfirmation) {
toast.success('GST declaration submitted')
}
},
onError: (_error, variables) => {
setFailedSubmissionSlug(variables.slug)
toast.error("We couldn't submit your GST declaration. Reload the page and try again.", {
duration: Infinity,
})
},
}
)
const canViewDeclaration =
IS_PLATFORM && organization !== undefined && permissionsLoaded && canUpdateBillingInfo
let declarationModal: DeclarationModal = null
if (canViewDeclaration) {
if (organization.requires_indirect_tax_declaration) {
if (organization.slug !== failedSubmissionSlug) {
declarationModal = 'declaration-form'
}
} else if (shouldShowDeclarationConfirmation) {
declarationModal = 'submission-confirmation'
}
}
const onSubmit = () => {
if (organization?.slug === undefined || response === '') return
updateCustomerProfile({
slug: organization.slug,
indirect_tax_registration_declaration: response,
})
}
const closeSubmissionConfirmation = () => {
setShouldShowDeclarationConfirmation(null)
}
return (
<>
<Dialog open={declarationModal === 'declaration-form'}>
<DialogContent
size="medium"
hideClose
onInteractOutside={(event) => event.preventDefault()}
onEscapeKeyDown={(event) => event.preventDefault()}
>
<DialogHeader>
<DialogTitle>Confirm your Australian GST status</DialogTitle>
<DialogDescription>
Confirm the following for your organization {organization?.name}
</DialogDescription>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection className="py-4">
<RadioGroupStacked
className="[&_p]:text-pretty"
value={response}
onValueChange={(value) => {
if (value === 'yes' || value === 'no') setResponse(value)
}}
>
<RadioGroupStackedItem
value="yes"
label="Yes, I confirm"
description="We are and were registered for GST in Australia when we acquired services from Supabase, and the services were acquired in the course or furtherance of our business."
/>
<RadioGroupStackedItem
value="no"
label="No, I do not confirm"
description="We are not or were not registered for GST in Australia when we acquired services from Supabase, or the services were acquired for a purpose unrelated to our business."
/>
</RadioGroupStacked>
</DialogSection>
<DialogFooter>
<ButtonTooltip
variant="primary"
onClick={onSubmit}
disabled={response === ''}
loading={isPending}
tooltip={{
content: {
side: 'top',
text: response === '' ? 'Select Yes or No to continue' : undefined,
},
}}
>
Submit declaration
</ButtonTooltip>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog
open={declarationModal === 'submission-confirmation'}
onOpenChange={(open) => {
if (!open) closeSubmissionConfirmation()
}}
>
<DialogContent size="small">
<DialogHeader>
<DialogTitle>GST declaration submitted</DialogTitle>
<DialogDescription>
The GST declaration for {organization?.name} has been submitted. No further action is
required.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button onClick={closeSubmissionConfirmation}>Close</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
)
}