mirror of
https://github.com/Motion-Games/MotionWebStudio.git
synced 2026-04-21 09:00:53 +02:00
643 lines
35 KiB
TypeScript
643 lines
35 KiB
TypeScript
|
|
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
Send, CheckCircle, AlertCircle, Globe, Server, Check,
|
|
ArrowRight, ArrowLeft, User, FileText, Target, Layout,
|
|
Palette, Zap, Lightbulb, Settings, ClipboardCheck, Lock,
|
|
Cloud, Upload, Receipt, Building2, Link as LinkIcon, Info,
|
|
CreditCard, Wallet, Calculator, RefreshCw
|
|
} from 'lucide-react';
|
|
import { Button } from './Button';
|
|
import { useAuth } from '../context/AuthContext';
|
|
import { Link } from 'react-router-dom';
|
|
import { supabase, isSupabaseConfigured } from '../lib/supabaseClient';
|
|
import { defaultPlans } from '../lib/defaultPlans';
|
|
import { ProductPackage } from '../types';
|
|
|
|
interface Inspiration {
|
|
url: string;
|
|
comment: string;
|
|
}
|
|
|
|
export const OrderForm: React.FC = () => {
|
|
const { user, loading } = useAuth();
|
|
const [currentStep, setCurrentStep] = useState(1);
|
|
const [showPaymentSummary, setShowPaymentSummary] = useState(false);
|
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [submitError, setSubmitError] = useState<string | null>(null);
|
|
const [errors, setErrors] = useState<string[]>([]);
|
|
const [privacyAccepted, setPrivacyAccepted] = useState(false);
|
|
const [aszfAccepted, setAszfAccepted] = useState(false);
|
|
const [availablePackages, setAvailablePackages] = useState<ProductPackage[]>(defaultPlans);
|
|
const totalSteps = 10;
|
|
|
|
const [formData, setFormData] = useState({
|
|
name: '',
|
|
company: '',
|
|
email: user?.email || '',
|
|
phone: '',
|
|
package: 'Pro Web',
|
|
description: '',
|
|
goals: [] as string[],
|
|
goalOther: '',
|
|
successCriteria: '',
|
|
content: [] as string[],
|
|
contentOther: '',
|
|
existingAssets: 'Nem' as 'Igen' | 'Nem',
|
|
contentLink: '',
|
|
primaryColor: '',
|
|
secondaryColor: '',
|
|
balanceColor: '',
|
|
style: [] as string[],
|
|
targetAudience: '',
|
|
features: [] as string[],
|
|
inspirations: [
|
|
{ url: '', comment: '' },
|
|
{ url: '', comment: '' },
|
|
{ url: '', comment: '' }
|
|
] as Inspiration[],
|
|
extras: [] as string[],
|
|
domainName: '',
|
|
notes: '',
|
|
// Számlázási Mezők
|
|
billingType: 'individual' as 'individual' | 'company',
|
|
billingName: '',
|
|
billingZip: '',
|
|
billingCity: '',
|
|
billingAddress: '',
|
|
taxNumber: ''
|
|
});
|
|
|
|
const colorOptions = [
|
|
{ name: 'Piros', value: '#ef4444' },
|
|
{ name: 'Kék', value: '#3b82f6' },
|
|
{ name: 'Zöld', value: '#22c55e' },
|
|
{ name: 'Lila', value: '#a855f7' },
|
|
{ name: 'Fekete', value: '#171717' },
|
|
{ name: 'Fehér', value: '#ffffff' },
|
|
{ name: 'Szürke', value: '#6b7280' },
|
|
{ name: 'Narancs', value: '#f97316' },
|
|
{ name: 'Sárga', value: '#eab308' },
|
|
{ name: 'Türkiz', value: '#14b8a6' },
|
|
{ name: 'Barna', value: '#78350f' },
|
|
];
|
|
|
|
const styleOptions = [
|
|
'Modern és letisztult', 'Üzleti és professzionális', 'Fiatalos és energikus',
|
|
'Spirituális / nyugodt', 'Természetes / barátságos', 'Luxus / prémium'
|
|
];
|
|
|
|
const steps = [
|
|
{ id: 1, title: 'Kapcsolat', icon: User },
|
|
{ id: 2, title: 'Bemutatkozás', icon: FileText },
|
|
{ id: 3, title: 'Célok', icon: Target },
|
|
{ id: 4, title: 'Tartalom', icon: Layout },
|
|
{ id: 5, title: 'Design', icon: Palette },
|
|
{ id: 6, title: 'Funkciók', icon: Zap },
|
|
{ id: 7, title: 'Inspirációk', icon: Lightbulb },
|
|
{ id: 8, title: 'Extrák', icon: Settings },
|
|
{ id: 9, title: 'Számlázás', icon: Receipt },
|
|
{ id: 10, title: 'Összegzés', icon: ClipboardCheck },
|
|
];
|
|
|
|
useEffect(() => {
|
|
const fetchPlans = async () => {
|
|
if (!isSupabaseConfigured) return;
|
|
try {
|
|
const { data } = await supabase.from('plans').select('*');
|
|
if (data && data.length > 0) {
|
|
const sorted = [...data].sort((a, b) => {
|
|
const priceA = a.is_custom_price ? Infinity : (a.total_price || 0);
|
|
const priceB = b.is_custom_price ? Infinity : (b.total_price || 0);
|
|
return priceA - priceB;
|
|
});
|
|
setAvailablePackages(sorted);
|
|
}
|
|
} catch (e) {
|
|
console.error("Error fetching packages:", e);
|
|
}
|
|
};
|
|
fetchPlans();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (user) {
|
|
setFormData(prev => ({
|
|
...prev,
|
|
email: user.email || '',
|
|
name: prev.name || `${user.user_metadata?.last_name || ''} ${user.user_metadata?.first_name || ''}`.trim(),
|
|
billingName: prev.billingName || `${user.user_metadata?.last_name || ''} ${user.user_metadata?.first_name || ''}`.trim()
|
|
}));
|
|
}
|
|
}, [user]);
|
|
|
|
const selectedPkg = availablePackages.find(p => p.name === formData.package);
|
|
const totalAmount = selectedPkg?.total_price || 0;
|
|
const advanceAmount = selectedPkg?.advance_price || 0;
|
|
const remainingAmount = totalAmount - advanceAmount;
|
|
const isCustomPrice = selectedPkg?.is_custom_price;
|
|
|
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
const { name, value } = e.target;
|
|
setFormData(prev => ({ ...prev, [name]: value }));
|
|
};
|
|
|
|
const handleCheckboxChange = (category: 'goals' | 'content' | 'style' | 'features' | 'extras', value: string) => {
|
|
setFormData(prev => {
|
|
const list = prev[category];
|
|
if (list.includes(value)) {
|
|
return { ...prev, [category]: list.filter(item => item !== value) };
|
|
} else {
|
|
if (category === 'style' && list.length >= 2) return prev;
|
|
return { ...prev, [category]: [...list, value] };
|
|
}
|
|
});
|
|
};
|
|
|
|
const validateStep = (step: number): boolean => {
|
|
const newErrors: string[] = [];
|
|
if (step === 1) {
|
|
if (!formData.name) newErrors.push('A név megadása kötelező.');
|
|
if (!formData.phone) newErrors.push('A telefonszám megadása kötelező.');
|
|
}
|
|
if (step === 9) {
|
|
if (!formData.billingName) newErrors.push('A számlázási név megadása kötelező.');
|
|
if (!formData.billingZip) newErrors.push('Az irányítószám megadása kötelező.');
|
|
if (!formData.billingCity) newErrors.push('A város megadása kötelező.');
|
|
if (!formData.billingAddress) newErrors.push('A cím megadása kötelező.');
|
|
if (formData.billingType === 'company' && !formData.taxNumber) newErrors.push('Cég esetén az adószám kötelező.');
|
|
}
|
|
if (step === 10) {
|
|
if (!privacyAccepted) newErrors.push('Az adatkezelési tájékoztató elfogadása kötelező.');
|
|
if (!aszfAccepted) newErrors.push('Az ÁSZF elfogadása kötelező.');
|
|
}
|
|
|
|
setErrors(newErrors);
|
|
return newErrors.length === 0;
|
|
};
|
|
|
|
const nextStep = () => {
|
|
if (validateStep(currentStep)) {
|
|
if (currentStep < totalSteps) {
|
|
setCurrentStep(prev => prev + 1);
|
|
window.scrollTo({ top: document.getElementById('order-form-container')?.offsetTop || 0, behavior: 'smooth' });
|
|
} else {
|
|
setShowPaymentSummary(true);
|
|
window.scrollTo({ top: document.getElementById('order-form-container')?.offsetTop || 0, behavior: 'smooth' });
|
|
}
|
|
}
|
|
};
|
|
|
|
const prevStep = () => {
|
|
if (showPaymentSummary) {
|
|
setShowPaymentSummary(false);
|
|
return;
|
|
}
|
|
if (currentStep > 1) {
|
|
setCurrentStep(prev => prev - 1);
|
|
window.scrollTo({ top: document.getElementById('order-form-container')?.offsetTop || 0, behavior: 'smooth' });
|
|
}
|
|
};
|
|
|
|
const handleSubmit = async () => {
|
|
setIsSubmitting(true);
|
|
setSubmitError(null);
|
|
|
|
const amountStr = isCustomPrice ? 'Egyedi árazás' : `${totalAmount.toLocaleString('hu-HU')} Ft`;
|
|
|
|
if (isSupabaseConfigured && user) {
|
|
try {
|
|
// 1. Create order
|
|
const { data: orderData, error } = await supabase.from('orders').insert({
|
|
user_id: user.id,
|
|
customer_name: formData.name,
|
|
customer_email: formData.email,
|
|
package: formData.package,
|
|
status: 'new',
|
|
amount: amountStr,
|
|
details: {
|
|
...formData,
|
|
payment_summary: {
|
|
total: totalAmount,
|
|
advance: advanceAmount,
|
|
remaining: remainingAmount,
|
|
currency: 'HUF',
|
|
is_custom: isCustomPrice
|
|
}
|
|
}
|
|
}).select().single();
|
|
|
|
if (error) throw error;
|
|
|
|
// 2. Initiate Stripe Payment if NOT custom price and is a standard package
|
|
// Enterprise csomagnál ez a feltétel hamis lesz, így a fizetés kimarad.
|
|
if (!isCustomPrice && (formData.package === 'Landing Page' || formData.package === 'Pro Web')) {
|
|
try {
|
|
const { data: checkoutData, error: checkoutError } = await supabase.functions.invoke('create-checkout-session', {
|
|
body: {
|
|
order_id: orderData.id,
|
|
package_name: formData.package,
|
|
payment_type: 'deposit',
|
|
customer_email: formData.email
|
|
}
|
|
});
|
|
|
|
if (checkoutError) {
|
|
console.error("Invoke Error:", checkoutError);
|
|
throw new Error("A fizetési szerver nem válaszolt megfelelően. (Edge Function hiba)");
|
|
}
|
|
|
|
if (checkoutData?.url) {
|
|
window.location.href = checkoutData.url;
|
|
return; // Stop execution to redirect
|
|
} else {
|
|
if(checkoutData?.error) throw new Error(checkoutData.error);
|
|
throw new Error("Nem sikerült létrehozni a fizetési linket.");
|
|
}
|
|
} catch (stripeErr: any) {
|
|
console.error("Stripe/Network error:", stripeErr);
|
|
const msg = stripeErr?.message || "Hálózati vagy konfigurációs hiba.";
|
|
alert(`Rendelés rögzítve (ID: ${orderData.id.slice(0,8)}), de a fizetési kapu megnyitása nem sikerült.\n\nHibaüzenet: ${msg}\n\nKérjük, ellenőrizze internetkapcsolatát, vagy vegye fel velünk a kapcsolatot.`);
|
|
setIsSubmitted(true);
|
|
}
|
|
} else {
|
|
// Enterprise / Custom price or demo mode
|
|
// Itt nincs Stripe hívás, csak simán befejezzük a folyamatot.
|
|
setIsSubmitted(true);
|
|
}
|
|
|
|
} catch (err: any) {
|
|
setSubmitError('Hiba a rendelés mentésekor: ' + err.message);
|
|
} finally {
|
|
setIsSubmitting(false);
|
|
}
|
|
} else {
|
|
// Demo mode fallback
|
|
await new Promise(r => setTimeout(r, 1000));
|
|
setIsSubmitted(true);
|
|
setIsSubmitting(false);
|
|
}
|
|
};
|
|
|
|
const inputClass = "w-full px-4 py-3 rounded-xl border border-gray-200 bg-white focus:ring-4 focus:ring-primary/10 focus:border-primary outline-none transition-all shadow-sm font-medium text-gray-900";
|
|
const labelClass = "text-xs font-black text-gray-400 uppercase tracking-widest mb-2 block ml-1";
|
|
|
|
const formatPrice = (num: number) => num.toLocaleString('hu-HU') + ' Ft';
|
|
|
|
if (loading) {
|
|
return <div className="p-12 text-center text-gray-500 font-bold animate-pulse">Betöltés...</div>;
|
|
}
|
|
|
|
// Ha nincs bejelentkezve, mutassuk a bejelentkezési felhívást
|
|
if (!user) {
|
|
return (
|
|
<div id="order-form-container" className="bg-white rounded-[40px] shadow-2xl p-12 text-center border border-gray-100 max-w-4xl mx-auto scroll-mt-24">
|
|
<div className="w-24 h-24 bg-purple-50 rounded-full flex items-center justify-center mx-auto mb-8 shadow-inner">
|
|
<User className="w-12 h-12 text-primary" />
|
|
</div>
|
|
<h2 className="text-3xl font-black text-gray-900 mb-4 tracking-tighter">Jelentkezz be a folytatáshoz!</h2>
|
|
<p className="text-lg text-gray-600 mb-10 max-w-2xl mx-auto leading-relaxed">
|
|
A projekt indításához és a rendelés leadásához kérjük, lépj be fiókodba, vagy regisztrálj egyet pár perc alatt.
|
|
</p>
|
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
|
<Link to="/auth/login">
|
|
<Button size="lg" className="px-12 font-black uppercase tracking-widest text-xs w-full sm:w-auto">Bejelentkezés</Button>
|
|
</Link>
|
|
<Link to="/auth/register">
|
|
<Button variant="outline" size="lg" className="px-12 font-black uppercase tracking-widest text-xs w-full sm:w-auto">Regisztráció</Button>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (isSubmitted) {
|
|
return (
|
|
<div id="order-form-container" className="bg-white rounded-[32px] shadow-xl p-12 text-center border border-gray-100 animate-fade-in-up scroll-mt-24 max-w-4xl mx-auto">
|
|
<div className="w-24 h-24 bg-green-50 rounded-full flex items-center justify-center mx-auto mb-8 shadow-inner"><CheckCircle className="w-12 h-12 text-green-500" /></div>
|
|
<h2 className="text-3xl font-black text-gray-900 mb-4 tracking-tighter">Rendelésedet fogadtuk!</h2>
|
|
<p className="text-lg text-gray-600 mb-10 max-w-2xl mx-auto leading-relaxed">Köszönjük a bizalmat! A megadott e-mail címre elküldtük a visszaigazolást. Kollégánk hamarosan felveszi veled a kapcsolatot.</p>
|
|
<Link to="/dashboard">
|
|
<Button size="lg" className="px-12 font-black uppercase tracking-widest text-xs">Vezérlőpult megnyitása</Button>
|
|
</Link>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div id="order-form-container" className="bg-white rounded-[40px] shadow-2xl overflow-hidden border border-gray-100 scroll-mt-24 transition-all duration-500 flex flex-col relative min-h-[600px]">
|
|
{/* Header with Progress */}
|
|
<div className="bg-gray-50/80 backdrop-blur-md pt-12 pb-8 px-6 md:px-12 border-b border-gray-100">
|
|
<div className="text-center mb-10">
|
|
<h2 className="text-3xl md:text-4xl font-black text-gray-900 mb-3 tracking-tighter uppercase italic">Projekt Indítása</h2>
|
|
<p className="text-gray-500 font-bold uppercase text-[10px] tracking-[0.3em]">
|
|
{showPaymentSummary
|
|
? (isCustomPrice ? 'Utolsó lépés: Véglegesítés' : 'Utolsó lépés: Fizetés')
|
|
: `Lépés ${currentStep} / ${totalSteps}`}
|
|
</p>
|
|
</div>
|
|
|
|
{!showPaymentSummary && (
|
|
<div className="max-w-4xl mx-auto">
|
|
<div className="h-1.5 w-full bg-gray-200 rounded-full overflow-hidden">
|
|
<div className="h-full bg-primary transition-all duration-700 ease-out shadow-[0_0_15px_rgba(124,58,237,0.5)]" style={{ width: `${(currentStep / totalSteps) * 100}%` }}></div>
|
|
</div>
|
|
<div className="flex justify-between mt-4">
|
|
{steps.map((s) => (
|
|
<div key={s.id} className={`flex flex-col items-center gap-2 ${s.id === currentStep ? 'opacity-100' : 'opacity-30 hidden md:flex'}`}>
|
|
<div className={`w-8 h-8 rounded-lg flex items-center justify-center transition-all ${s.id === currentStep ? 'bg-primary text-white scale-110 shadow-lg shadow-primary/20' : 'bg-white text-gray-400 border border-gray-200'}`}>
|
|
<s.icon className="w-4 h-4" />
|
|
</div>
|
|
{s.id === currentStep && <span className="text-[10px] font-black uppercase tracking-widest text-primary">{s.title}</span>}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Main Content */}
|
|
<div className="p-6 md:p-12 flex-grow bg-white">
|
|
{errors.length > 0 && (
|
|
<div className="bg-red-50 border-2 border-red-100 text-red-600 px-6 py-4 rounded-2xl flex items-start gap-4 mb-8 animate-fade-in shadow-sm">
|
|
<AlertCircle className="w-6 h-6 flex-shrink-0" />
|
|
<div className="text-xs font-black uppercase tracking-widest leading-relaxed">
|
|
{errors.map((err, idx) => <p key={idx}>{err}</p>)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{!showPaymentSummary ? (
|
|
<div className="max-w-3xl mx-auto animate-fade-in">
|
|
{currentStep === 1 && (
|
|
<div className="space-y-8">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div><label className={labelClass}>Teljes Név *</label><input type="text" name="name" value={formData.name} onChange={handleInputChange} placeholder="Pl: Kovács János" className={inputClass} /></div>
|
|
<div><label className={labelClass}>Cégnév (opcionális)</label><input type="text" name="company" value={formData.company} onChange={handleInputChange} placeholder="Pl: Kreatív Kft." className={inputClass} /></div>
|
|
<div><label className={labelClass}>E-mail *</label><input type="email" value={formData.email} readOnly className={`${inputClass} bg-white text-gray-400`} /></div>
|
|
<div><label className={labelClass}>Telefonszám *</label><input type="tel" name="phone" value={formData.phone} onChange={handleInputChange} placeholder="+36..." className={inputClass} /></div>
|
|
</div>
|
|
<div className="pt-6">
|
|
<label className={labelClass}>Választott Csomag</label>
|
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
|
{availablePackages.map((pkg) => (
|
|
<button key={pkg.id} onClick={() => setFormData({...formData, package: pkg.name})} className={`p-4 rounded-2xl border-2 text-left transition-all ${formData.package === pkg.name ? 'border-primary bg-purple-50 shadow-md' : 'border-gray-100 hover:border-gray-200 bg-white'}`}>
|
|
<p className={`text-xs font-black uppercase tracking-widest ${formData.package === pkg.name ? 'text-primary' : 'text-gray-400'}`}>{pkg.name}</p>
|
|
<p className="text-sm font-bold text-gray-900 mt-1">{pkg.price}</p>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 2 && (
|
|
<div className="space-y-6">
|
|
<label className={labelClass}>Mutassa be röviden vállalkozását!</label>
|
|
<textarea name="description" rows={8} value={formData.description} onChange={handleInputChange} placeholder="Mivel foglalkozik a cég, mi a fő profilja?" className={inputClass}></textarea>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 3 && (
|
|
<div className="space-y-6">
|
|
<label className={labelClass}>Melyek a weboldal fő céljai?</label>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
{['Cég bemutatása', 'Online értékesítés', 'Időpontfoglalás', 'Ügyfélszerzés', 'Információközlés'].map(goal => (
|
|
<button key={goal} onClick={() => handleCheckboxChange('goals', goal)} className={`p-4 rounded-2xl border-2 text-left font-bold transition-all ${formData.goals.includes(goal) ? 'border-primary bg-purple-50 text-primary' : 'border-gray-100 text-gray-500 bg-white'}`}>{goal}</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 4 && (
|
|
<div className="space-y-8">
|
|
<label className={labelClass}>Milyen aloldalakat szeretne?</label>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
{['Rólunk', 'Szolgáltatások', 'Referenciák', 'Gyakori Kérdések', 'Blog', 'Kapcsolat'].map(item => (
|
|
<button key={item} onClick={() => handleCheckboxChange('content', item)} className={`p-4 rounded-2xl border-2 text-left font-bold transition-all ${formData.content.includes(item) ? 'border-primary bg-purple-50 text-primary' : 'border-gray-100 text-gray-500 bg-white'}`}>{item}</button>
|
|
))}
|
|
</div>
|
|
<div className="pt-6 border-t border-gray-100">
|
|
<label className={labelClass}>Vannak meglévő anyagai? (Link)</label>
|
|
<input type="text" name="contentLink" value={formData.contentLink} onChange={handleInputChange} placeholder="Google Drive, Dropbox link..." className={inputClass} />
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 5 && (
|
|
<div className="space-y-8">
|
|
<label className={labelClass}>Design preferenciák (Fő színek)</label>
|
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
|
<div><p className="text-[10px] font-black text-gray-400 mb-2">FŐSZÍN</p><input type="color" value={formData.primaryColor || '#7c3aed'} onChange={e => setFormData({...formData, primaryColor: e.target.value})} className="w-full h-12 rounded-xl cursor-pointer bg-white" /></div>
|
|
<div><p className="text-[10px] font-black text-gray-400 mb-2">MELLÉKSZÍN</p><input type="color" value={formData.secondaryColor || '#3b82f6'} onChange={e => setFormData({...formData, secondaryColor: e.target.value})} className="w-full h-12 rounded-xl cursor-pointer bg-white" /></div>
|
|
<div><p className="text-[10px] font-black text-gray-400 mb-2">HÁTTÉRSZÍN</p><input type="color" value={formData.balanceColor || '#ffffff'} onChange={e => setFormData({...formData, balanceColor: e.target.value})} className="w-full h-12 rounded-xl cursor-pointer bg-white" /></div>
|
|
</div>
|
|
<div className="pt-6">
|
|
<label className={labelClass}>Stílusirányzat (Max 2)</label>
|
|
<div className="flex flex-wrap gap-3">
|
|
{styleOptions.map(style => (
|
|
<button key={style} onClick={() => handleCheckboxChange('style', style)} className={`px-5 py-2.5 rounded-full border-2 text-[10px] font-black uppercase tracking-widest transition-all ${formData.style.includes(style) ? 'border-primary bg-primary text-white' : 'border-gray-100 text-gray-400 bg-white'}`}>{style}</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 6 && (
|
|
<div className="space-y-6">
|
|
<label className={labelClass}>Milyen funkciókra van szüksége?</label>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
{['Kapcsolatfelvételi űrlap', 'Hírlevél feliratkozás', 'Kereső funkció', 'Többnyelvűség', 'Admin felület', 'Bankkártyás fizetés'].map(feat => (
|
|
<button key={feat} onClick={() => handleCheckboxChange('features', feat)} className={`p-4 rounded-2xl border-2 text-left font-bold transition-all ${formData.features.includes(feat) ? 'border-primary bg-purple-50 text-primary' : 'border-gray-100 text-gray-500 bg-white'}`}>{feat}</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 7 && (
|
|
<div className="space-y-8 animate-fade-in">
|
|
<label className={labelClass}>Inspirációs weboldalak és megjegyzések</label>
|
|
<div className="space-y-6">
|
|
{[0, 1, 2].map(i => (
|
|
<div key={i} className="grid grid-cols-1 md:grid-cols-2 gap-4 p-4 bg-gray-50/50 rounded-2xl border border-gray-100">
|
|
<div className="space-y-2">
|
|
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest ml-1">Példa oldal {i+1} linkje</p>
|
|
<input
|
|
type="url"
|
|
value={formData.inspirations[i].url}
|
|
onChange={e => {
|
|
const ins = [...formData.inspirations];
|
|
ins[i].url = e.target.value;
|
|
setFormData({...formData, inspirations: ins});
|
|
}}
|
|
placeholder="https://..."
|
|
className={inputClass}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest ml-1">Mi tetszik rajta?</p>
|
|
<input
|
|
type="text"
|
|
value={formData.inspirations[i].comment}
|
|
onChange={e => {
|
|
const ins = [...formData.inspirations];
|
|
ins[i].comment = e.target.value;
|
|
setFormData({...formData, inspirations: ins});
|
|
}}
|
|
placeholder="Színek, elrendezés, stílus..."
|
|
className={inputClass}
|
|
/>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 8 && (
|
|
<div className="space-y-6">
|
|
<label className={labelClass}>Egyéb megjegyzések az extrákhoz</label>
|
|
<textarea name="notes" rows={8} value={formData.notes} onChange={handleInputChange} placeholder="Bármilyen egyéb kérés, funkció..." className={inputClass}></textarea>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 9 && (
|
|
<div className="space-y-8">
|
|
<div className="flex gap-4 p-2 bg-gray-100 rounded-2xl w-fit mx-auto mb-8">
|
|
<button onClick={() => setFormData({...formData, billingType: 'individual'})} className={`px-6 py-2 rounded-xl text-xs font-black uppercase tracking-widest transition-all ${formData.billingType === 'individual' ? 'bg-white text-primary shadow-sm' : 'text-gray-400'}`}>Magánszemély</button>
|
|
<button onClick={() => setFormData({...formData, billingType: 'company'})} className={`px-6 py-2 rounded-xl text-xs font-black uppercase tracking-widest transition-all ${formData.billingType === 'company' ? 'bg-white text-primary shadow-sm' : 'text-gray-400'}`}>Cég</button>
|
|
</div>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div className="md:col-span-2"><label className={labelClass}>{formData.billingType === 'company' ? 'Cégnév *' : 'Számlázási Név *'}</label><input type="text" name="billingName" value={formData.billingName} onChange={handleInputChange} className={inputClass} /></div>
|
|
{formData.billingType === 'company' && <div className="md:col-span-2"><label className={labelClass}>Adószám *</label><input type="text" name="taxNumber" value={formData.taxNumber} onChange={handleInputChange} placeholder="XXXXXXXX-Y-ZZ" className={inputClass} /></div>}
|
|
<div><label className={labelClass}>Irányítószám *</label><input type="text" name="billingZip" value={formData.billingZip} onChange={handleInputChange} className={inputClass} /></div>
|
|
<div><label className={labelClass}>Város *</label><input type="text" name="billingCity" value={formData.billingCity} onChange={handleInputChange} className={inputClass} /></div>
|
|
<div className="md:col-span-2"><label className={labelClass}>Cím *</label><input type="text" name="billingAddress" value={formData.billingAddress} onChange={handleInputChange} placeholder="Utca, házszám..." className={inputClass} /></div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{currentStep === 10 && (
|
|
<div className="space-y-10">
|
|
<div className="bg-gray-50 p-8 rounded-[32px] border border-gray-200">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
<div><p className="text-[10px] font-black text-gray-400 uppercase tracking-widest mb-1">Csomag</p><p className="text-xl font-black text-primary">{formData.package}</p></div>
|
|
<div><p className="text-[10px] font-black text-gray-400 uppercase tracking-widest mb-1">Ügyfél</p><p className="text-lg font-bold text-gray-900">{formData.name}</p></div>
|
|
<div className="md:col-span-2 pt-6 border-t border-gray-200"><p className="text-[10px] font-black text-gray-400 uppercase tracking-widest mb-1">Számlázási Cím</p><p className="font-bold text-gray-700">{formData.billingZip} {formData.billingCity}, {formData.billingAddress}</p></div>
|
|
</div>
|
|
</div>
|
|
<div className="space-y-4">
|
|
<label className="flex items-start gap-4 cursor-pointer group p-4 rounded-2xl border border-transparent hover:bg-purple-50/50 transition-colors">
|
|
<input type="checkbox" checked={privacyAccepted} onChange={e => setPrivacyAccepted(e.target.checked)} className="w-5 h-5 rounded text-primary mt-0.5" />
|
|
<span className="text-sm font-bold text-gray-600 group-hover:text-gray-900 transition-colors">Elfogadom az <Link to="/privacy" className="text-primary underline">adatkezelési tájékoztatót</Link>.</span>
|
|
</label>
|
|
<label className="flex items-start gap-4 cursor-pointer group p-4 rounded-2xl border border-transparent hover:bg-purple-50/50 transition-colors">
|
|
<input type="checkbox" checked={aszfAccepted} onChange={e => setAszfAccepted(e.target.checked)} className="w-5 h-5 rounded text-primary mt-0.5" />
|
|
<span className="text-sm font-bold text-gray-600 group-hover:text-gray-900 transition-colors">Elfogadom az <Link to="/terms" className="text-primary underline">általános szerződési feltételeket</Link>.</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
) : (
|
|
/* PAYMENT SUMMARY / CUSTOM ORDER VIEW */
|
|
<div className="max-w-2xl mx-auto space-y-10 animate-fade-in-up">
|
|
{isCustomPrice ? (
|
|
/* CUSTOM PRICE VIEW */
|
|
<>
|
|
<div className="text-center">
|
|
<div className="w-20 h-20 bg-blue-50 rounded-3xl flex items-center justify-center mx-auto mb-6 text-blue-600 shadow-sm">
|
|
<FileText className="w-10 h-10" />
|
|
</div>
|
|
<h3 className="text-3xl font-black text-gray-900 tracking-tight mb-4">Rendelés Véglegesítése</h3>
|
|
<p className="text-gray-600 font-medium leading-relaxed">
|
|
Egyedi csomagot választottál. A rendelés leadása után munkatársunk hamarosan felveszi veled a kapcsolatot a pontos igények és az árazás egyeztetése miatt.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="bg-primary/5 p-10 rounded-[32px] border-2 border-primary/20 text-center shadow-xl shadow-primary/5 relative overflow-hidden">
|
|
<div className="absolute -top-10 -right-10 w-40 h-40 bg-primary/10 rounded-full blur-3xl"></div>
|
|
<p className="text-[11px] font-black text-primary uppercase tracking-[0.3em] mb-4">Választott Konstrukció</p>
|
|
<div className="text-4xl md:text-5xl font-black text-primary mb-6 tracking-tighter">
|
|
Egyedi Árazás
|
|
</div>
|
|
<p className="text-xs text-primary/60 font-bold uppercase tracking-widest leading-relaxed">
|
|
A "Rendelés Leadása" gombra kattintva rögzítjük igényedet.
|
|
</p>
|
|
</div>
|
|
</>
|
|
) : (
|
|
/* STANDARD PAYMENT VIEW */
|
|
<>
|
|
<div className="text-center">
|
|
<div className="w-20 h-20 bg-green-50 rounded-3xl flex items-center justify-center mx-auto mb-6 text-green-600 shadow-sm">
|
|
<Wallet className="w-10 h-10" />
|
|
</div>
|
|
<h3 className="text-3xl font-black text-gray-900 tracking-tight mb-4">Rendelés Összesítése</h3>
|
|
<p className="text-gray-600 font-medium leading-relaxed">
|
|
A projekt elindításához kérjük, fizesse be az előleget. A rendszerünk automatikusan értesít minket a befizetésről, és azonnal megkezdjük a munkát.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div className="bg-gray-50 p-6 rounded-[24px] border border-gray-100 flex flex-col items-center text-center">
|
|
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest mb-2">Projekt Teljes Ára</p>
|
|
<p className="text-xl font-bold text-gray-900">{formatPrice(totalAmount)}</p>
|
|
</div>
|
|
<div className="bg-gray-50 p-6 rounded-[24px] border border-gray-100 flex flex-col items-center text-center">
|
|
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest mb-2">Fennmaradó (Demó után)</p>
|
|
<p className="text-xl font-bold text-gray-900">{formatPrice(remainingAmount)}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-primary/5 p-10 rounded-[32px] border-2 border-primary/20 text-center shadow-xl shadow-primary/5 relative overflow-hidden">
|
|
<div className="absolute -top-10 -right-10 w-40 h-40 bg-primary/10 rounded-full blur-3xl"></div>
|
|
<p className="text-[11px] font-black text-primary uppercase tracking-[0.3em] mb-4">Jelenleg Fizetendő Előleg</p>
|
|
<div className="text-5xl md:text-6xl font-black text-primary mb-6 tracking-tighter">
|
|
{formatPrice(advanceAmount)}
|
|
</div>
|
|
<p className="text-xs text-primary/60 font-bold uppercase tracking-widest leading-relaxed">
|
|
A gombra kattintva átirányítjuk a biztonságos Stripe fizetési oldalra.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="bg-amber-50 border border-amber-200 p-6 rounded-2xl flex gap-4">
|
|
<div className="shrink-0"><Info className="w-5 h-5 text-amber-500" /></div>
|
|
<p className="text-xs text-amber-800 font-medium leading-relaxed">
|
|
<strong>Fontos:</strong> A rendszer a rendelés leadása után elküldi Önnek az előlegszámlát is. A bankkártyás fizetés azonnali feldolgozást tesz lehetővé.
|
|
</p>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Footer Navigation */}
|
|
<div className="bg-white border-t border-gray-100 p-8 flex justify-between items-center rounded-b-[40px]">
|
|
<Button onClick={prevStep} variant="white" disabled={currentStep === 1 || isSubmitting} className={`${currentStep === 1 ? 'opacity-0' : ''} border border-gray-200 font-black uppercase text-[10px] tracking-widest px-10`}>Vissza</Button>
|
|
{!showPaymentSummary ? (
|
|
<Button onClick={nextStep} className="font-black uppercase text-[10px] tracking-widest px-12 shadow-lg shadow-primary/20">
|
|
{currentStep < totalSteps ? 'Következő' : 'Rendelés Leadása'} <ArrowRight className="w-4 h-4 ml-2" />
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
onClick={handleSubmit}
|
|
disabled={isSubmitting}
|
|
className="font-black uppercase text-[10px] tracking-widest px-16 py-6 shadow-2xl shadow-primary/40 h-auto"
|
|
>
|
|
{isSubmitting ? (
|
|
<><RefreshCw className="w-4 h-4 animate-spin mr-2" /> FELDOLGOZÁS...</>
|
|
) : isCustomPrice ? (
|
|
<><Send className="w-4 h-4 mr-2" /> RENDELÉS LEADÁSA</>
|
|
) : (
|
|
<><CreditCard className="w-4 h-4 mr-2" /> FIZETÉS INDÍTÁSA</>
|
|
)}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|