MCPcopy Create free account
hub / github.com/sourcebot-dev/sourcebot / TrialStep

Function TrialStep

packages/web/src/app/onboard/components/trialStep.tsx:74–271  ·  view source on GitHub ↗
({ stepIndex }: TrialStepProps)

Source from the content-addressed store, hash-verified

72}
73
74export function TrialStep({ stepIndex }: TrialStepProps) {
75 const { data: offers, isPending, isError } = useOffers({
76 // we have a escape hatch on error, so don't retry.
77 retry: 0
78 });
79 const { toast } = useToast();
80 const router = useRouter();
81 const searchParams = useSearchParams();
82 const captureEvent = useCaptureEvent();
83 const [billingInterval, setBillingInterval] = useState<BillingInterval>("year");
84 const [isPrimaryLoading, setIsPrimaryLoading] = useState(false);
85 const [isSkipLoading, setIsSkipLoading] = useState(false);
86 const { data: session } = useSession();
87 const sessionEmail = session?.user?.email ?? "";
88 const [currentEmail, setCurrentEmail] = useState<string>("");
89
90 // Only treat the email as an override when the user has actually changed it
91 // away from the canonical session email.
92 const overrideEmail =
93 sessionEmail && currentEmail && currentEmail !== sessionEmail
94 ? currentEmail
95 : undefined;
96
97 const [isReturningFromCheckoutSuccess, setIsReturningFromCheckoutSuccess] = useState(searchParams.get('checkout') === 'success');
98
99 // Fire-once when offers resolve, so isTrialEligible is reliable and react-query
100 // refetches don't cause duplicate views.
101 const hasCapturedViewRef = useRef(false);
102 useEffect(() => {
103 if (isReturningFromCheckoutSuccess) {
104 return;
105 }
106 if (offers && !hasCapturedViewRef.current) {
107 hasCapturedViewRef.current = true;
108 captureEvent('wa_onboard_trial_step_viewed', {
109 isTrialEligible: offers.trial.eligible,
110 });
111 }
112 }, [offers, captureEvent, isReturningFromCheckoutSuccess]);
113
114 // Post-checkout: complete onboarding, then forward `session_id` to `/` so
115 // CheckoutReturnHandler (mounted in the (app) layout) can fire the activation
116 // dialog. We defer completeOnboarding until after Stripe actually returns
117 // success — abandoning checkout leaves the user on /onboard to retry.
118 const hasHandledReturnRef = useRef(false);
119 useEffect(() => {
120 if (!isReturningFromCheckoutSuccess || hasHandledReturnRef.current) {
121 return;
122 }
123 hasHandledReturnRef.current = true;
124
125 const sessionId = searchParams.get('session_id');
126 void (async () => {
127 const result = await completeOnboarding();
128 if (isServiceError(result)) {
129 toast({
130 description: `Failed to complete onboarding: ${result.message}`,
131 variant: "destructive",

Callers

nothing calls this directly

Calls 8

useOffersFunction · 0.90
useToastFunction · 0.90
completeOnboardingFunction · 0.90
isServiceErrorFunction · 0.90
createCheckoutSessionFunction · 0.90
useCaptureEventFunction · 0.85
toastFunction · 0.85
captureEventFunction · 0.50

Tested by

no test coverage detected