252 lines
13 KiB
TypeScript
252 lines
13 KiB
TypeScript
import React from 'react';
|
|
import { useForm, router } from '@inertiajs/react';
|
|
import { Head } from '@inertiajs/react';
|
|
import { LoaderCircle } from 'lucide-react';
|
|
|
|
interface RegisterProps {
|
|
package?: {
|
|
id: number;
|
|
name: string;
|
|
description: string;
|
|
price: number;
|
|
} | null;
|
|
}
|
|
|
|
export default function Register({ package: initialPackage }: RegisterProps) {
|
|
const { data, setData, post, processing, errors } = useForm({
|
|
name: '',
|
|
username: '',
|
|
email: '',
|
|
password: '',
|
|
password_confirmation: '',
|
|
first_name: '',
|
|
last_name: '',
|
|
address: '',
|
|
phone: '',
|
|
privacy_consent: false,
|
|
package_id: initialPackage?.id || null,
|
|
});
|
|
|
|
const submit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
router.post('/register');
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
|
<Head title="Registrieren" />
|
|
<div className="max-w-md w-full space-y-8">
|
|
<div>
|
|
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
|
Registrieren
|
|
</h2>
|
|
{initialPackage && (
|
|
<div className="mt-4 p-4 bg-blue-50 border border-blue-200 rounded-md">
|
|
<h3 className="text-lg font-semibold text-blue-900 mb-2">{initialPackage.name}</h3>
|
|
<p className="text-blue-800 mb-2">{initialPackage.description}</p>
|
|
<p className="text-sm text-blue-700">
|
|
{initialPackage.price === 0 ? 'Kostenlos' : `${initialPackage.price} €`}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<form onSubmit={submit} className="mt-8 space-y-6">
|
|
<div className="space-y-4">
|
|
<div>
|
|
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
|
Name
|
|
</label>
|
|
<input
|
|
id="name"
|
|
name="name"
|
|
type="text"
|
|
required
|
|
autoFocus
|
|
value={data.name}
|
|
onChange={(e) => setData('name', e.target.value)}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="Vollständiger Name"
|
|
/>
|
|
{errors.name && <p className="mt-2 text-sm text-red-600">{errors.name}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="username" className="block text-sm font-medium text-gray-700">
|
|
Benutzername
|
|
</label>
|
|
<input
|
|
id="username"
|
|
name="username"
|
|
type="text"
|
|
required
|
|
value={data.username}
|
|
onChange={(e) => setData('username', e.target.value)}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="Benutzername"
|
|
/>
|
|
{errors.username && <p className="text-sm text-red-600">{errors.username}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
|
|
E-Mail-Adresse
|
|
</label>
|
|
<input
|
|
id="email"
|
|
name="email"
|
|
type="email"
|
|
required
|
|
value={data.email}
|
|
onChange={(e) => setData('email', e.target.value)}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="email@example.com"
|
|
/>
|
|
{errors.email && <p className="text-sm text-red-600">{errors.email}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="first_name" className="block text-sm font-medium text-gray-700">
|
|
Vorname
|
|
</label>
|
|
<input
|
|
id="first_name"
|
|
name="first_name"
|
|
type="text"
|
|
required
|
|
value={data.first_name}
|
|
onChange={(e) => setData('first_name', e.target.value)}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="Vorname"
|
|
/>
|
|
{errors.first_name && <p className="text-sm text-red-600">{errors.first_name}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="last_name" className="block text-sm font-medium text-gray-700">
|
|
Nachname
|
|
</label>
|
|
<input
|
|
id="last_name"
|
|
name="last_name"
|
|
type="text"
|
|
required
|
|
value={data.last_name}
|
|
onChange={(e) => setData('last_name', e.target.value)}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="Nachname"
|
|
/>
|
|
{errors.last_name && <p className="text-sm text-red-600">{errors.last_name}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="address" className="block text-sm font-medium text-gray-700">
|
|
Adresse
|
|
</label>
|
|
<textarea
|
|
id="address"
|
|
name="address"
|
|
required
|
|
value={data.address}
|
|
onChange={(e) => setData('address', e.target.value)}
|
|
rows={3}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="Adresse"
|
|
/>
|
|
{errors.address && <p className="text-sm text-red-600">{errors.address}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="phone" className="block text-sm font-medium text-gray-700">
|
|
Telefon
|
|
</label>
|
|
<input
|
|
id="phone"
|
|
name="phone"
|
|
type="tel"
|
|
required
|
|
value={data.phone}
|
|
onChange={(e) => setData('phone', e.target.value)}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="Telefonnummer"
|
|
/>
|
|
{errors.phone && <p className="text-sm text-red-600">{errors.phone}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
|
|
Passwort
|
|
</label>
|
|
<input
|
|
id="password"
|
|
name="password"
|
|
type="password"
|
|
required
|
|
value={data.password}
|
|
onChange={(e) => setData('password', e.target.value)}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="Passwort"
|
|
/>
|
|
{errors.password && <p className="text-sm text-red-600">{errors.password}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="password_confirmation" className="block text-sm font-medium text-gray-700">
|
|
Passwort bestätigen
|
|
</label>
|
|
<input
|
|
id="password_confirmation"
|
|
name="password_confirmation"
|
|
type="password"
|
|
required
|
|
value={data.password_confirmation}
|
|
onChange={(e) => setData('password_confirmation', e.target.value)}
|
|
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
|
|
placeholder="Passwort bestätigen"
|
|
/>
|
|
{errors.password_confirmation && <p className="text-sm text-red-600">{errors.password_confirmation}</p>}
|
|
</div>
|
|
|
|
<div className="flex items-start">
|
|
<input
|
|
id="privacy_consent"
|
|
name="privacy_consent"
|
|
type="checkbox"
|
|
required
|
|
checked={data.privacy_consent}
|
|
onChange={(e) => setData('privacy_consent', e.target.checked)}
|
|
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
|
/>
|
|
<label htmlFor="privacy_consent" className="ml-2 block text-sm text-gray-900">
|
|
Ich stimme der{' '}
|
|
<a href="/de/datenschutz" className="text-blue-600 hover:underline">
|
|
Datenschutzerklärung
|
|
</a>{' '}
|
|
zu.
|
|
</label>
|
|
{errors.privacy_consent && <p className="mt-2 text-sm text-red-600">{errors.privacy_consent}</p>}
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={processing}
|
|
className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-300 disabled:opacity-50"
|
|
>
|
|
{processing && <LoaderCircle className="h-4 w-4 animate-spin mr-2" />}
|
|
Account erstellen
|
|
</button>
|
|
|
|
<div className="text-center">
|
|
<p className="text-sm text-gray-600">
|
|
Bereits registriert?{' '}
|
|
<a href="/login" className="font-medium text-blue-600 hover:text-blue-500">
|
|
Anmelden
|
|
</a>
|
|
</p>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|