import { zodResolver } from '@hookform/resolvers/zod' import { RadioGroupCard, RadioGroupCardItem } from '@ui/components/radio-group-card' import { cn } from '@ui/lib/utils' import { ChevronRight } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/router' import { useMemo, useState } from 'react' import { SubmitHandler, useForm } from 'react-hook-form' import { toast } from 'sonner' import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger, Form, FormField, Skeleton, } from 'ui' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { z } from 'zod' import { OrganizationCard } from '../OrganizationCard' import AwsMarketplaceAutoRenewalWarning from './AwsMarketplaceAutoRenewalWarning' import AwsMarketplaceOnboardingPlaceholder from './AwsMarketplaceOnboardingPlaceholder' import AwsMarketplaceOnboardingSuccessModal from './AwsMarketplaceOnboardingSuccessModal' import { useCloudMarketplaceOnboardingInfoQuery } from './cloud-marketplace-query' import NewAwsMarketplaceOrgModal from './NewAwsMarketplaceOrgModal' import { ScaffoldSection, ScaffoldSectionContent, ScaffoldSectionDetail, } from '@/components/layouts/Scaffold' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { useOrganizationLinkAwsMarketplaceMutation } from '@/data/organizations/organization-link-aws-marketplace-mutation' import { DOCS_URL } from '@/lib/constants' import type { Organization } from '@/types' interface AwsMarketplaceLinkExistingOrgProps { organizations?: Organization[] | undefined } const FormSchema = z.object({ orgSlug: z.string(), }) type LinkExistingOrgForm = z.infer export const AwsMarketplaceLinkExistingOrg = ({ organizations, }: AwsMarketplaceLinkExistingOrgProps) => { const router = useRouter() const { query: { buyer_id: buyerId }, } = router const { data: onboardingInfo, isPending: isLoadingOnboardingInfo } = useCloudMarketplaceOnboardingInfoQuery({ buyerId: buyerId as string, }) const form = useForm({ resolver: zodResolver(FormSchema as any), defaultValues: { orgSlug: undefined, }, mode: 'onBlur', reValidateMode: 'onChange', }) const isDirty = !!Object.keys(form.formState.dirtyFields).length // Sort organizations by name ascending const sortedOrganizations = useMemo(() => { return organizations?.slice().sort((a, b) => a.name.localeCompare(b.name)) }, [organizations]) const { orgsLinkable, orgsNotLinkable } = useMemo(() => { const orgQualifiesForLinking = (org: Organization) => { const validationResult = onboardingInfo?.organization_linking_eligibility.find( (result) => result.slug === org.slug ) return validationResult?.is_eligible ?? false } const linkable: Organization[] = [] const notLinkable: Organization[] = [] sortedOrganizations?.forEach((org) => { if (orgQualifiesForLinking(org)) { linkable.push(org) } else { notLinkable.push(org) } }) return { orgsLinkable: linkable, orgsNotLinkable: notLinkable } }, [sortedOrganizations, onboardingInfo?.organization_linking_eligibility]) const [isNotLinkableOrgListOpen, setIsNotLinkableOrgListOpen] = useState(false) const [orgLinkedSuccessfully, setOrgLinkedSuccessfully] = useState(false) const [showOrgCreationDialog, setShowOrgCreationDialog] = useState(false) const [orgToRedirectTo, setOrgToRedirectTo] = useState('') const { mutate: linkOrganization, isPending: isLinkingOrganization } = useOrganizationLinkAwsMarketplaceMutation({ onSuccess: (_) => { //TODO(thomas): send tracking event? setOrgLinkedSuccessfully(true) setOrgToRedirectTo(form.getValues('orgSlug')) }, onError: (res) => { toast.error(res.message, { duration: 7_000, }) }, }) const onSubmit: SubmitHandler = async (values) => { linkOrganization({ slug: values.orgSlug, buyerId: buyerId as string }) } return ( <> {onboardingInfo && !onboardingInfo.aws_contract_auto_renewal && !onboardingInfo.aws_contract_is_private_offer && ( )} {isLoadingOnboardingInfo ? ( ) : ( <>

You’ve subscribed to the Briven{' '} {onboardingInfo?.plan_name_selected_on_marketplace} Plan via the AWS Marketplace. As a final step, you need to link a Briven organization to that subscription. Select the organization you want to be managed and billed through AWS.

You can read more on billing through AWS in our {''} Billing Docs.

Want to start fresh? Create a new organization and it will be linked automatically.

( { form.setValue('orgSlug', value, { shouldDirty: true, shouldValidate: false, }) }} >
{isLoadingOnboardingInfo ? ( Array(3) .fill(0) .map((_, i) => ( )) ) : ( <>

Organizations that can be linked

{orgsLinkable.length === 0 ? (

None of your organizations can be linked to your AWS Marketplace subscription at the moment.

) : ( orgsLinkable.map((org) => ( } /> )) )} )}
)} /> {orgsNotLinkable.length > 0 && !isLoadingOnboardingInfo && ( setIsNotLinkableOrgListOpen((prev) => !prev)} >

Organizations that can't be linked

The following organizations can’t be linked to your AWS Marketplace subscription at the moment. This may be due to missing permissions, outstanding invoices, or an existing marketplace link. If you'd like to link one of these organizations, please review the organization settings. You need to be Owner or Administrator of the organization to link it.

{orgsNotLinkable.map((org) => ( ))}
)}
{ await onSubmit(form.getValues()) }} loading={isLinkingOrganization} disabled={!isDirty || isLinkingOrganization || isLoadingOnboardingInfo} tooltip={{ content: { side: 'top', text: !isDirty ? 'No organization selected' : undefined, }, }} > Link organization
)} { setOrgLinkedSuccessfully(false) router.push(`/org/${orgToRedirectTo}`) }} /> setShowOrgCreationDialog(false)} buyerId={buyerId as string} onSuccess={(newlyCreatedOrgSlug) => { setShowOrgCreationDialog(false) setOrgToRedirectTo(newlyCreatedOrgSlug) setOrgLinkedSuccessfully(true) }} /> ) }