diff --git a/ui/src/components/lead-forms/TopUpModal.tsx b/ui/src/components/lead-forms/TopUpModal.tsx new file mode 100644 index 00000000..b574ee45 --- /dev/null +++ b/ui/src/components/lead-forms/TopUpModal.tsx @@ -0,0 +1,188 @@ +"use client"; + +import { useState } from "react"; +import { toast } from "sonner"; + +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +import { validateWorkEmail } from "./isPersonalEmail"; +import { + TOPUP_COMPANY_SIZE_OPTIONS, + TOPUP_VOLUME_OPTIONS, + VOLUME_PRICING_GATE, + type LeadSource, +} from "./leadFieldOptions"; +import { MathCaptcha } from "./MathCaptcha"; +import { submitLead } from "./submitLead"; + +interface TopUpModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; + source: LeadSource; + onOpenEnterprise: () => void; +} + +export function TopUpModal({ open, onOpenChange, source, onOpenEnterprise }: TopUpModalProps) { + const [credits, setCredits] = useState(""); + const [useCase, setUseCase] = useState(""); + const [volume, setVolume] = useState(""); + const [workEmail, setWorkEmail] = useState(""); + const [company, setCompany] = useState(""); + const [companySize, setCompanySize] = useState(""); + const [emailError, setEmailError] = useState(null); + const [captchaValid, setCaptchaValid] = useState(false); + const [submitting, setSubmitting] = useState(false); + + const wantsVolumePricing = volume === VOLUME_PRICING_GATE; + + const reset = () => { + setCredits(""); setUseCase(""); setVolume(""); setWorkEmail(""); + setCompany(""); setCompanySize(""); setEmailError(null); + setCaptchaValid(false); setSubmitting(false); + }; + + const handleSubmit = async () => { + if (!credits.trim() || !useCase.trim() || !volume) { + toast.error("Please fill in all required fields"); + return; + } + if (wantsVolumePricing) { + const err = validateWorkEmail(workEmail); + if (err) { setEmailError(err); return; } + if (!company.trim() || !companySize) { + toast.error("Please complete the volume-pricing details"); + return; + } + } + if (!captchaValid) { toast.error("Please answer the quick check"); return; } + + setSubmitting(true); + try { + await submitLead({ + kind: "topup", + source, + payload: { + credits, useCase, volume, wantsVolumePricing, + ...(wantsVolumePricing ? { workEmail, company, companySize } : {}), + }, + }); + toast.success("Thanks — we'll get your top-up sorted shortly."); + reset(); + onOpenChange(false); + } catch { + toast.error("Something went wrong. Please try again."); + setSubmitting(false); + } + }; + + return ( + { if (!o) reset(); onOpenChange(o); }}> + + + Request a credit top-up + + Tell us how many credits you need and we'll sort you out. + + + +
+
+ + setCredits(e.target.value)} + placeholder="e.g. 5000" + /> +
+ +
+ + setUseCase(e.target.value)} /> +
+ +
+ + +
+ + {wantsVolumePricing && ( +
+

Talk to us about volume pricing

+ +
+ + { setWorkEmail(e.target.value); setEmailError(null); }} + placeholder="you@company.com" + /> + {emailError &&

{emailError}

} +
+ +
+ + setCompany(e.target.value)} /> +
+ +
+ + +
+ + +
+ )} + + +
+ +
+ + +
+
+
+ ); +}