Files
supabase/apps/studio/components/interfaces/Settings/General/CustomDomainConfig/CustomDomainDelete.tsx
Joshen Lim 88c43b31b9 Support optionally remove custom domain addon when deleting custom domain after activated (#45880)
## Context

Related BE PR: https://github.com/supabase/platform/pull/32693

Add support to remove the custom domain add-on when deleting a custom
domain after the custom domain is activated.

<img width="411" height="310" alt="image"
src="https://github.com/user-attachments/assets/23d57fc0-f760-42d4-8383-480ff2b2ec5a"
/>

We previously had this behaviour by default to address some customer
feedback RE confusion that they were still being charged for custom
domain add-on despite deleting the custom domain, but not removing the
add-on.

However this was a bit of confusing UX (RE deleting the add-on
implicitly), so this makes the deleting of the custom domain add-on an
explicit action instead.

## To test

- [ ] Set up custom domain on a project
- [ ] Trying deleting the custom domain after activating _without_
removing the add-on
- [ ] Trying deleting the custom domain after activating _with_ removing
the add-on
2026-05-15 16:41:58 +08:00

109 lines
3.9 KiB
TypeScript

import { Trash } from 'lucide-react'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
import { Button, Checkbox } from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { DocsButton } from '@/components/ui/DocsButton'
import Panel from '@/components/ui/Panel'
import { useCustomDomainDeleteMutation } from '@/data/custom-domains/custom-domains-delete-mutation'
import type { CustomDomainResponse } from '@/data/custom-domains/custom-domains-query'
import { DOCS_URL } from '@/lib/constants'
export type CustomDomainDeleteProps = {
projectRef?: string
customDomain: CustomDomainResponse
}
export const CustomDomainDelete = ({ projectRef, customDomain }: CustomDomainDeleteProps) => {
const [removeCustomDomain, setRemoveCustomDomain] = useState(false)
const [isDeleteConfirmModalVisible, setIsDeleteConfirmModalVisible] = useState(false)
const { mutate: deleteCustomDomain, isPending: isDeletingCustomDomain } =
useCustomDomainDeleteMutation({
onSuccess: () => {
toast.success(
`Successfully deleted custom domain. Refresh your browser to see the changes.`
)
setIsDeleteConfirmModalVisible(false)
},
})
const onDeleteCustomDomain = async () => {
if (!projectRef) return console.error('Project ref is required')
deleteCustomDomain({ projectRef, removeAddon: removeCustomDomain })
}
useEffect(() => {
if (!isDeleteConfirmModalVisible) setRemoveCustomDomain(false)
}, [isDeleteConfirmModalVisible])
return (
<>
<Panel.Content>
<div className="w-full space-y-2">
<p className="text-xs text-foreground-light">Active custom domain:</p>
<div className="flex items-center space-x-2">
<code className="text-lg mx-0 flex items-center space-x-2">
<div className="h-2 w-2 rounded-full bg-brand" />
<span>
<code className="text-code-inline">{customDomain.hostname}</code>
</span>
</code>
</div>
<p className="text-sm text-foreground-light">
Your custom domain is currently active and is serving traffic
</p>
</div>
</Panel.Content>
<div className="w-full border-t border-muted" />
<Panel.Content className="w-full">
<div className="flex items-center justify-between">
<DocsButton href={`${DOCS_URL}/guides/platform/custom-domains`} />
<Button
type="danger"
icon={<Trash />}
onClick={() => setIsDeleteConfirmModalVisible(true)}
>
Delete custom domain
</Button>
</div>
</Panel.Content>
<ConfirmationModal
visible={isDeleteConfirmModalVisible}
variant="destructive"
title="Delete custom domain"
confirmLabel="Delete"
confirmLabelLoading="Deleting"
loading={isDeletingCustomDomain}
onCancel={() => setIsDeleteConfirmModalVisible(false)}
onConfirm={onDeleteCustomDomain}
>
<p className="text-sm mb-4">
Are you sure you want to delete the custom domain{' '}
<code className="text-code-inline break-normal!">{customDomain.hostname}</code> for your
project? You will need to re-verify this domain if you want to use it again.
</p>
<FormItemLayout
isReactForm={false}
layout="flex"
name="removeCustomDomain"
label="Also remove custom domain add-on"
description="Stops the monthly add-on charge for this project"
className="[&>div:first-child>button]:translate-y-0.5"
>
<Checkbox
checked={removeCustomDomain}
onCheckedChange={(value) => setRemoveCustomDomain(!!value)}
/>
</FormItemLayout>
</ConfirmationModal>
</>
)
}