236 lines
6.8 KiB
TypeScript
236 lines
6.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Button } from "@/app/_components/ui/button";
|
|
import {
|
|
Sheet,
|
|
SheetContent,
|
|
SheetDescription,
|
|
SheetFooter,
|
|
SheetHeader,
|
|
SheetTitle,
|
|
} from "@/app/_components/ui/sheet";
|
|
import { Input } from "@/app/_components/ui/input";
|
|
import { Label } from "@/app/_components/ui/label";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/app/_components/ui/select";
|
|
import { User } from "./users-table";
|
|
|
|
interface AddUserSheetProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
onSave: (
|
|
userData: Omit<User, "id" | "lastSignedIn"> & { password: string }
|
|
) => void;
|
|
}
|
|
|
|
export function AddUserSheet({
|
|
open,
|
|
onOpenChange,
|
|
onSave,
|
|
}: AddUserSheetProps) {
|
|
const [userData, setUserData] = useState<
|
|
Omit<User, "id" | "lastSignedIn"> & { password: string }
|
|
>({
|
|
email: "",
|
|
firstName: "",
|
|
lastName: "",
|
|
avatar: "/placeholder.svg?height=40&width=40",
|
|
role: "user",
|
|
status: "active",
|
|
password: "",
|
|
});
|
|
|
|
const [errors, setErrors] = useState<Record<string, string>>({});
|
|
|
|
const validateForm = () => {
|
|
const newErrors: Record<string, string> = {};
|
|
|
|
if (!userData.email) {
|
|
newErrors.email = "Email is required";
|
|
} else if (!/\S+@\S+\.\S+/.test(userData.email)) {
|
|
newErrors.email = "Email is invalid";
|
|
}
|
|
|
|
if (!userData.password) {
|
|
newErrors.password = "Password is required";
|
|
} else if (userData.password.length < 6) {
|
|
newErrors.password = "Password must be at least 6 characters";
|
|
}
|
|
|
|
if (!userData.firstName) {
|
|
newErrors.firstName = "First name is required";
|
|
}
|
|
|
|
if (!userData.lastName) {
|
|
newErrors.lastName = "Last name is required";
|
|
}
|
|
|
|
setErrors(newErrors);
|
|
return Object.keys(newErrors).length === 0;
|
|
};
|
|
|
|
const handleSubmit = () => {
|
|
if (validateForm()) {
|
|
onSave(userData);
|
|
// Reset form
|
|
setUserData({
|
|
email: "",
|
|
firstName: "",
|
|
lastName: "",
|
|
avatar: "/placeholder.svg?height=40&width=40",
|
|
role: "user",
|
|
status: "active",
|
|
password: "",
|
|
});
|
|
setErrors({});
|
|
}
|
|
};
|
|
|
|
const handleInputChange = (field: keyof typeof userData, value: string) => {
|
|
setUserData((prev) => ({ ...prev, [field]: value }));
|
|
// Clear error when field is edited
|
|
if (errors[field]) {
|
|
setErrors((prev) => {
|
|
const newErrors = { ...prev };
|
|
delete newErrors[field];
|
|
return newErrors;
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Sheet open={open} onOpenChange={onOpenChange}>
|
|
<SheetContent className="sm:max-w-md">
|
|
<SheetHeader>
|
|
<SheetTitle>Add New User</SheetTitle>
|
|
<SheetDescription>
|
|
Create a new user account with Supabase authentication.
|
|
</SheetDescription>
|
|
</SheetHeader>
|
|
<div className="grid gap-4 py-4">
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
<Label htmlFor="email" className="text-right">
|
|
Email
|
|
</Label>
|
|
<Input
|
|
id="email"
|
|
value={userData.email}
|
|
onChange={(e) => handleInputChange("email", e.target.value)}
|
|
className="col-span-3"
|
|
/>
|
|
{errors.email && (
|
|
<p className="col-span-3 col-start-2 text-sm text-red-500">
|
|
{errors.email}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
<Label htmlFor="password" className="text-right">
|
|
Password
|
|
</Label>
|
|
<Input
|
|
id="password"
|
|
type="password"
|
|
value={userData.password}
|
|
onChange={(e) => handleInputChange("password", e.target.value)}
|
|
className="col-span-3"
|
|
/>
|
|
{errors.password && (
|
|
<p className="col-span-3 col-start-2 text-sm text-red-500">
|
|
{errors.password}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
<Label htmlFor="firstName" className="text-right">
|
|
First Name
|
|
</Label>
|
|
<Input
|
|
id="firstName"
|
|
value={userData.firstName}
|
|
onChange={(e) => handleInputChange("firstName", e.target.value)}
|
|
className="col-span-3"
|
|
/>
|
|
{errors.firstName && (
|
|
<p className="col-span-3 col-start-2 text-sm text-red-500">
|
|
{errors.firstName}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
<Label htmlFor="lastName" className="text-right">
|
|
Last Name
|
|
</Label>
|
|
<Input
|
|
id="lastName"
|
|
value={userData.lastName}
|
|
onChange={(e) => handleInputChange("lastName", e.target.value)}
|
|
className="col-span-3"
|
|
/>
|
|
{errors.lastName && (
|
|
<p className="col-span-3 col-start-2 text-sm text-red-500">
|
|
{errors.lastName}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
<Label htmlFor="role" className="text-right">
|
|
Role
|
|
</Label>
|
|
<Select
|
|
value={userData.role}
|
|
onValueChange={(value: "admin" | "staff" | "user") =>
|
|
handleInputChange("role", value)
|
|
}
|
|
>
|
|
<SelectTrigger className="col-span-3">
|
|
<SelectValue placeholder="Select a role" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="admin">Admin</SelectItem>
|
|
<SelectItem value="staff">Staff</SelectItem>
|
|
<SelectItem value="user">User</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
<Label htmlFor="status" className="text-right">
|
|
Status
|
|
</Label>
|
|
<Select
|
|
value={userData.status}
|
|
onValueChange={(value: "active" | "inactive") =>
|
|
handleInputChange("status", value)
|
|
}
|
|
>
|
|
<SelectTrigger className="col-span-3">
|
|
<SelectValue placeholder="Select a status" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="active">Active</SelectItem>
|
|
<SelectItem value="inactive">Inactive</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
<SheetFooter>
|
|
<Button type="submit" onClick={handleSubmit}>
|
|
Add User
|
|
</Button>
|
|
</SheetFooter>
|
|
</SheetContent>
|
|
</Sheet>
|
|
);
|
|
}
|