186 lines
7.4 KiB
TypeScript
186 lines
7.4 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { useRouter } from 'next/navigation'
|
|
import { trpc } from '@/lib/trpc-client'
|
|
import Link from 'next/link'
|
|
import { SPARTEN } from '@innungsapp/shared'
|
|
|
|
export default function MitgliedNeuPage() {
|
|
const router = useRouter()
|
|
const [form, setForm] = useState({
|
|
name: '',
|
|
betrieb: '',
|
|
sparte: 'Elektrotechnik',
|
|
ort: '',
|
|
telefon: '',
|
|
email: '',
|
|
status: 'aktiv' as const,
|
|
istAusbildungsbetrieb: false,
|
|
seit: new Date().getFullYear(),
|
|
role: 'member' as 'member' | 'admin',
|
|
password: '',
|
|
})
|
|
|
|
const createMutation = trpc.members.create.useMutation({
|
|
onSuccess: () => router.push('/dashboard/mitglieder'),
|
|
})
|
|
|
|
const isPending = createMutation.isPending
|
|
const error = createMutation.error
|
|
|
|
function handleSubmit(e: React.FormEvent) {
|
|
e.preventDefault()
|
|
createMutation.mutate(form)
|
|
}
|
|
|
|
return (
|
|
<div className="max-w-2xl space-y-6">
|
|
<div className="flex items-center gap-4">
|
|
<Link href="/dashboard/mitglieder" className="text-gray-400 hover:text-gray-600">
|
|
← Zurück
|
|
</Link>
|
|
<h1 className="text-2xl font-bold text-gray-900">Mitglied anlegen</h1>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="bg-white rounded-xl border shadow-sm p-6 space-y-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="col-span-2">
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Name *</label>
|
|
<input
|
|
required
|
|
value={form.name}
|
|
onChange={(e) => setForm({ ...form, name: e.target.value })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
/>
|
|
</div>
|
|
<div className="col-span-2">
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Betrieb *</label>
|
|
<input
|
|
required
|
|
value={form.betrieb}
|
|
onChange={(e) => setForm({ ...form, betrieb: e.target.value })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Sparte *</label>
|
|
<select
|
|
value={form.sparte}
|
|
onChange={(e) => setForm({ ...form, sparte: e.target.value })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
>
|
|
{SPARTEN.map((s) => <option key={s}>{s}</option>)}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Ort *</label>
|
|
<input
|
|
required
|
|
value={form.ort}
|
|
onChange={(e) => setForm({ ...form, ort: e.target.value })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">E-Mail *</label>
|
|
<input
|
|
required
|
|
type="email"
|
|
value={form.email}
|
|
onChange={(e) => setForm({ ...form, email: e.target.value })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Telefon</label>
|
|
<input
|
|
type="tel"
|
|
value={form.telefon}
|
|
onChange={(e) => setForm({ ...form, telefon: e.target.value })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Mitglied seit</label>
|
|
<input
|
|
type="number"
|
|
value={form.seit}
|
|
onChange={(e) => setForm({ ...form, seit: Number(e.target.value) })}
|
|
min="1900"
|
|
max="2100"
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Status</label>
|
|
<select
|
|
value={form.status}
|
|
onChange={(e) => setForm({ ...form, status: e.target.value as typeof form.status })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
>
|
|
<option value="aktiv">Aktiv</option>
|
|
<option value="ruhend">Ruhend</option>
|
|
<option value="ausgetreten">Ausgetreten</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Rolle</label>
|
|
<select
|
|
value={form.role}
|
|
onChange={(e) => setForm({ ...form, role: e.target.value as typeof form.role })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
>
|
|
<option value="member">Mitglied</option>
|
|
<option value="admin">Administrator</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Passwort</label>
|
|
<input
|
|
type="password"
|
|
placeholder="Mind. 8 Zeichen"
|
|
value={form.password}
|
|
onChange={(e) => setForm({ ...form, password: e.target.value })}
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500"
|
|
/>
|
|
</div>
|
|
<div className="col-span-2">
|
|
<label className="flex items-center gap-2 cursor-pointer">
|
|
<input
|
|
type="checkbox"
|
|
checked={form.istAusbildungsbetrieb}
|
|
onChange={(e) => setForm({ ...form, istAusbildungsbetrieb: e.target.checked })}
|
|
className="rounded border-gray-300 text-brand-500 focus:ring-brand-500"
|
|
/>
|
|
<span className="text-sm text-gray-700">Ausbildungsbetrieb</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
{error && (
|
|
<p className="text-sm text-red-600 bg-red-50 px-4 py-2 rounded-lg">
|
|
{error.message}
|
|
</p>
|
|
)}
|
|
|
|
<div className="flex gap-3 pt-2">
|
|
<button
|
|
type="submit"
|
|
disabled={isPending}
|
|
className="bg-brand-500 text-white px-6 py-2 rounded-lg text-sm font-medium hover:bg-brand-600 disabled:opacity-60 transition-colors"
|
|
>
|
|
{isPending ? 'Wird gespeichert...' : 'Speichern'}
|
|
</button>
|
|
<Link
|
|
href="/dashboard/mitglieder"
|
|
className="px-6 py-2 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-100 transition-colors"
|
|
>
|
|
Abbrechen
|
|
</Link>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
)
|
|
}
|