Files
Danny White 476d4a5851 refactor(ui): drop redundant Button variant="default" props (#50161)
## What kind of change does this PR introduce?

Mechanical cleanup on top of the Button default-variant change (#50160).

## What is the current behavior?

Many callsites still pass `variant="default"` even though that is now
the component default.

## What is the new behavior?

Removes redundant static `variant="default"` from legacy `Button` and
`ButtonTooltip` callsites. Keeps explicit defaults where they document
the API:

- `button-default.tsx` and `button-sizes.tsx` demos
- `DocsButton`, which pins neutral styling at the wrapper boundary

## To test

Studio:

- [Auth → Rate
Limits](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/auth/rate-limits):
dirty the form so Cancel appears; Cancel stays neutral, Save stays green
- [Project Settings → API
Keys](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/settings/api-keys):
`DocsButton` in the header actions stays neutral

Design system:

- [Design system →
Button](https://design-system-git-dnywh-dc924ac1-supabase.vercel.app/design-system/docs/components/button):
`button-default` / `button-sizes` still show explicit default styling;
Primary (green) is restricted to the Primary section (and `asChild`)

WWW:

- [www → Brand
assets](https://zone-www-dot-com-git-dnywh-dc924ac1-supabase.vercel.app/brand-assets):
Download logo kit / Download button kit stay neutral
2026-09-11 17:05:26 +10:00

139 lines
5.2 KiB
TypeScript

import { useParams } from 'common'
import { useRouter } from 'next/router'
import { useState } from 'react'
import { toast } from 'sonner'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { hasMultipleOwners } from './TeamSettings.utils'
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import { useOrganizationRolesV2Query } from '@/data/organization-members/organization-roles-query'
import { useOrganizationMemberDeleteMutation } from '@/data/organizations/organization-member-delete-mutation'
import { useOrganizationMembersQuery } from '@/data/organizations/organization-members-query'
import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
import { useProfile } from '@/lib/profile'
export const LeaveTeamButton = () => {
const router = useRouter()
const { slug } = useParams()
const { profile } = useProfile()
const { data: selectedOrganization } = useSelectedOrganizationQuery()
const { setLastVisitedOrganization } = useLastVisitedOrganization()
// if organizationMembersDeletionEnabled is false, you also can't delete yourself
const { organizationMembersDelete: organizationMembersDeletionEnabled } = useIsFeatureEnabled([
'organization_members:delete',
])
const [isLeaving, setIsLeaving] = useState(false)
const [isLeaveTeamModalOpen, setIsLeaveTeamModalOpen] = useState(false)
const { refetch: refetchOrganizations } = useOrganizationsQuery()
const { data: members } = useOrganizationMembersQuery({ slug })
const { data: allRoles } = useOrganizationRolesV2Query({ slug })
const roles = allRoles?.org_scoped_roles ?? []
const currentUserMember = members?.find((member) => member.gotrue_id === profile?.gotrue_id)
const currentUserRoleId = currentUserMember?.role_ids?.[0]
const currentUserRole = roles.find((role) => role.id === currentUserRoleId)
const isAdmin = currentUserRole?.name === 'Administrator'
const isOwner = selectedOrganization?.is_owner
const canLeave = !isOwner || (isOwner && hasMultipleOwners(members, roles))
const { mutate: deleteMember } = useOrganizationMemberDeleteMutation({
onSuccess: async () => {
setIsLeaving(false)
setIsLeaveTeamModalOpen(false)
await refetchOrganizations()
toast.success(`Successfully left ${selectedOrganization?.name}`)
setLastVisitedOrganization('')
router.push('/organizations')
},
onError: (error) => {
setIsLeaving(false)
toast.error(`Failed to leave organization: ${error?.message}`)
},
})
const leaveTeam = async () => {
if (!slug) return console.error('Org slug is required')
if (!profile) return console.error('Profile is required')
setIsLeaving(true)
deleteMember({ slug, gotrueId: profile.gotrue_id })
}
return (
<>
<ButtonTooltip
disabled={!canLeave || !organizationMembersDeletionEnabled || isLeaving}
onClick={() => setIsLeaveTeamModalOpen(true)}
tooltip={{
content: {
side: 'bottom',
text: !canLeave
? 'An organization requires at least 1 owner'
: !organizationMembersDeletionEnabled
? 'Unable to leave organization'
: undefined,
},
}}
>
Leave team
</ButtonTooltip>
<ConfirmationModal
size="medium"
visible={isLeaveTeamModalOpen}
title="Confirm to leave organization"
confirmLabel="Leave"
variant="warning"
alert={{
title: 'All of your user content will be permanently removed.',
description: (
<div>
<p>
Leaving the organization will delete all of your saved content in the projects of
the organization, which includes:
</p>
<ul className="list-disc pl-4">
<li>
SQL snippets <span className="text-foreground">(both private and shared)</span>
</li>
<li>Custom reports</li>
<li>Log Explorer queries</li>
</ul>
{(isOwner || isAdmin) && (
<div className="mt-2">
<p>
<span className="text-foreground">
Leaving won't remove your payment method or stop payments.
</span>
</p>
<ul className="list-disc pl-4">
<li>
The current payment method will remain active and may still be charged after
you leave.
</li>
<li>The billing address will remain unchanged.</li>
</ul>
</div>
)}
</div>
),
}}
onCancel={() => setIsLeaveTeamModalOpen(false)}
onConfirm={() => leaveTeam()}
>
<p className="text-sm text-foreground-light">
Are you sure you want to leave this organization? This is permanent.
</p>
</ConfirmationModal>
</>
)
}