From 8084e9904674c548df0625b692201a700a0908f0 Mon Sep 17 00:00:00 2001 From: Pritesh Date: Wed, 3 Jun 2026 04:23:01 +0530 Subject: [PATCH] feat(lead-gen): shared lead-forms context provider Co-Authored-By: Claude Opus 4.8 (1M context) --- ui/src/context/LeadFormsContext.tsx | 84 +++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 ui/src/context/LeadFormsContext.tsx diff --git a/ui/src/context/LeadFormsContext.tsx b/ui/src/context/LeadFormsContext.tsx new file mode 100644 index 00000000..d885ac5a --- /dev/null +++ b/ui/src/context/LeadFormsContext.tsx @@ -0,0 +1,84 @@ +"use client"; + +import posthog from "posthog-js"; +import { createContext, useCallback, useContext, useMemo, useRef, useState, type ReactNode } from "react"; + +import { EnterpriseModal } from "@/components/lead-forms/EnterpriseModal"; +import { HireExpertModal } from "@/components/lead-forms/HireExpertModal"; +import type { LeadSource } from "@/components/lead-forms/leadFieldOptions"; +import { TopUpModal } from "@/components/lead-forms/TopUpModal"; +import { PostHogEvent } from "@/constants/posthog-events"; + +interface LeadFormsContextValue { + openHireExpert: (source: LeadSource) => void; + openTopUp: (source: LeadSource) => void; + openEnterprise: (source: LeadSource) => void; + // True once the hire modal has been opened this session (used to suppress the builder nudge). + hasOpenedHireRef: React.MutableRefObject; +} + +const LeadFormsContext = createContext(null); + +export function LeadFormsProvider({ children }: { children: ReactNode }) { + const [hireOpen, setHireOpen] = useState(false); + const [topUpOpen, setTopUpOpen] = useState(false); + const [enterpriseOpen, setEnterpriseOpen] = useState(false); + // Track the originating source so the *_OPENED and submit events agree. + const [hireSource, setHireSource] = useState("sidebar"); + const [topUpSource, setTopUpSource] = useState("billing_card"); + const [enterpriseSource, setEnterpriseSource] = useState("topup"); + const hasOpenedHireRef = useRef(false); + + const openHireExpert = useCallback((source: LeadSource) => { + hasOpenedHireRef.current = true; + setHireSource(source); + setHireOpen(true); + posthog.capture(PostHogEvent.HIRE_EXPERT_OPENED, { source }); + }, []); + + const openTopUp = useCallback((source: LeadSource) => { + setTopUpSource(source); + setTopUpOpen(true); + posthog.capture(PostHogEvent.TOPUP_REQUEST_OPENED, { source }); + }, []); + + const openEnterprise = useCallback((source: LeadSource) => { + setEnterpriseSource(source); + setEnterpriseOpen(true); + posthog.capture(PostHogEvent.ENTERPRISE_LEAD_OPENED, { source }); + }, []); + + const value = useMemo( + () => ({ openHireExpert, openTopUp, openEnterprise, hasOpenedHireRef }), + [openHireExpert, openTopUp, openEnterprise], + ); + + return ( + + {children} + openEnterprise("topup")} + /> + openEnterprise("hire_expert")} + /> + + + ); +} + +export function useLeadForms(): LeadFormsContextValue { + const ctx = useContext(LeadFormsContext); + if (!ctx) throw new Error("useLeadForms must be used within a LeadFormsProvider"); + return ctx; +}