"use client"; import { AnimatePresence } from "framer-motion"; import { useRouter } from "next/navigation"; import posthog from "posthog-js"; import { useEffect, useRef, useTransition } from "react"; import { isCompanyEmail } from "@calcom/features/ee/organizations/lib/utils"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import classNames from "@calcom/ui/classNames"; import { Badge } from "@calcom/ui/components/badge"; import { Button } from "@calcom/ui/components/button"; import { type IconName } from "@calcom/ui/components/icon"; import { RadioAreaGroup } from "@calcom/ui/components/radio"; import { useHasTeamMembership } from "@calcom/web/modules/billing/hooks/useHasPaidPlan"; import { OnboardingCard } from "../components/OnboardingCard"; import { OnboardingLayout } from "../components/OnboardingLayout"; import { OnboardingContinuationPrompt } from "../components/onboarding-continuation-prompt"; import { PlanIcon } from "../components/plan-icon"; import { useOnboardingStore, type PlanType } from "../store/onboarding-store"; type OnboardingViewProps = { userEmail: string; }; export const OnboardingView = ({ userEmail }: OnboardingViewProps) => { const router = useRouter(); const { t } = useLocale(); const { selectedPlan, setSelectedPlan, resetOnboardingPreservingPlan } = useOnboardingStore(); const previousPlanRef = useRef(null); const [isPending, startTransition] = useTransition(); const { hasTeamMembership, isPending: isPendingMembership } = useHasTeamMembership(); // Reset onboarding data when visiting this page, but preserve the selected plan useEffect(() => { resetOnboardingPreservingPlan(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // If user has any team membership (pending or accepted), redirect them directly to personal onboarding // This handles the case where users sign up with an invite token (membership is auto-accepted) useEffect(() => { if (!isPendingMembership && hasTeamMembership) { setSelectedPlan("personal"); startTransition(() => { router.push("/onboarding/personal/settings"); }); } }, [isPendingMembership, hasTeamMembership, router, setSelectedPlan]); // Plan order mapping for determining direction const planOrder: Record = { personal: 0, team: 1, organization: 2, }; // Calculate animation direction synchronously const getDirection = (): "up" | "down" => { if (!selectedPlan || !previousPlanRef.current) return "down"; const previousOrder = planOrder[previousPlanRef.current]; const currentOrder = planOrder[selectedPlan]; return currentOrder > previousOrder ? "up" : "down"; }; const direction = getDirection(); // Update previous plan ref after render useEffect(() => { previousPlanRef.current = selectedPlan; }, [selectedPlan]); const handleContinue = () => { if (selectedPlan) { posthog.capture("onboarding_plan_continue_clicked", { plan_type: selectedPlan, }); } startTransition(() => { if (selectedPlan === "organization") { router.push("/onboarding/organization/details"); } else if (selectedPlan === "team") { router.push("/onboarding/teams/details"); } else if (selectedPlan === "personal") { router.push("/onboarding/personal/settings"); } }); }; const planIconByType: Record = { personal: "user", team: "user", organization: "users", }; const allPlans = [ { id: "personal" as PlanType, title: t("onboarding_plan_personal_title"), badge: t("onboarding_plan_personal_badge"), description: t("onboarding_plan_personal_description"), icon: planIconByType.personal, variant: "single" as const, }, { id: "team" as PlanType, title: t("onboarding_plan_team_title"), badge: t("onboarding_plan_team_badge"), description: t("onboarding_plan_team_description"), icon: planIconByType.team, variant: "team" as const, }, { id: "organization" as PlanType, title: t("onboarding_plan_organization_title"), badge: t("onboarding_plan_organization_badge"), description: t("onboarding_plan_organization_description"), icon: planIconByType.organization, variant: "organization" as const, }, ]; // Only show organization plan for company emails const plans = allPlans.filter((plan) => { if (plan.id === "organization") { return isCompanyEmail(userEmail); } return true; }); const selectedPlanData = plans.find((plan) => plan.id === selectedPlan); // Show loading state while checking for team membership or if redirecting if (isPendingMembership || hasTeamMembership) { return ( ); } return ( <> {/* Left column - Main content */} }> {/* Card */}
{/* Plan options */} { const planType = value as PlanType; setSelectedPlan(planType); posthog.capture("onboarding_plan_selected", { plan_type: planType, }); }} className="flex w-full flex-col gap-1 rounded-[10px]"> {plans.map((plan) => { const isSelected = selectedPlan === plan.id; return ( button]:left-auto [&>button]:right-6 [&>button]:mt-0 [&>button]:transform" )} classNames={{ container: "flex w-full items-center gap-3 p-5 pr-12", }}>

{plan.title}

{plan.badge}
{plan.badge}

{plan.description}

); })}
{/* Right column - Icon display */}
{selectedPlanData && ( )}
); };