Files
Joshen Lim 90d3b56db0 Joshen/fe 2621 show custom domain on dashboard and connect modal (#43233)
## Context

Main fix is to adjust the new home page + connect dialog (and connect
sheet) to render the project's custom domain if available

<img width="471" height="255" alt="image"
src="https://github.com/user-attachments/assets/3a208b2e-bdeb-43f5-a2e7-3495881dbaaa"
/>
<img width="1065" height="233" alt="image"
src="https://github.com/user-attachments/assets/2a7b8f81-8c0b-4803-bf0a-fc16a2f1e0e1"
/>

## Changes involved

- Created a `useProjectApiUrl` hook that will return the API URL
depending if custom domains is available, otherwise default to default
project API URL
- Refactored all the other places that were manually deriving the
project's endpoint
  - Storage Explorer -> copy URL
  - Edge Functions
  - Integrations -> Data API + API Docs
  - Auth Providers -> Callback URL
- Also updated the copy CTA for the addons page
  - Instead of just "Change xxx", make it a bit more actionable
  - For add ons with binary states (Custom domains, IPv4)
    - If not enabled yet, "Enable xxx", otherwise "Toggle xxx"
  - For PITR
- If not enabled yet, "Enable PITR", otherwise "Change recovery
duration"
  - Also added "Edit custom domain" CTA if enabled
<img width="1144" height="518" alt="image"
src="https://github.com/user-attachments/assets/4f152ea5-0cc7-412c-95e8-ad5bb37c19c3"
/>


## To test
- [ ] Verify that for a project with custom domain set up, all the
affected UI mentioned in the above section look correct
2026-03-03 11:37:08 +08:00

136 lines
5.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { DocsButton } from 'components/ui/DocsButton'
import Panel from 'components/ui/Panel'
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
import { useCheckCNAMERecordMutation } from 'data/custom-domains/check-cname-mutation'
import { useCustomDomainActivateMutation } from 'data/custom-domains/custom-domains-activate-mutation'
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'
import { useState } from 'react'
import { toast } from 'sonner'
import { Button } from 'ui'
import { Admonition } from 'ui-patterns/admonition'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
export type CustomDomainActivateProps = {
projectRef?: string
customDomain: CustomDomainResponse
}
export const CustomDomainActivate = ({ projectRef, customDomain }: CustomDomainActivateProps) => {
const [isActivateConfirmModalVisible, setIsActivateConfirmModalVisible] = useState(false)
const { data: settings } = useProjectSettingsV2Query({ projectRef })
const { mutate: checkCNAMERecord, isPending: isCheckingRecord } = useCheckCNAMERecordMutation()
const { mutate: activateCustomDomain, isPending: isActivating } = useCustomDomainActivateMutation(
{
onSuccess: () => {
toast.success(`Successfully activated custom domain`)
setIsActivateConfirmModalVisible(false)
},
}
)
const { mutate: deleteCustomDomain, isPending: isDeleting } = useCustomDomainDeleteMutation({
onSuccess: () => {
toast.success(
'Custom domain setup cancelled successfully. It may take a few seconds before your custom domain is fully removed, so you may need to refresh your browser.'
)
},
})
const endpoint = settings?.app_config?.endpoint
const onActivateCustomDomain = async () => {
if (!projectRef) return console.error('Project ref is required')
checkCNAMERecord(
{ domain: customDomain.hostname },
{ onSuccess: () => activateCustomDomain({ projectRef }) }
)
}
const onCancelCustomDomain = async () => {
if (!projectRef) return console.error('Project ref is required')
deleteCustomDomain({ projectRef })
}
return (
<>
<div className="flex flex-col items-start">
<Panel.Content>
<div className="flex flex-col gap-2">
<h4 className="text-foreground">Enable your custom domain</h4>
<p className="text-sm text-foreground-light">
Set up is almost complete. Press “Activate” below to enable{' '}
<code className="text-code-inline">{customDomain.hostname}</code> for this project.
</p>
<p className="text-sm text-foreground-light">
We recommend that you schedule a downtime window of 20 - 30 minutes for your
application, as you will need to update any services that need to know about your
custom domain (e.g client side code or OAuth providers).
</p>
</div>
<div className="mt-4">
<Admonition
type="note"
title="Retain your CNAME record for service continuity after activation"
>
<p>
Your custom domain CNAME record for{' '}
<code className="text-code-inline">{customDomain.hostname}</code> should resolve to{' '}
{endpoint ? (
<code className="text-code-inline">{endpoint}</code>
) : (
"your project's API URL"
)}
. If you're using Cloudflare as your DNS provider, disable the proxy option.
</p>
</Admonition>
</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`} />
<div className="flex items-center space-x-2">
<Button
type="default"
className="self-end"
onClick={onCancelCustomDomain}
loading={isDeleting}
>
Cancel
</Button>
<Button
disabled={isDeleting}
onClick={() => setIsActivateConfirmModalVisible(true)}
className="self-end"
>
Activate
</Button>
</div>
</div>
</Panel.Content>
</div>
<ConfirmationModal
size="small"
loading={isCheckingRecord || isActivating}
visible={isActivateConfirmModalVisible}
title="Activate custom domain"
confirmLabel="Activate"
confirmLabelLoading="Activating"
onCancel={() => setIsActivateConfirmModalVisible(false)}
onConfirm={onActivateCustomDomain}
>
<p className="text-sm">
Activating <code className="text-code-inline !break-normal">{customDomain.hostname}</code>{' '}
will make it visible to users in place of your project’s Supabase domain. The Supabase
domain will continue to work too.
</p>
</ConfirmationModal>
</>
)
}