183 lines
6.7 KiB
TypeScript
183 lines
6.7 KiB
TypeScript
'use client'
|
||
|
||
import { useState } from 'react'
|
||
import { useRouter } from 'next/navigation'
|
||
import { trpc } from '@/lib/trpc-client'
|
||
import { getTrpcErrorMessage } from '@/lib/trpc-error'
|
||
import Link from 'next/link'
|
||
|
||
export default function StelleNeuPage() {
|
||
const router = useRouter()
|
||
|
||
const { data: members } = trpc.members.list.useQuery({})
|
||
const createMutation = trpc.stellen.createForMember.useMutation({
|
||
onSuccess: () => router.push('/dashboard/stellen'),
|
||
})
|
||
|
||
const [form, setForm] = useState({
|
||
memberId: '',
|
||
sparte: '',
|
||
stellenAnz: 1,
|
||
verguetung: '',
|
||
lehrjahr: '',
|
||
beschreibung: '',
|
||
kontaktEmail: '',
|
||
kontaktName: '',
|
||
})
|
||
|
||
function handleSubmit(e: React.FormEvent) {
|
||
e.preventDefault()
|
||
if (!form.memberId) return
|
||
createMutation.mutate({
|
||
...form,
|
||
stellenAnz: Number(form.stellenAnz),
|
||
verguetung: form.verguetung || undefined,
|
||
lehrjahr: form.lehrjahr || undefined,
|
||
beschreibung: form.beschreibung || undefined,
|
||
kontaktName: form.kontaktName || undefined,
|
||
})
|
||
}
|
||
|
||
const inputClass =
|
||
'w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-transparent'
|
||
|
||
return (
|
||
<div className="max-w-2xl space-y-6">
|
||
<div className="flex items-center gap-3">
|
||
<Link href="/dashboard/stellen" className="text-xs text-gray-400 hover:text-gray-600 uppercase tracking-wide">
|
||
← Zurück
|
||
</Link>
|
||
<span className="text-gray-200">/</span>
|
||
<h1 className="text-2xl font-bold text-gray-900">Stelle anlegen</h1>
|
||
</div>
|
||
|
||
<form onSubmit={handleSubmit} className="bg-white rounded-lg border p-6 space-y-6">
|
||
{/* Betrieb */}
|
||
<div>
|
||
<p className="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3">Betrieb</p>
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">Mitglied / Betrieb *</label>
|
||
<select
|
||
required
|
||
value={form.memberId}
|
||
onChange={(e) => {
|
||
const selected = members?.find((m) => m.id === e.target.value)
|
||
setForm({ ...form, memberId: e.target.value, sparte: selected?.sparte ?? form.sparte })
|
||
}}
|
||
className={inputClass}
|
||
>
|
||
<option value="">Mitglied auswählen...</option>
|
||
{members?.map((m) => (
|
||
<option key={m.id} value={m.id}>
|
||
{m.betrieb} – {m.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Stellendetails */}
|
||
<div className="border-t pt-5">
|
||
<p className="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3">Stellendetails</p>
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">Sparte *</label>
|
||
<input
|
||
required
|
||
value={form.sparte}
|
||
onChange={(e) => setForm({ ...form, sparte: e.target.value })}
|
||
placeholder="z.B. Elektrotechnik"
|
||
className={inputClass}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">Anzahl Stellen</label>
|
||
<input
|
||
type="number"
|
||
min={1}
|
||
value={form.stellenAnz}
|
||
onChange={(e) => setForm({ ...form, stellenAnz: Number(e.target.value) })}
|
||
className={inputClass}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">Lehrjahr</label>
|
||
<input
|
||
value={form.lehrjahr}
|
||
onChange={(e) => setForm({ ...form, lehrjahr: e.target.value })}
|
||
placeholder="z.B. 1. Lehrjahr"
|
||
className={inputClass}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">Vergütung</label>
|
||
<input
|
||
value={form.verguetung}
|
||
onChange={(e) => setForm({ ...form, verguetung: e.target.value })}
|
||
placeholder="z.B. 650 € / Monat"
|
||
className={inputClass}
|
||
/>
|
||
</div>
|
||
<div className="col-span-2">
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">Beschreibung</label>
|
||
<textarea
|
||
rows={3}
|
||
value={form.beschreibung}
|
||
onChange={(e) => setForm({ ...form, beschreibung: e.target.value })}
|
||
placeholder="Aufgaben, Anforderungen, ..."
|
||
className={inputClass}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Kontakt */}
|
||
<div className="border-t pt-5">
|
||
<p className="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3">Kontakt</p>
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">Kontakt-E-Mail *</label>
|
||
<input
|
||
type="email"
|
||
required
|
||
value={form.kontaktEmail}
|
||
onChange={(e) => setForm({ ...form, kontaktEmail: e.target.value })}
|
||
placeholder="bewerbung@betrieb.de"
|
||
className={inputClass}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">Ansprechpartner</label>
|
||
<input
|
||
value={form.kontaktName}
|
||
onChange={(e) => setForm({ ...form, kontaktName: e.target.value })}
|
||
placeholder="Max Mustermann"
|
||
className={inputClass}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{createMutation.error && (
|
||
<p className="text-sm text-red-600 bg-red-50 px-4 py-2 rounded-lg">
|
||
{getTrpcErrorMessage(createMutation.error)}
|
||
</p>
|
||
)}
|
||
|
||
<div className="flex gap-3 pt-2 border-t">
|
||
<button
|
||
type="submit"
|
||
disabled={createMutation.isPending || !form.memberId}
|
||
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"
|
||
>
|
||
{createMutation.isPending ? 'Wird gespeichert...' : 'Stelle anlegen'}
|
||
</button>
|
||
<Link href="/dashboard/stellen" 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>
|
||
)
|
||
}
|