"use client"; import * as React from "react"; import { useState, useMemo, useEffect, useRef } from "react"; import { motion } from "framer-motion"; import * as confetti from "canvas-confetti"; import { Layers, BrainCircuit, Workflow, Plug, CheckCircle2, AlertCircle, } from "lucide-react"; import { FormState } from "./ContactForm/types"; import { PRICING, initialState, FEATURE_OPTIONS, FUNCTION_OPTIONS, API_OPTIONS, PAGE_SAMPLES, ASSET_OPTIONS, } from "./ContactForm/constants"; import { calculateTotals } from "@mintel/pdf"; import { sendContactInquiry } from "../actions/contact"; // Configurator Components import { ConfiguratorLayout } from "./ContactForm/Configurator/ConfiguratorLayout"; import { NarrativeInput } from "./ContactForm/Configurator/NarrativeInput"; import { ModuleGrid } from "./ContactForm/Configurator/ModuleGrid"; import { ReferenceInput } from "./ContactForm/Configurator/ReferenceInput"; import { Launchpad } from "./ContactForm/Configurator/Launchpad"; import { Reveal } from "./Reveal"; interface ContactFormProps { initialStepIndex?: number; initialState?: Partial; } const CONFIGURATOR_STEPS = [ { id: "intro", title: "INITIALISIERUNG" }, { id: "scope", title: "PROJEKT_UMFANG" }, { id: "refs", title: "INSPIRATIONS_QUELLE" }, { id: "assets", title: "BESTANDS_AUFNAHME" }, { id: "features", title: "KERN_MODULE" }, { id: "functions", title: "FUNKTIONALE_ERW" }, { id: "api", title: "SYSTEM_INTEGRATION" }, { id: "launch", title: "FINALE_SEQUENZ" }, ]; import { ContactGateway } from "./ContactForm/ContactGateway"; import { DirectMessageFlow } from "./ContactForm/DirectMessageFlow"; type FlowState = "discovery" | "configurator" | "direct-message"; export function ContactForm({ initialStepIndex = 0, initialState: injectedState, }: ContactFormProps) { const [flow, setFlow] = useState("discovery"); const [stepIndex, setStepIndex] = useState(initialStepIndex); const [state, setState] = useState({ ...initialState, ...injectedState, }); const [isSubmitted, setIsSubmitted] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); const containerRef = useRef(null); // Scroll to top on flow or step change useEffect(() => { if (containerRef.current) { containerRef.current.scrollTo({ top: 0, behavior: "smooth" }); } else { window.scrollTo({ top: 0, behavior: "smooth" }); } }, [flow, stepIndex]); // Keyboard Navigation (only for configurator) useEffect(() => { if (flow !== "configurator") return; const handleKeyDown = (e: KeyboardEvent) => { if ( e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement ) return; if (e.key === "Enter" && stepIndex < CONFIGURATOR_STEPS.length - 1) { handleNext(); } else if (e.key === "Backspace" && stepIndex > 0) { handlePrev(); } }; window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [stepIndex, flow]); const totals = useMemo(() => calculateTotals(state as any, PRICING), [state]); const updateState = (updates: Partial) => { setState((prev) => ({ ...prev, ...updates })); }; const toggleItem = (list: string[], id: string) => { return list.includes(id) ? list.filter((i) => i !== id) : [...list, id]; }; const handleNext = () => setStepIndex((prev) => prev + 1); const handlePrev = () => setStepIndex((prev) => Math.max(0, prev - 1)); const handleSubmit = async (e?: React.FormEvent) => { e?.preventDefault(); setIsSubmitting(true); setError(null); const result = await sendContactInquiry({ name: state.name, email: state.email, companyName: state.companyName, projectType: state.projectType, message: state.message, isFreeText: flow === "direct-message", config: flow === "configurator" ? state : undefined, }); setIsSubmitting(false); if (result.success) { setIsSubmitted(true); // Celebration const duration = 3 * 1000; const animationEnd = Date.now() + duration; const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 }; const randomInRange = (min: number, max: number) => Math.random() * (max - min) + min; const interval: any = setInterval(function () { const timeLeft = animationEnd - Date.now(); if (timeLeft <= 0) return clearInterval(interval); const particleCount = 50 * (timeLeft / duration); (confetti as any)({ ...defaults, particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 }, }); (confetti as any)({ ...defaults, particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 }, }); }, 250); } else { setError(result.error || "Unerwarteter Fehler bei der Übertragung."); } }; // Success view (unified) if (isSubmitted) { return (

