import React, { useEffect, useMemo, useState } from 'react'; import { useForm, usePage } from '@inertiajs/react'; import { useTranslation } from 'react-i18next'; import toast from 'react-hot-toast'; import { LoaderCircle, User, Mail, Phone, Lock, MapPin } from 'lucide-react'; import { Dialog, DialogContent, DialogTitle, DialogDescription } from '@/components/ui/dialog'; import type { GoogleProfilePrefill } from '../marketing/checkout/types'; declare const route: (name: string, params?: Record) => string; export interface RegisterSuccessPayload { user: any | null; redirect?: string | null; pending_purchase?: boolean; } interface RegisterFormProps { packageId?: number; onSuccess?: (payload: RegisterSuccessPayload) => void; privacyHtml: string; locale?: string; prefill?: GoogleProfilePrefill; onClearGoogleProfile?: () => void; } type RegisterFormFields = { username: string; email: string; password: string; password_confirmation: string; first_name: string; last_name: string; address: string; phone: string; privacy_consent: boolean; terms: boolean; package_id: number | null; }; export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale, prefill, onClearGoogleProfile }: RegisterFormProps) { const [privacyOpen, setPrivacyOpen] = useState(false); const [hasTriedSubmit, setHasTriedSubmit] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [prefillApplied, setPrefillApplied] = useState(false); const { t } = useTranslation(['auth', 'common']); const page = usePage<{ errors: Record; locale?: string; auth?: { user?: any | null } }>(); const resolvedLocale = locale ?? page.props.locale ?? 'de'; const { data, setData, errors, clearErrors, reset, setError } = useForm({ username: '', email: '', password: '', password_confirmation: '', first_name: '', last_name: '', address: '', phone: '', privacy_consent: false, terms: false, package_id: packageId || null, }); useEffect(() => { if (hasTriedSubmit && Object.keys(errors).length > 0) { toast.error(Object.values(errors).join(' ')); } }, [errors, hasTriedSubmit]); const registerEndpoint = '/checkout/register'; const namePrefill = useMemo(() => { const rawFirst = prefill?.given_name ?? prefill?.name?.split(' ')[0] ?? ''; const remaining = prefill?.name ? prefill.name.split(' ').slice(1).join(' ') : ''; const rawLast = prefill?.family_name ?? remaining; return { first: rawFirst ?? '', last: rawLast ?? '', }; }, [prefill]); const suggestedUsername = useMemo(() => { if (prefill?.email) { const localPart = prefill.email.split('@')[0]; if (localPart) { return localPart.slice(0, 30); } } const first = prefill?.given_name ?? prefill?.name?.split(' ')[0] ?? ''; const last = prefill?.family_name ?? prefill?.name?.split(' ').slice(1).join(' ') ?? ''; const combined = `${first}${last}`.trim(); if (!combined) { return undefined; } return combined .toLowerCase() .replace(/[^a-z0-9]+/g, '') .slice(0, 30) || undefined; }, [prefill]); useEffect(() => { if (!prefill || prefillApplied) { return; } if (namePrefill.first && !data.first_name) { setData('first_name', namePrefill.first); } if (namePrefill.last && !data.last_name) { setData('last_name', namePrefill.last); } if (prefill.email && !data.email) { setData('email', prefill.email); } if (suggestedUsername && !data.username) { setData('username', suggestedUsername); } setPrefillApplied(true); }, [prefill, namePrefill.first, namePrefill.last, data.first_name, data.last_name, data.email, data.username, prefillApplied, setData, suggestedUsername]); const submit = async (event: React.FormEvent) => { event.preventDefault(); setHasTriedSubmit(true); setIsSubmitting(true); clearErrors(); const body = { ...data, locale: resolvedLocale, package_id: data.package_id ?? packageId ?? null, }; try { const response = await fetch(registerEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-CSRF-TOKEN': (document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement | null)?.content ?? '', }, credentials: 'same-origin', body: JSON.stringify(body), }); if (response.ok) { const json = await response.json(); toast.success(t('register.success_toast', 'Registrierung erfolgreich')); onSuccess?.({ user: json?.user ?? null, redirect: json?.redirect ?? null, pending_purchase: json?.pending_purchase ?? json?.user?.pending_purchase ?? false, }); onClearGoogleProfile?.(); reset(); setHasTriedSubmit(false); return; } if (response.status === 422) { const json = await response.json(); const fieldErrors = json?.errors ?? {}; Object.entries(fieldErrors).forEach(([key, message]) => { if (key in data) { const fieldKey = key as keyof RegisterFormFields; const firstMessage = Array.isArray(message) ? (message[0] as string | undefined) : typeof message === 'string' ? message : undefined; if (firstMessage) { setError(fieldKey, firstMessage); } } }); toast.error(t('register.validation_failed', 'Bitte pruefen Sie Ihre Eingaben.')); return; } toast.error(t('register.unexpected_error', 'Registrierung nicht moeglich.')); } catch (error) { console.error('Register request failed', error); toast.error(t('register.unexpected_error', 'Registrierung nicht moeglich.')); } finally { setIsSubmitting(false); } }; useEffect(() => { if (!hasTriedSubmit) { return; } const errorKeys = Object.keys(errors); if (errorKeys.length === 0) { return; } const firstError = errorKeys[0]; const field = document.querySelector(`[name="${firstError}"]`); if (field) { field.scrollIntoView({ behavior: 'smooth', block: 'center' }); field.focus(); } }, [errors, hasTriedSubmit]); return (
{ setData('first_name', e.target.value); if (e.target.value.trim() && errors.first_name) { clearErrors('first_name'); } }} className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.first_name ? 'border-red-500' : 'border-gray-300'}`} placeholder={t('register.first_name_placeholder')} />
{errors.first_name &&

{errors.first_name}

}
{ setData('last_name', e.target.value); if (e.target.value.trim() && errors.last_name) { clearErrors('last_name'); } }} className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.last_name ? 'border-red-500' : 'border-gray-300'}`} placeholder={t('register.last_name_placeholder')} />
{errors.last_name &&

{errors.last_name}

}
{ setData('email', e.target.value); if (e.target.value.trim() && errors.email) { clearErrors('email'); } }} className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.email ? 'border-red-500' : 'border-gray-300'}`} placeholder={t('register.email_placeholder')} />
{errors.email &&

{errors.email}

}
{ setData('address', e.target.value); if (e.target.value.trim() && errors.address) { clearErrors('address'); } }} className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.address ? 'border-red-500' : 'border-gray-300'}`} placeholder={t('register.address_placeholder')} />
{errors.address &&

{errors.address}

}
{ setData('phone', e.target.value); if (e.target.value.trim() && errors.phone) { clearErrors('phone'); } }} className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.phone ? 'border-red-500' : 'border-gray-300'}`} placeholder={t('register.phone_placeholder')} />
{errors.phone &&

{errors.phone}

}
{ setData('username', e.target.value); if (e.target.value.trim() && errors.username) { clearErrors('username'); } }} className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.username ? 'border-red-500' : 'border-gray-300'}`} placeholder={t('register.username_placeholder')} />
{errors.username &&

{errors.username}

}
{ setData('password', e.target.value); if (e.target.value.trim() && errors.password) { clearErrors('password'); } if (data.password_confirmation && e.target.value === data.password_confirmation) { clearErrors('password_confirmation'); } }} className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.password ? 'border-red-500' : 'border-gray-300'}`} placeholder={t('register.password_placeholder')} />
{errors.password &&

{errors.password}

}
{ setData('password_confirmation', e.target.value); if (e.target.value.trim() && errors.password_confirmation) { clearErrors('password_confirmation'); } if (data.password && e.target.value === data.password) { clearErrors('password_confirmation'); } }} className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.password_confirmation ? 'border-red-500' : 'border-gray-300'}`} placeholder={t('register.confirm_password_placeholder')} />
{errors.password_confirmation &&

{errors.password_confirmation}

}
{ setData('privacy_consent', e.target.checked); setData('terms', e.target.checked); if (e.target.checked && errors.privacy_consent) { clearErrors('privacy_consent'); } if (e.target.checked && errors.terms) { clearErrors('terms'); } }} className="h-4 w-4 text-[#FFB6C1] focus:ring-[#FFB6C1] border-gray-300 rounded" /> {errors.privacy_consent &&

{errors.privacy_consent}

} {errors.terms &&

{errors.terms}

}
{Object.keys(errors).length > 0 && (

{t('register.errors_title')}

    {Object.entries(errors).map(([key, value]) => (
  • {t(`register.errors.${key}`)}: {value}
  • ))}
)} Datenschutzerklärung Lesen Sie unsere Datenschutzerklärung.
); }