import type { SessionContextValue } from "next-auth/react"; import { signIn, useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; import { useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { subdomainSuffix } from "@calcom/features/ee/organizations/lib/orgDomains"; import classNames from "@calcom/lib/classNames"; import { MINIMUM_NUMBER_OF_ORG_SEATS } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import slugify from "@calcom/lib/slugify"; import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; import { UserPermissionRole } from "@calcom/prisma/enums"; import { trpc } from "@calcom/trpc/react"; import type { Ensure } from "@calcom/types/utils"; import { Alert, Button, Form, Label, RadioGroup as RadioArea, TextField, ToggleGroup } from "@calcom/ui"; function extractDomainFromEmail(email: string) { let out = ""; try { const match = email.match(/^(?:.*?:\/\/)?.*?(?[\w\-]*(?:\.\w{2,}|\.\w{2,}\.\w{2}))(?:[\/?#:]|$)/); out = (match && match.groups?.root) ?? ""; } catch (ignore) {} return out.split(".")[0]; } export const CreateANewOrganizationForm = () => { const session = useSession(); if (!session.data) { return null; } return ; }; enum BillingPeriod { MONTHLY = "MONTHLY", ANNUALLY = "ANNUALLY", } const CreateANewOrganizationFormChild = ({ session, }: { session: Ensure; isPlatformOrg?: boolean; }) => { const { t } = useLocale(); const router = useRouter(); const telemetry = useTelemetry(); const [serverErrorMessage, setServerErrorMessage] = useState(null); const isAdmin = session.data.user.role === UserPermissionRole.ADMIN; const defaultOrgOwnerEmail = session.data.user.email ?? ""; const newOrganizationFormMethods = useForm<{ name: string; seats: number; billingPeriod: BillingPeriod; pricePerSeat: number; slug: string; orgOwnerEmail: string; }>({ defaultValues: { billingPeriod: BillingPeriod.MONTHLY, slug: !isAdmin ? deriveSlugFromEmail(defaultOrgOwnerEmail) : undefined, orgOwnerEmail: !isAdmin ? defaultOrgOwnerEmail : undefined, name: !isAdmin ? deriveOrgNameFromEmail(defaultOrgOwnerEmail) : undefined, }, }); const createOrganizationMutation = trpc.viewer.organizations.create.useMutation({ onSuccess: async (data) => { telemetry.event(telemetryEventTypes.org_created); // This is necessary so that server token has the updated upId await session.update({ upId: data.upId, }); if (isAdmin && data.userId !== session.data?.user.id) { // Impersonate the user chosen as the organization owner(if the admin user isn't the owner himself), so that admin can now configure the organisation on his behalf. // He won't need to have access to the org directly in this way. signIn("impersonation-auth", { username: data.email, callbackUrl: `/settings/organizations/${data.organizationId}/about`, }); } router.push(`/settings/organizations/${data.organizationId}/about`); }, onError: (err) => { if (err.message === "organization_url_taken") { newOrganizationFormMethods.setError("slug", { type: "custom", message: t("url_taken") }); } else if (err.message === "domain_taken_team" || err.message === "domain_taken_project") { newOrganizationFormMethods.setError("slug", { type: "custom", message: t("problem_registering_domain"), }); } else { setServerErrorMessage(err.message); } }, }); return ( <>
{ if (!createOrganizationMutation.isPending) { setServerErrorMessage(null); createOrganizationMutation.mutate(v); } }}>
{serverErrorMessage && (
)} {isAdmin && (
( <> { if ([BillingPeriod.ANNUALLY, BillingPeriod.MONTHLY].includes(e)) { onChange(e); } }} options={[ { value: "MONTHLY", label: "Monthly", }, { value: "ANNUALLY", label: "Annually", }, ]} /> )} />
)} (
{ const email = e?.target.value; const slug = deriveSlugFromEmail(email); newOrganizationFormMethods.setValue("orgOwnerEmail", email.trim()); if (newOrganizationFormMethods.getValues("slug") === "") { newOrganizationFormMethods.setValue("slug", slug); } newOrganizationFormMethods.setValue("name", deriveOrgNameFromEmail(email)); }} autoComplete="off" />
)} />
( <> { newOrganizationFormMethods.setValue("name", e?.target.value.trim()); if (newOrganizationFormMethods.formState.touchedFields["slug"] === undefined) { newOrganizationFormMethods.setValue("slug", slugify(e?.target.value)); } }} autoComplete="off" /> )} />
( { newOrganizationFormMethods.setValue("slug", slugify(e?.target.value), { shouldTouch: true, }); newOrganizationFormMethods.clearErrors("slug"); }} /> )} />
{isAdmin && ( <>
(
{ onChange(+e.target.value); }} autoComplete="off" />
)} />
(
{ onChange(+e.target.value); }} autoComplete="off" />
)} />
)} {/* This radio group does nothing - its just for visuall purposes */} {!isAdmin && ( <>

Upgrade to Organizations

{t("teams")}

{t("your_current_plan")}

{t("organization")}

{t("organization_price_per_user_month")}

)}
); }; export function deriveSlugFromEmail(email: string) { const domain = extractDomainFromEmail(email); return domain; } export function deriveOrgNameFromEmail(email: string) { const domain = extractDomainFromEmail(email); return domain.charAt(0).toUpperCase() + domain.slice(1); }