SEQUENZ_INITIIERT

Das System wird Sie in Kürze unter {state.email} kontaktieren.

); } // Gateway Flow if (flow === "discovery") { return ( updateState({ name: v })} company={state.companyName} setCompany={(v) => updateState({ companyName: v })} projectType={state.projectType} setProjectType={(v) => updateState({ projectType: v })} onChooseConfigurator={() => setFlow("configurator")} onChooseDirectMessage={() => setFlow("direct-message")} /> ); } // Direct Message Flow if (flow === "direct-message") { return ( updateState({ email: v })} company={state.companyName} message={state.message} setMessage={(v) => updateState({ message: v })} onBack={() => setFlow("discovery")} onSubmit={handleSubmit} isSubmitting={isSubmitting} /> ); } // Configurator Flow const renderConfiguratorContent = () => { switch (CONFIGURATOR_STEPS[stepIndex].id) { case "intro": return ( updateState({ name: v })} company={state.companyName} setCompany={(v) => updateState({ companyName: v })} projectType={state.projectType} setProjectType={(v) => updateState({ projectType: v })} /> ); case "scope": return ( ({ id: p.id, title: p.label, description: p.desc, icon: , }))} selected={state.selectedPages} onToggle={(id) => updateState({ selectedPages: toggleItem(state.selectedPages, id), }) } otherCount={state.otherPagesCount} onOtherCountChange={(val) => updateState({ otherPagesCount: val })} otherLabel="Weitere Seiten" /> ); case "refs": return ( updateState({ references: refs })} /> ); case "assets": return ( ({ id: a.id, title: a.label, description: a.desc, icon: , }))} selected={state.assets} onToggle={(id) => updateState({ assets: toggleItem(state.assets, id) }) } /> ); case "features": return ( ({ id: f.id, title: f.label, description: f.desc, priceEstimate: "€€", icon: , }))} selected={state.features} onToggle={(id) => updateState({ features: toggleItem(state.features, id) }) } otherCount={state.otherFeaturesCount} onOtherCountChange={(val) => updateState({ otherFeaturesCount: val }) } otherLabel="Zusätzliche Features" /> ); case "functions": return ( ({ id: f.id, title: f.label, description: f.desc, priceEstimate: "€€€", icon: , }))} selected={state.functions} onToggle={(id) => updateState({ functions: toggleItem(state.functions, id) }) } /> ); case "api": return ( ({ id: a.id, title: a.label, description: a.desc, priceEstimate: "€€€", icon: , }))} selected={state.apiSystems} onToggle={(id) => updateState({ apiSystems: toggleItem(state.apiSystems, id) }) } /> ); case "launch": return (
{error && (
{error}
)} updateState({ email: v })} timeline={state.deadline} setTimeline={(v) => updateState({ deadline: v })} message={state.message} setMessage={(v) => updateState({ message: v })} onSubmit={handleSubmit} isValid={!!state.email && !!state.name} />
); default: return null; } }; return (
0 ? handlePrev : undefined} isSubmitting={isSubmitting} totalPrice={totals.totalPrice} monthlyPrice={totals.monthlyPrice} onRestart={() => { setFlow("discovery"); setStepIndex(0); setState(initialState); }} > {renderConfiguratorContent()}
); }