feat: Implement Edit Staff Functionality For Administrators

This commit is contained in:
dhinesh-m24
2026-02-03 13:57:12 +05:30
parent 8461a23adc
commit b25da0fc6a
4 changed files with 52 additions and 71 deletions

View File

@@ -125,7 +125,6 @@ const Login: React.FC = () => {
// Dispatch Redux action to handle login
dispatch(loginUser({ email, password }));
};
console.log(user);
return (
<div className="flex min-h-screen bg-slate-50/50">
{/* Left Side: Hero Image (Hidden on Mobile) */}

View File

@@ -1,7 +1,7 @@
const AdminDashboard = () => {
return (
<div>Dashboard</div>
<div> Admin Dashboard</div>
)
}

View File

@@ -1,14 +1,15 @@
import { useState, useEffect } from "react";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { Button } from "@/common/components/ui/button";
import { Input } from "@/common/components/ui/input";
import { Label } from "@/common/components/ui/label";
import { ArrowLeft, Loader2, Save, Mail, Phone, User, Award, ShieldAlert } from "lucide-react";
import { ArrowLeft, Loader2, Save, Mail, Phone, User, Award } from "lucide-react";
import DashboardLayout from "@/features/layouts/DashboardLayout";
import { useCreateStaff, useGetUserById } from "@/dataconnect-generated/react";
import { dataConnect, auth } from "@/features/auth/firebase";
import { useCreateStaff } from "@/dataconnect-generated/react";
import { dataConnect } from "@/features/auth/firebase";
import { useForm, Controller } from "react-hook-form";
import { Checkbox } from "@/common/components/ui/checkbox";
import { BackgroundCheckStatus } from "@/dataconnect-generated";
const COMMON_SKILLS = [
"Barista",
@@ -30,15 +31,6 @@ interface AddStaffFormData {
export default function AddStaff() {
const navigate = useNavigate();
const [isSubmitting, setIsSubmitting] = useState(false);
// Get current user and their role from DataConnect
const currentUser = auth.currentUser;
const { data: userData, isLoading: isUserLoading } = useGetUserById(
dataConnect,
{ id: currentUser?.uid || "" },
{ enabled: !!currentUser }
);
const { mutateAsync: createStaff } = useCreateStaff(dataConnect);
const { register, handleSubmit, control, formState: { errors } } = useForm<AddStaffFormData>({
@@ -51,22 +43,7 @@ export default function AddStaff() {
}
});
// Check for admin role
const isAdmin = userData?.user?.userRole?.toLowerCase() === 'admin';
useEffect(() => {
if (!isUserLoading && !isAdmin && currentUser) {
// Small delay to allow user to see why they are being redirected if needed,
// but usually immediate is better for security
const timer = setTimeout(() => {
navigate("/staff");
}, 2000);
return () => clearTimeout(timer);
}
}, [isAdmin, isUserLoading, navigate, currentUser]);
const onSubmit = async (data: AddStaffFormData) => {
if (!isAdmin) return;
setIsSubmitting(true);
try {
await createStaff({
@@ -75,7 +52,7 @@ export default function AddStaff() {
email: data.email,
phone: data.phone,
skills: data.skills,
backgroundCheckStatus: "PENDING",
backgroundCheckStatus: BackgroundCheckStatus.PENDING,
initial: `${data.firstName.charAt(0)}${data.lastName.charAt(0)}`.toUpperCase(),
});
navigate("/staff");
@@ -86,39 +63,6 @@ export default function AddStaff() {
}
};
if (isUserLoading) {
return (
<div className="flex flex-col items-center justify-center min-h-screen gap-4">
<Loader2 className="w-10 h-10 animate-spin text-primary" />
<p className="text-muted-foreground font-bold animate-pulse">VERIFYING PERMISSIONS...</p>
</div>
);
}
if (!isAdmin) {
return (
<div className="flex flex-col items-center justify-center min-h-screen gap-6 p-4 text-center">
<div className="w-20 h-20 bg-rose-500/10 rounded-3xl flex items-center justify-center border-2 border-rose-500/20 shadow-xl shadow-rose-500/5">
<ShieldAlert className="w-10 h-10 text-rose-500" />
</div>
<div className="space-y-2">
<h2 className="text-2xl font-black text-foreground">Access Denied</h2>
<p className="text-muted-foreground font-medium max-w-md">
Only administrators can manually onboard new staff members.
You are being redirected to the staff directory.
</p>
</div>
<Button
variant="outline"
onClick={() => navigate("/staff")}
className="rounded-xl font-bold px-8"
>
Return Now
</Button>
</div>
);
}
return (
<DashboardLayout
title="Add New Staff"
@@ -220,8 +164,7 @@ export default function AddStaff() {
<Checkbox
id={skill}
checked={field.value?.includes(skill)}
onChange={(e) => {
const checked = e.target.checked;
onCheckedChange={(checked) => {
const updatedSkills = checked
? [...(field.value || []), skill]
: field.value?.filter((s: string) => s !== skill);
@@ -262,7 +205,6 @@ export default function AddStaff() {
</div>
</div>
</form>
</div>
</DashboardLayout>
</div>= </DashboardLayout>
);
}

View File

@@ -1,23 +1,30 @@
import { useState, useMemo } from "react";
import { useParams, useNavigate } from "react-router-dom";
import { useSelector } from "react-redux";
import type { RootState } from "@/store/store";
import { Button } from "@/common/components/ui/button";
import { ArrowLeft, Loader2, Edit, Save, X, User, FileText, Briefcase, Shield } from "lucide-react";
import { ArrowLeft, Loader2, Edit, Save, X, AlertCircle } from "lucide-react";
import StaffForm from "./components/StaffForm";
import DashboardLayout from "@/features/layouts/DashboardLayout";
import { useGetStaffById, useUpdateStaff } from "@/dataconnect-generated/react";
import { useGetStaffById, useUpdateStaff, useCreateActivityLog } from "@/dataconnect-generated/react";
import { dataConnect } from "@/features/auth/firebase";
import type { Staff } from "../type";
import { Badge } from "@/common/components/ui/badge";
import { ActivityIconType, ActivityType } from "@/dataconnect-generated";
export default function EditStaff() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const [isEditing, setIsEditing] = useState(false);
const { user } = useSelector((state: RootState) => state.auth);
const { data: staffData, isLoading, refetch } = useGetStaffById(dataConnect, { id: id || "" });
const { mutateAsync: updateStaff } = useUpdateStaff(dataConnect);
const { mutateAsync: createActivityLog } = useCreateActivityLog(dataConnect);
const [isSubmitting, setIsSubmitting] = useState(false);
const isAdmin = user?.userRole === 'admin' || user?.userRole === 'ADMIN';
const staff = useMemo(() => {
if (!staffData?.staff) return null;
const s = staffData.staff;
@@ -48,7 +55,7 @@ export default function EditStaff() {
}, [staffData]);
const handleSubmit = async (staffData: Staff) => {
if (!id) return;
if (!id || !isAdmin) return;
setIsSubmitting(true);
try {
await updateStaff({
@@ -69,6 +76,18 @@ export default function EditStaff() {
city: staffData.city,
addres: staffData.address,
});
// Audit Log
await createActivityLog({
userId: user?.uid || "system",
date: new Date().toISOString(),
title: "Staff Profile Updated",
description: `Administrator ${user?.displayName || user?.email} updated professional records for ${staffData.employee_name}`,
activityType: ActivityType.SYSTEM_UPDATE,
iconType: ActivityIconType.CHECK,
iconColor: "emerald",
});
await refetch();
setIsEditing(false);
} catch (error) {
@@ -91,6 +110,27 @@ export default function EditStaff() {
);
}
if (!isAdmin) {
return (
<DashboardLayout title="Access Denied" subtitle="Unauthorized Access">
<div className="flex flex-col items-center justify-center min-h-[40vh] gap-6 bg-card/60 backdrop-blur-md border border-border rounded-3xl p-12 text-center">
<div className="w-20 h-20 bg-rose-500/10 rounded-full flex items-center justify-center text-rose-500 border border-rose-500/20 shadow-lg">
<AlertCircle className="w-10 h-10" />
</div>
<div className="space-y-2">
<h2 className="text-2xl font-black text-foreground">Restricted Access</h2>
<p className="text-muted-foreground max-w-md mx-auto">
Only administrators are authorized to modify staff professional records. Please contact your system administrator if you believe this is an error.
</p>
</div>
<Button onClick={() => navigate("/staff")} variant="outline" leadingIcon={<ArrowLeft />} className="rounded-xl font-bold">
Return to Directory
</Button>
</div>
</DashboardLayout>
);
}
return (
<DashboardLayout
title={isEditing ? `Edit: ${staff?.employee_name || 'Staff Member'}` : staff?.employee_name || 'Staff Member'}