import * as Tooltip from '@radix-ui/react-tooltip' import { PermissionAction } from '@supabase/shared-types/out/constants' import Link from 'next/link' import { useEffect, useState } from 'react' import { Alert, Button, IconAlertCircle, IconLoader, IconShield, IconTool, IconUsers, Listbox, Loading, Modal, } from 'ui' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useProjectTransferMutation } from 'data/projects/project-transfer-mutation' import { useProjectTransferPreviewQuery } from 'data/projects/project-transfer-preview-query' import { useCheckPermissions, useFlag, useSelectedProject, useStore } from 'hooks' const TransferProjectButton = () => { const { ui } = useStore() const project = useSelectedProject() const projectRef = project?.ref const projectOrgId = project?.organization_id const { data: allOrganizations } = useOrganizationsQuery() const disableProjectTransfer = useFlag('disableProjectTransfer') const organizations = (allOrganizations || []).filter((it) => it.id !== projectOrgId) const [isOpen, setIsOpen] = useState(false) const [selectedOrg, setSelectedOrg] = useState() const { mutate: transferProject, error: transferError, isLoading: isTransferring, } = useProjectTransferMutation({ onSuccess: () => { ui.setNotification({ category: 'success', duration: 5000, message: `Successfully transferred project ${project?.name}.`, }) setIsOpen(false) }, }) const { data: transferPreviewData, error: transferPreviewError, isLoading: transferPreviewIsLoading, remove, } = useProjectTransferPreviewQuery( { projectRef, targetOrganizationSlug: selectedOrg }, { enabled: !isTransferring && isOpen } ) useEffect(() => { if (isOpen) { // reset state setSelectedOrg(undefined) } else { // Invalidate cache remove() } }, [isOpen]) const canTransferProject = useCheckPermissions(PermissionAction.UPDATE, 'organizations') const toggle = () => { setIsOpen(!isOpen) } async function handleTransferProject() { if (project === undefined) return if (selectedOrg === undefined) return transferProject({ projectRef, targetOrganizationSlug: selectedOrg }) } return ( <> {(!canTransferProject || disableProjectTransfer) && (
{!canTransferProject ? 'You need additional permissions to transfer this project' : 'Project transfers are temporarily disabled, please try again later.'}
)}
toggle()} visible={isOpen} loading={isTransferring} size={'xlarge'} header={`Transfer project ${project?.name}`} customFooter={
} >

To transfer projects, the owner must be a member of both the source and target organizations. For further information see our{' '} Documentation .

Transferring considerations:

  • No downtime

    There is no downtime or restrictions involved when transferring a project.

  • Permissions

    Depending on your role in the target organization, your level of permissions may change after transfer.

  • Features

    Moving your project to an organization with a smaller subscription plan may result in the loss of certain features (i.e. image transformations).

{organizations && (
{organizations.length === 0 ? (
You do not have any organizations with an organization-based subscription.
) : ( setSelectedOrg(slug)} placeholder="Select Organization" > Select Organization {organizations.map((x: any) => ( } > {x.name} ))} )}

The target organization needs to use{' '} organization-based billing . To migrate an organization to the new billing, head to your{' '} organizations billing settings .

)}
{transferPreviewData && transferPreviewData.valid && (
{transferPreviewData.source_subscription_plan !== transferPreviewData.target_subscription_plan ? (

Your project is currently on the{' '} {transferPreviewData.source_subscription_plan} plan, whereas the target organization uses the {transferPreviewData.target_subscription_plan} plan.

) : (
Your project and the target organization are both on the{' '} {transferPreviewData.source_subscription_plan} subscription plan.
)}
{transferPreviewData.credits_on_source_organization === 0 ? ( {' '} Your current organization won't be granted any prorated credits. ) : ( {' '} Your current organization will be granted{' '} ${transferPreviewData.credits_on_source_organization} {' '} in credits as proration. )} {transferPreviewData.costs_on_target_organization === 0 ? ( {' '} The target organization won't be charged any immediate upfront payment. ) : ( {' '} The target organization will be billed{' '} ${transferPreviewData.costs_on_target_organization} {' '} immediately to prorate for the remainder of the billing period. )}
)} {transferPreviewData && transferPreviewData.warnings.length > 0 && (
{transferPreviewData.warnings.map((warning) => (

{warning.message}

))}
)} {transferPreviewData && transferPreviewData.errors.length > 0 && (
{transferPreviewData.errors.map((error) => (

{error.message}

))}
{transferPreviewData.members_exceeding_free_project_limit.length > 0 && (

These members have reached their maximum limits for the number of active Free plan projects within organizations where they are an administrator or owner:

    {(transferPreviewData.members_exceeding_free_project_limit || []).map( (member, idx: number) => (
  • {member.name} (Limit: {member.limit} free projects)
  • ) )}

These members will need to either delete, pause, or upgrade one or more of their projects before you can downgrade this project.

)}
)} {transferPreviewError && !transferError && (

{transferPreviewError.message}

)} {transferError && (

{transferError.message}

)}
) } export default TransferProjectButton