139 lines
4.7 KiB
TypeScript
139 lines
4.7 KiB
TypeScript
import { type FormEvent, useEffect, useState } from 'react'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import { createStaff, fetchStaffFormOptions, type RoleOption } from '../../api/staff'
|
|
import { ReadOnlyBanner, SchoolYearSelector } from '../../components/schoolYear'
|
|
import { useSchoolYear } from '../../context/SchoolYearContext'
|
|
|
|
export function StaffCreatePage() {
|
|
const navigate = useNavigate()
|
|
const { selectedSchoolYearName, isReadOnlyYear } = useSchoolYear()
|
|
const [roles, setRoles] = useState<RoleOption[]>([])
|
|
const [firstname, setFirstname] = useState('')
|
|
const [lastname, setLastname] = useState('')
|
|
const [email, setEmail] = useState('')
|
|
const [phone, setPhone] = useState('')
|
|
const [password, setPassword] = useState('')
|
|
const [roleId, setRoleId] = useState<number>(0)
|
|
const [status, setStatus] = useState('active')
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
useEffect(() => {
|
|
let cancelled = false
|
|
;(async () => {
|
|
try {
|
|
const data = await fetchStaffFormOptions({ school_year: selectedSchoolYearName ?? undefined })
|
|
if (cancelled) return
|
|
const list = data.roles ?? []
|
|
setRoles(list)
|
|
if (list[0]?.id) setRoleId(Number(list[0].id))
|
|
} catch {
|
|
if (!cancelled) setRoles([])
|
|
}
|
|
})()
|
|
return () => {
|
|
cancelled = true
|
|
}
|
|
}, [selectedSchoolYearName])
|
|
|
|
async function onSubmit(e: FormEvent) {
|
|
e.preventDefault()
|
|
if (!selectedSchoolYearName) {
|
|
setError('Please select a school year.')
|
|
return
|
|
}
|
|
if (!roleId) {
|
|
setError('Please select a role.')
|
|
return
|
|
}
|
|
try {
|
|
await createStaff({ firstname, lastname, email, phone, password, role_id: roleId, status, school_year: selectedSchoolYearName })
|
|
navigate(`/app/staff?school_year=${encodeURIComponent(selectedSchoolYearName)}`)
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Unable to create staff.')
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="container mt-4">
|
|
<h2>Add Staff Member</h2>
|
|
<div className="d-flex justify-content-between align-items-center mb-3">
|
|
<div className="text-muted">School year: {selectedSchoolYearName ?? '—'}</div>
|
|
<SchoolYearSelector compact />
|
|
</div>
|
|
<ReadOnlyBanner />
|
|
{error ? <div className="alert alert-danger">{error}</div> : null}
|
|
<form onSubmit={(e) => void onSubmit(e)}>
|
|
<div className="mb-3">
|
|
<label className="form-label">First Name</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={firstname}
|
|
onChange={(e) => setFirstname(e.target.value)}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Last Name</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={lastname}
|
|
onChange={(e) => setLastname(e.target.value)}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Email</label>
|
|
<input
|
|
type="email"
|
|
className="form-control"
|
|
value={email}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Password</label>
|
|
<input
|
|
type="password"
|
|
className="form-control"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Phone</label>
|
|
<input type="tel" className="form-control" value={phone} onChange={(e) => setPhone(e.target.value)} />
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Role</label>
|
|
<select
|
|
className="form-control"
|
|
value={roleId || ''}
|
|
onChange={(e) => setRoleId(Number(e.target.value))}
|
|
required
|
|
>
|
|
{roles.map((role) => (
|
|
<option key={role.id} value={role.id}>
|
|
{role.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Status</label>
|
|
<select className="form-select" value={status} onChange={(e) => setStatus(e.target.value)}>
|
|
<option value="active">Active</option>
|
|
<option value="inactive">Inactive</option>
|
|
</select>
|
|
</div>
|
|
<button type="submit" className="btn btn-success" disabled={isReadOnlyYear || !selectedSchoolYearName}>
|
|
Create
|
|
</button>
|
|
</form>
|
|
</div>
|
|
)
|
|
}
|