Files
frontend/app/(manager)/manager/create-staff/page.tsx
T
2026-05-08 19:58:07 +07:00

171 lines
5.3 KiB
TypeScript

"use client";
import { Button, TextInput } from "@/components/atoms";
import Link from "next/link";
import { useState } from "react";
interface FormState {
name: string;
phone: string;
password: string;
}
interface FormErrors {
name?: string;
phone?: string;
password?: string;
}
const PHONE_RE = /^0\d{9}$/;
function validate(data: FormState): FormErrors {
const errors: FormErrors = {};
if (!data.name.trim()) errors.name = "Name is required";
if (!data.phone.trim()) {
errors.phone = "Phone number is required";
} else if (!PHONE_RE.test(data.phone.trim())) {
errors.phone = "Must be 10 digits starting with 0 (e.g. 0912345678)";
}
if (!data.password) {
errors.password = "Password is required";
} else if (data.password.length < 6) {
errors.password = "Password must be at least 6 characters";
}
return errors;
}
export default function CreateStaffPage() {
const [form, setForm] = useState<FormState>({ name: "", phone: "", password: "" });
const [errors, setErrors] = useState<FormErrors>({});
const [apiError, setApiError] = useState<string | null>(null);
const [success, setSuccess] = useState(false);
const [loading, setLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
const { name, value } = e.target;
setForm((prev) => ({ ...prev, [name]: value }));
setErrors((prev) => ({ ...prev, [name]: undefined }));
setApiError(null);
setSuccess(false);
}
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
const validation = validate(form);
if (Object.keys(validation).length > 0) {
setErrors(validation);
return;
}
setLoading(true);
setApiError(null);
try {
const res = await fetch("/api/Staff/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: form.name.trim(),
phone: form.phone.trim(),
password: form.password,
}),
});
if (res.ok) {
setSuccess(true);
setForm({ name: "", phone: "", password: "" });
setErrors({});
} else {
const text = await res.text();
setApiError(text || "Failed to create account. Please try again.");
}
} catch {
setApiError("Connection error. Please check your network and try again.");
} finally {
setLoading(false);
}
}
return (
<div className="flex min-h-screen items-start justify-center bg-(--color-background) px-4 py-10">
<div className="w-full max-w-md">
<div className="mb-6">
<Link
href="/manager"
className="mb-4 inline-flex items-center gap-1.5 text-sm text-(--color-text-muted) no-underline transition hover:text-(--color-primary)"
>
<i className="fa-solid fa-arrow-left"></i>
Back to Dashboard
</Link>
<h1 className="text-foreground text-2xl font-bold">Create Staff Account</h1>
<p className="mt-1 text-sm text-(--color-text-muted)">
Fill in the details below to register a new staff member.
</p>
</div>
{success && (
<div className="mb-4 flex items-center gap-2 rounded-xl bg-green-50 px-4 py-3 text-sm font-medium text-green-700">
<i className="fa-solid fa-circle-check"></i>
Staff account created successfully.
</div>
)}
{apiError && (
<div className="mb-4 flex items-center gap-2 rounded-xl bg-red-50 px-4 py-3 text-sm font-medium text-red-600">
<i className="fa-solid fa-circle-exclamation"></i>
{apiError}
</div>
)}
<div className="rounded-2xl border border-(--color-border-light) bg-white p-8 shadow-sm">
<form onSubmit={handleSubmit} className="space-y-5" noValidate>
<TextInput
label="Full Name"
name="name"
value={form.name}
onChange={handleChange}
placeholder="Enter staff's full name"
error={errors.name}
autoComplete="name"
/>
<TextInput
label="Phone Number"
name="phone"
value={form.phone}
onChange={handleChange}
placeholder="0xxxxxxxxx"
error={errors.phone}
inputMode="tel"
autoComplete="tel"
/>
<TextInput
label="Password"
name="password"
type={showPassword ? "text" : "password"}
value={form.password}
onChange={handleChange}
placeholder="At least 6 characters"
error={errors.password}
icon={showPassword ? "fa-eye-slash" : "fa-eye"}
onIconClick={() => setShowPassword((v) => !v)}
autoComplete="new-password"
/>
<Button
type="submit"
variant="primary"
size="lg"
icon="fa-user-plus"
disabled={loading}
className="mt-2 w-full"
>
{loading ? "Creating..." : "Create Account"}
</Button>
</form>
</div>
</div>
</div>
);
}