274 lines
11 KiB
TypeScript
274 lines
11 KiB
TypeScript
"use client";
|
|
|
|
import { motion } from "framer-motion";
|
|
import { cn } from "../../utils/cn";
|
|
import { Reveal } from "../Reveal";
|
|
import { ProjectType } from "./types";
|
|
import {
|
|
Mail,
|
|
MessageSquare,
|
|
ArrowLeft,
|
|
Send,
|
|
Phone,
|
|
User as UserIcon,
|
|
Calendar,
|
|
Layers,
|
|
} from "lucide-react";
|
|
|
|
interface DirectMessageFlowProps {
|
|
name: string;
|
|
setName: (val: string) => void;
|
|
email: string;
|
|
setEmail: (val: string) => void;
|
|
phone: string;
|
|
setPhone: (val: string) => void;
|
|
role: string;
|
|
setRole: (val: string) => void;
|
|
company: string;
|
|
setCompany: (val: string) => void;
|
|
projectType: ProjectType;
|
|
setProjectType: (val: ProjectType) => void;
|
|
deadline: string;
|
|
setDeadline: (val: string) => void;
|
|
message: string;
|
|
setMessage: (val: string) => void;
|
|
onBack: () => void;
|
|
onSubmit: () => void;
|
|
isSubmitting: boolean;
|
|
error?: string | null;
|
|
}
|
|
|
|
export const DirectMessageFlow = ({
|
|
name,
|
|
setName,
|
|
email,
|
|
setEmail,
|
|
phone,
|
|
setPhone,
|
|
role,
|
|
setRole,
|
|
company,
|
|
setCompany,
|
|
projectType,
|
|
setProjectType,
|
|
deadline,
|
|
setDeadline,
|
|
message,
|
|
setMessage,
|
|
onBack,
|
|
onSubmit,
|
|
isSubmitting,
|
|
error,
|
|
}: DirectMessageFlowProps) => {
|
|
return (
|
|
<div className="w-full max-w-3xl mx-auto px-4 py-12">
|
|
<div className="space-y-12">
|
|
{error && (
|
|
<Reveal width="100%" delay={0.1}>
|
|
<div className="bg-red-50 border border-red-100 rounded-2xl p-6 flex items-start gap-4 mb-8">
|
|
<div className="p-2 bg-red-100 rounded-lg text-red-600">
|
|
<Mail size={20} className="animate-pulse" />
|
|
</div>
|
|
<div className="space-y-1">
|
|
<h3 className="text-red-900 font-bold text-sm uppercase tracking-wider">
|
|
Übertragungsfehler
|
|
</h3>
|
|
<p className="text-red-700/80 font-medium text-base">
|
|
{error}
|
|
</p>
|
|
<div className="mt-2 text-[10px] font-mono text-red-400 uppercase tracking-widest">
|
|
Status: FEHLER_BEI_SEQUENZ_INIT
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Reveal>
|
|
)}
|
|
|
|
<Reveal width="100%" delay={0.2}>
|
|
<div className="space-y-4">
|
|
<span className="text-[10px] font-mono text-green-600 uppercase tracking-[0.3em] font-bold">
|
|
DIREKTANFRAGE // SCHRITT_01
|
|
</span>
|
|
<h2 className="text-3xl md:text-5xl font-bold tracking-tight text-slate-900 line-clamp-2">
|
|
Lassen Sie uns sprechen.
|
|
</h2>
|
|
<p className="text-slate-500 font-medium text-lg">
|
|
Senden Sie mir eine Nachricht und ich melde mich zeitnah zurück.
|
|
</p>
|
|
</div>
|
|
</Reveal>
|
|
|
|
<div className="space-y-12">
|
|
{/* Section: Mission Focus */}
|
|
<Reveal width="100%" delay={0.3} direction="up">
|
|
<div className="space-y-6">
|
|
<label className="flex items-center gap-2 text-[10px] font-mono font-bold uppercase tracking-widest text-slate-400">
|
|
<Layers size={12} /> Mission // Projekt-Typ
|
|
</label>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
|
|
{(["website", "web-app", "ecommerce"] as ProjectType[]).map(
|
|
(type) => {
|
|
const labels = {
|
|
website: "Website",
|
|
"web-app": "Web Application",
|
|
ecommerce: "E-Commerce",
|
|
};
|
|
return (
|
|
<button
|
|
key={type}
|
|
onClick={() => setProjectType(type)}
|
|
className={cn(
|
|
"px-6 py-4 rounded-xl border font-bold text-sm transition-all duration-200 text-left",
|
|
projectType === type
|
|
? "bg-slate-900 text-white border-slate-900 shadow-lg"
|
|
: "bg-white border-slate-100 text-slate-500 hover:border-slate-300",
|
|
)}
|
|
>
|
|
{labels[type]}
|
|
</button>
|
|
);
|
|
},
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Reveal>
|
|
|
|
{/* Section: Identity Details */}
|
|
<Reveal width="100%" delay={0.4} direction="up">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div className="space-y-4">
|
|
<label className="flex items-center gap-2 text-[10px] font-mono font-bold uppercase tracking-widest text-slate-400">
|
|
<UserIcon size={12} /> Ihr Name
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={name}
|
|
onChange={(e) => setName(e.target.value)}
|
|
placeholder="Max Mustermann"
|
|
className="w-full bg-slate-50 border border-slate-100 rounded-xl px-4 py-3 text-base font-medium focus:outline-none focus:ring-2 focus:ring-slate-900/5 focus:border-slate-900 transition-all"
|
|
/>
|
|
</div>
|
|
<div className="space-y-4">
|
|
<label className="flex items-center gap-2 text-[10px] font-mono font-bold uppercase tracking-widest text-slate-400">
|
|
<Layers size={12} /> Unternehmen (Optional)
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={company}
|
|
onChange={(e) => setCompany(e.target.value)}
|
|
placeholder="Beispiel GmbH"
|
|
className="w-full bg-slate-50 border border-slate-100 rounded-xl px-4 py-3 text-base font-medium focus:outline-none focus:ring-2 focus:ring-slate-900/5 focus:border-slate-900 transition-all"
|
|
/>
|
|
</div>
|
|
<div className="space-y-4">
|
|
<label className="flex items-center gap-2 text-[10px] font-mono font-bold uppercase tracking-widest text-slate-400">
|
|
<Mail size={12} /> E-Mail Adresse
|
|
</label>
|
|
<input
|
|
type="email"
|
|
value={email}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
placeholder="name@firma.de"
|
|
className="w-full bg-slate-50 border border-slate-100 rounded-xl px-4 py-3 text-base font-medium focus:outline-none focus:ring-2 focus:ring-slate-900/5 focus:border-slate-900 transition-all"
|
|
/>
|
|
</div>
|
|
<div className="space-y-4">
|
|
<label className="flex items-center gap-2 text-[10px] font-mono font-bold uppercase tracking-widest text-slate-400">
|
|
<Phone size={12} /> Rückruf-Nummer (Optional)
|
|
</label>
|
|
<input
|
|
type="tel"
|
|
value={phone}
|
|
onChange={(e) => setPhone(e.target.value)}
|
|
placeholder="+49 123 456789"
|
|
className="w-full bg-slate-50 border border-slate-100 rounded-xl px-4 py-3 text-base font-medium focus:outline-none focus:ring-2 focus:ring-slate-900/5 focus:border-slate-900 transition-all"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Reveal>
|
|
|
|
{/* Section: Additional Context */}
|
|
<Reveal width="100%" delay={0.5} direction="up">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div className="space-y-4">
|
|
<label className="flex items-center gap-2 text-[10px] font-mono font-bold uppercase tracking-widest text-slate-400">
|
|
<UserIcon size={12} /> Ihre Position
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={role}
|
|
onChange={(e) => setRole(e.target.value)}
|
|
placeholder="z.B. Gründer, Marketing Lead..."
|
|
className="w-full bg-slate-50 border border-slate-100 rounded-xl px-4 py-3 text-base font-medium focus:outline-none focus:ring-2 focus:ring-slate-900/5 focus:border-slate-900 transition-all"
|
|
/>
|
|
</div>
|
|
<div className="space-y-4">
|
|
<label className="flex items-center gap-2 text-[10px] font-mono font-bold uppercase tracking-widest text-slate-400">
|
|
<Calendar size={12} /> Zeitfenster
|
|
</label>
|
|
<select
|
|
value={deadline}
|
|
onChange={(e) => setDeadline(e.target.value)}
|
|
className="w-full bg-slate-50 border border-slate-100 rounded-xl px-4 py-3 text-base font-medium focus:outline-none focus:ring-2 focus:ring-slate-900/5 focus:border-slate-900 transition-all appearance-none cursor-pointer"
|
|
>
|
|
<option value="asap">ASAP (Sofort)</option>
|
|
<option value="1month">< 1 Monat (Priorität)</option>
|
|
<option value="3months">1-3 Monate (Standard)</option>
|
|
<option value="flexible">Flexibel</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</Reveal>
|
|
|
|
{/* Section: Payload */}
|
|
<Reveal width="100%" delay={0.6} direction="up">
|
|
<div className="space-y-4">
|
|
<label className="flex items-center gap-2 text-[10px] font-mono font-bold uppercase tracking-widest text-slate-400">
|
|
<MessageSquare size={12} /> Nachricht // Briefing
|
|
</label>
|
|
<textarea
|
|
value={message}
|
|
onChange={(e) => setMessage(e.target.value)}
|
|
placeholder="Beschreiben Sie kurz Ihr Anliegen oder hinterlassen Sie einen Link zum Briefing..."
|
|
rows={5}
|
|
className="w-full bg-slate-50 border border-slate-100 rounded-2xl px-6 py-4 text-base font-medium focus:outline-none focus:ring-2 focus:ring-slate-900/5 focus:border-slate-900 transition-all resize-none"
|
|
/>
|
|
</div>
|
|
</Reveal>
|
|
|
|
{/* Submit Button */}
|
|
<Reveal width="100%" delay={0.7} direction="up">
|
|
<button
|
|
onClick={onSubmit}
|
|
disabled={isSubmitting || !email || !message || !name}
|
|
className={cn(
|
|
"group relative w-full py-5 rounded-2xl font-bold text-lg transition-all duration-300 flex items-center justify-center gap-3 overflow-hidden",
|
|
isSubmitting || !email || !message || !name
|
|
? "bg-slate-100 text-slate-400 cursor-not-allowed"
|
|
: "bg-slate-900 text-white shadow-xl hover:shadow-2xl hover:-translate-y-1 active:scale-[0.98]",
|
|
)}
|
|
>
|
|
<div className="absolute inset-0 bg-gradient-to-r from-green-400/0 via-green-400/10 to-green-400/0 opacity-0 group-hover:opacity-100 -translate-x-full group-hover:translate-x-full transition-all duration-1000" />
|
|
|
|
{isSubmitting ? (
|
|
<>
|
|
<div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
|
<span>Übertragung läuft...</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<span>Anfrage senden</span>
|
|
<Send
|
|
size={20}
|
|
className="group-hover:translate-x-1 group-hover:-translate-y-1 transition-transform"
|
|
/>
|
|
</>
|
|
)}
|
|
</button>
|
|
</Reveal>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|