import { PermissionAction } from '@supabase/shared-types/out/constants' import clsx from 'clsx' import Link from 'next/link' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { useParams } from 'common' import { useProjectAddonRemoveMutation } from 'data/subscriptions/project-addon-remove-mutation' import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation' import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query' import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks' import Telemetry from 'lib/telemetry' import { useSubscriptionPageStateSnapshot } from 'state/subscription-page' import { Alert, AlertDescription_Shadcn_, Alert_Shadcn_, Button, IconAlertTriangle, IconExternalLink, Radio, SidePanel, } from 'ui' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' const CustomDomainSidePanel = () => { const { ui } = useStore() const router = useRouter() const { ref: projectRef } = useParams() const organization = useSelectedOrganization() const [selectedOption, setSelectedOption] = useState('cd_none') const canUpdateCustomDomain = useCheckPermissions( PermissionAction.BILLING_WRITE, 'stripe.subscriptions' ) const snap = useSubscriptionPageStateSnapshot() const visible = snap.panelKey === 'customDomain' const onClose = () => snap.setPanelKey(undefined) const { data: addons, isLoading } = useProjectAddonsQuery({ projectRef }) const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug }) const { mutate: updateAddon, isLoading: isUpdating } = useProjectAddonUpdateMutation({ onSuccess: () => { ui.setNotification({ category: 'success', message: `Successfully enabled custom domain`, }) onClose() }, onError: (error) => { ui.setNotification({ error, category: 'error', message: `Unable to enable custom domain: ${error.message}`, }) }, }) const { mutate: removeAddon, isLoading: isRemoving } = useProjectAddonRemoveMutation({ onSuccess: () => { ui.setNotification({ category: 'success', message: `Successfully disabled custom domain`, }) onClose() }, onError: (error) => { ui.setNotification({ error, category: 'error', message: `Unable to disable custom domain: ${error.message}`, }) }, }) const isSubmitting = isUpdating || isRemoving const subscriptionCDOption = (addons?.selected_addons ?? []).find( (addon) => addon.type === 'custom_domain' ) const availableOptions = (addons?.available_addons ?? []).find((addon) => addon.type === 'custom_domain')?.variants ?? [] const isFreePlan = subscription?.plan?.id === 'free' const hasChanges = selectedOption !== (subscriptionCDOption?.variant.identifier ?? 'cd_none') const selectedCustomDomain = availableOptions.find( (option) => option.identifier === selectedOption ) useEffect(() => { if (visible) { if (subscriptionCDOption !== undefined) { setSelectedOption(subscriptionCDOption.variant.identifier) } else { setSelectedOption('cd_none') } Telemetry.sendActivity( { activity: 'Side Panel Viewed', source: 'Dashboard', data: { title: 'Custom domains', section: 'Add ons', }, projectRef, }, router ) } }, [visible, isLoading]) const onConfirm = async () => { if (!projectRef) return console.error('Project ref is required') if (selectedOption === 'cd_none' && subscriptionCDOption !== undefined) { removeAddon({ projectRef, variant: subscriptionCDOption.variant.identifier }) } else { updateAddon({ projectRef, type: 'custom_domain', variant: selectedOption }) } } return (

Custom domains

} >

Custom domains allow you to present a branded experience to your users. You may set up your custom domain in the{' '} General Settings {' '} page after enabling the add-on.

{ setSelectedOption(event.target.value) Telemetry.sendActivity( { activity: 'Option Selected', source: 'Dashboard', data: { title: 'Custom domains', section: 'Add ons', option: event.target.label, }, projectRef, }, router ) }} >

No custom domain

Use the default supabase domain for your API

$0

/ month

{availableOptions.map((option) => (

{option.name}

Present a branded experience to your users

${option.price}

/ month

))}
{hasChanges && ( <> {selectedOption === 'cd_none' || (selectedCustomDomain?.price ?? 0) < (subscriptionCDOption?.variant.price ?? 0) ? (

Upon clicking confirm, the amount of that's unused during the current billing cycle will be returned as credits that can be used for subsequent billing cycles

) : (

Upon clicking confirm, the amount of{' '} ${selectedCustomDomain?.price.toLocaleString()} {' '} will be added to your monthly invoice. You're immediately charged for the remaining days of your billing cycle. The addon is prepaid per month and in case of a downgrade, you get credits for the remaining time.

)} {subscription?.billing_via_partner && subscription.scheduled_plan_change?.target_plan !== undefined && ( You have a scheduled subscription change that will be canceled if you change your custom domain add on. )} )} {isFreePlan && ( View available plans } > Upgrade your plan to add a custom domain to your project )}
) } export default CustomDomainSidePanel