feat: Implement Staff Detail View

This commit is contained in:
dhinesh-m24
2026-01-29 17:24:54 +05:30
parent 9e19ee7592
commit 48bb1c457c
5 changed files with 731 additions and 341 deletions

View File

@@ -4,6 +4,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import AppRoutes from './routes';
import { store } from './store/store';
import { initializeAuthPersistence } from './services/authService';
import AuthInitializer from './features/auth/AuthInitializer';
// Initialize the QueryClient
const queryClient = new QueryClient();
@@ -13,13 +14,16 @@ initializeAuthPersistence();
/**
* Root Application Component.
* Wraps the app with Redux Provider and React Query Provider.
* Wraps the app with Redux Provider, React Query Provider, and AuthInitializer.
* AuthInitializer ensures auth state is restored from persistence before routes are rendered.
*/
const App: React.FC = () => {
return (
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<AuthInitializer>
<AppRoutes />
</AuthInitializer>
</QueryClientProvider>
</Provider>
);

View File

@@ -0,0 +1,44 @@
import React from 'react';
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { checkAuthStatus } from './authSlice';
import type { RootState, AppDispatch } from '../../store/store';
interface AuthInitializerProps {
children: React.ReactNode;
}
/**
* AuthInitializer Component
* Initializes authentication state from Firebase persistence on app load
* Shows a loading screen until the initial auth check is complete
* This prevents premature redirect to login before the persisted session is restored
*/
const AuthInitializer: React.FC<AuthInitializerProps> = ({ children }) => {
const dispatch = useDispatch<AppDispatch>();
const { isInitialized } = useSelector((state: RootState) => state.auth);
useEffect(() => {
// Perform initial auth check when component mounts
// This restores the persisted session from Firebase
dispatch(checkAuthStatus());
}, [dispatch]);
// Show loading state while initializing auth
if (!isInitialized) {
return (
<div className="flex items-center justify-center h-screen bg-slate-50">
<div className="text-center">
<div className="inline-block">
<div className="w-8 h-8 border-4 border-slate-200 border-t-primary rounded-full animate-spin"></div>
</div>
<p className="mt-4 text-slate-600">Loading application...</p>
</div>
</div>
);
}
return <>{children}</>;
};
export default AuthInitializer;

View File

@@ -17,6 +17,7 @@ interface AuthState {
isAuthenticated: boolean;
status: "idle" | "loading" | "succeeded" | "failed";
error: string | null;
isInitialized: boolean; // Track whether initial auth check has completed
}
const initialState: AuthState = {
@@ -24,6 +25,7 @@ const initialState: AuthState = {
isAuthenticated: false,
status: "idle",
error: null,
isInitialized: false, // Start as false until initial auth check completes
};
/**
@@ -154,6 +156,9 @@ const authSlice = createSlice({
// Check auth status thunk
builder
.addCase(checkAuthStatus.pending, (state) => {
state.status = "loading";
})
.addCase(checkAuthStatus.fulfilled, (state, action) => {
if (action.payload) {
state.user = action.payload;
@@ -163,6 +168,11 @@ const authSlice = createSlice({
state.isAuthenticated = false;
}
state.status = "idle";
state.isInitialized = true; // Mark initialization as complete
})
.addCase(checkAuthStatus.rejected, (state) => {
state.isInitialized = true; // Mark initialization as complete even on error
state.isAuthenticated = false;
});
},
});

View File

@@ -13,6 +13,7 @@ export default function EditStaff() {
const [staff, setStaff] = useState<Staff | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isEditing, setIsEditing] = useState(false);
useEffect(() => {
const fetchStaff = async () => {
@@ -41,7 +42,8 @@ export default function EditStaff() {
setIsSubmitting(true);
try {
await workforceService.entities.Staff.update(id, staffData);
navigate("/staff");
setStaff(staffData);
setIsEditing(false);
} catch (error) {
console.error("Failed to update staff", error);
} finally {
@@ -49,6 +51,10 @@ export default function EditStaff() {
}
};
const handleCancel = () => {
setIsEditing(false);
};
if (isLoading) {
return (
<div className="flex flex-col items-center justify-center min-h-[60vh] gap-4">
@@ -60,7 +66,7 @@ export default function EditStaff() {
return (
<DashboardLayout
title={`Edit: ${staff?.employee_name || 'Staff Member'}`}
title={isEditing ? `Edit: ${staff?.employee_name || 'Staff Member'}` : staff?.employee_name || 'Staff Member'}
subtitle={`Management of ${staff?.employee_name}'s professional records`}
backAction={
<Button
@@ -74,11 +80,42 @@ export default function EditStaff() {
}
>
{staff && (
<div>
{!isEditing && (
<div className="mb-6 flex justify-end">
<Button onClick={() => setIsEditing(true)} variant="secondary">
Edit
</Button>
</div>
)}
{isEditing && (
<div className="mb-6 flex justify-end gap-2">
<Button
onClick={handleCancel}
variant="outline"
disabled={isSubmitting}
>
Cancel
</Button>
<Button
onClick={() => {
// Trigger form submission by dispatching event or calling form submit
const form = document.querySelector('form');
if (form) form.requestSubmit();
}}
disabled={isSubmitting}
>
{isSubmitting ? 'Saving...' : 'Save'}
</Button>
</div>
)}
<StaffForm
staff={staff}
onSubmit={handleSubmit}
isSubmitting={isSubmitting}
disabled={!isEditing}
/>
</div>
)}
</DashboardLayout>
);

View File

@@ -7,9 +7,9 @@ import { Button } from "@/common/components/ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/common/components/ui/select";
import { Checkbox } from "@/common/components/ui/checkbox";
import {
Save, Loader2, User, Activity, MapPin,
Calendar, ChevronRight, FileText,
Shield, Star, Info
Save, Loader2, User, FileText, Briefcase,
Calendar, ChevronRight, Shield, Star, Info,
Mail, Phone, MapPin, Award, Clock, AlertCircle
} from "lucide-react";
import { AnimatePresence } from "framer-motion";
import type { Staff } from "../../type";
@@ -19,12 +19,13 @@ interface StaffFormProps {
staff?: Staff;
onSubmit: (data: Omit<Staff, 'id'>) => Promise<void>;
isSubmitting: boolean;
disabled?: boolean;
}
type TabType = "general" | "performance" | "location" | "additional";
type TabType = "overview" | "documents" | "work_history" | "compliance";
export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormProps) {
const [activeTab, setActiveTab] = useState<TabType>("general");
export default function StaffForm({ staff, onSubmit, isSubmitting, disabled = false }: StaffFormProps) {
const [activeTab, setActiveTab] = useState<TabType>("overview");
const { register, handleSubmit, control, reset } = useForm<Staff>({
defaultValues: staff || {
@@ -55,7 +56,7 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
action: "",
notes: "",
accounting_comments: "",
rating: 0,
averageRating: 0,
shift_coverage_percentage: 100,
cancellation_count: 0,
no_show_count: 0,
@@ -75,10 +76,10 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
};
const tabs: { id: TabType; label: string; icon: React.ReactNode }[] = [
{ id: "general", label: "General Info", icon: <User className="w-4 h-4" /> },
{ id: "performance", label: "Performance", icon: <Activity className="w-4 h-4" /> },
{ id: "location", label: "Location", icon: <MapPin className="w-4 h-4" /> },
{ id: "additional", label: "Other", icon: <Info className="w-4 h-4" /> },
{ id: "overview", label: "Overview", icon: <User className="w-4 h-4" /> },
{ id: "documents", label: "Documents", icon: <FileText className="w-4 h-4" /> },
{ id: "work_history", label: "Work History", icon: <Briefcase className="w-4 h-4" /> },
{ id: "compliance", label: "Compliance", icon: <Shield className="w-4 h-4" /> },
];
return (
@@ -125,22 +126,22 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
{/* Content Area */}
<div className="flex-1 space-y-6">
<AnimatePresence mode="wait">
{activeTab === "general" && (
{activeTab === "overview" && (
<TabContent
id="general"
title="Basic Information"
id="overview"
title="Staff Overview"
icon={<User className="w-5 h-5" />}
className="p-8 grid grid-cols-1 md:grid-cols-2 gap-8"
className="p-8 space-y-8"
footer={
<div className="bg-primary/5 p-6 rounded-3xl border border-primary/10 flex items-center justify-between">
<div>
<h4 className="font-bold text-foreground">Next Step: Performance</h4>
<p className="text-sm text-muted-foreground">Define reliability and coverage metrics.</p>
<h4 className="font-bold text-foreground">Next Step: Documents</h4>
<p className="text-sm text-muted-foreground">Upload and manage staff documentation.</p>
</div>
<Button
type="button"
variant="ghost"
onClick={() => setActiveTab("performance")}
onClick={() => setActiveTab("documents")}
className="hover:bg-primary/10 hover:text-primary rounded-xl font-bold transition-premium"
>
Continue
@@ -149,10 +150,18 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
</div>
}
>
{/* Basic Information */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<User className="w-4 h-4" />
BASIC INFORMATION
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Name <span className="text-rose-500">*</span></Label>
<Input
{...register("employee_name", { required: true })}
disabled={disabled}
className="font-medium"
placeholder="John Doe"
/>
@@ -162,20 +171,53 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Initials</Label>
<Input
{...register("initial")}
disabled={disabled}
maxLength={3}
className="font-medium "
className="font-medium"
placeholder="JD"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Email</Label>
<Input
{...register("email")}
disabled={disabled}
type="email"
leadingIcon={<Mail />}
className="font-medium"
placeholder="j.doe@example.com"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Contact Number</Label>
<Input
{...register("contact_number")}
disabled={disabled}
leadingIcon={<Phone />}
className="font-medium"
placeholder="+1 (555) 000-0000"
/>
</div>
</div>
</div>
{/* Skills & Position */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<Award className="w-4 h-4" />
SKILLS & POSITION
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Primary Skill</Label>
<Controller
name="position"
control={control}
render={({ field }) => (
<Select onValueChange={field.onChange} value={field.value}>
<SelectTrigger className="font-medium">
<Select onValueChange={disabled ? undefined : field.onChange} value={field.value} disabled={disabled}>
<SelectTrigger className="font-medium" disabled={disabled}>
<SelectValue placeholder="Select primary skill" />
</SelectTrigger>
<SelectContent className="rounded-xl glass">
@@ -191,14 +233,24 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Secondary Skill</Label>
<Input
{...register("position_2")}
disabled={disabled}
className="font-medium"
placeholder="Additional skills"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Skill Level</Label>
<Controller
name="profile_type"
control={control}
render={({ field }) => (
<Select onValueChange={field.onChange} value={field.value}>
<SelectTrigger className="font-medium">
<Select onValueChange={disabled ? undefined : field.onChange} value={field.value} disabled={disabled}>
<SelectTrigger className="font-medium" disabled={disabled}>
<SelectValue placeholder="Select level" />
</SelectTrigger>
<SelectContent className="rounded-xl glass">
@@ -211,34 +263,14 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Email</Label>
<Input
{...register("email")}
type="email"
leadingIcon={<FileText />}
className="font-medium"
placeholder="j.doe@example.com"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Contact Number</Label>
<Input
{...register("contact_number")}
className="font-medium"
placeholder="+1 (555) 000-0000"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Employment Type</Label>
<Controller
name="employment_type"
control={control}
render={({ field }) => (
<Select onValueChange={field.onChange} value={field.value}>
<SelectTrigger className="font-medium">
<Select onValueChange={disabled ? undefined : field.onChange} value={field.value} disabled={disabled}>
<SelectTrigger className="font-medium" disabled={disabled}>
<SelectValue placeholder="Select type" />
</SelectTrigger>
<SelectContent className="rounded-xl glass">
@@ -251,138 +283,79 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
)}
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Reporting Manager</Label>
<Controller
name="manager"
control={control}
render={({ field }) => (
<Select onValueChange={field.onChange} value={field.value}>
<SelectTrigger className="font-medium">
<SelectValue placeholder="Select manager" />
</SelectTrigger>
<SelectContent className="rounded-xl glass">
<SelectItem value="Fernando">Fernando</SelectItem>
<SelectItem value="Maria">Maria</SelectItem>
<SelectItem value="Paola">Paola</SelectItem>
</SelectContent>
</Select>
)}
/>
</div>
</TabContent>
)}
</div>
{activeTab === "performance" && (
<TabContent
id="performance"
title="Performance Metrics"
icon={<Activity className="w-5 h-5" />}
className="p-8 space-y-8"
>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div className="space-y-4">
<div className="flex items-center gap-2">
{/* Rating & Performance Overview */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<Star className="w-4 h-4" />
RATING & PERFORMANCE
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="p-6 bg-amber-50 dark:bg-amber-950/20 rounded-2xl border border-amber-200 dark:border-amber-900">
<div className="flex items-center gap-2 mb-2">
<Star className="w-4 h-4 text-amber-500" />
<Label className="text-xs font-black text-muted-foreground/80">Rating (0-5)</Label>
<Label className="text-xs font-black text-amber-700 dark:text-amber-400">Average Rating</Label>
</div>
<Input
{...register("rating", { valueAsNumber: true })}
{...register("averageRating", { valueAsNumber: true })}
disabled={disabled}
type="number"
step="0.1"
min="0"
max="5"
className="h-14 rounded-2xl text-2xl font-black text-center"
className="h-12 rounded-xl text-xl font-black text-center bg-white dark:bg-amber-950/40"
/>
</div>
<div className="space-y-4">
<div className="flex items-center gap-2">
<div className="p-6 bg-emerald-50 dark:bg-emerald-950/20 rounded-2xl border border-emerald-200 dark:border-emerald-900">
<div className="flex items-center gap-2 mb-2">
<Shield className="w-4 h-4 text-emerald-500" />
<Label className="text-xs font-black text-muted-foreground/80">Reliability %</Label>
<Label className="text-xs font-black text-emerald-700 dark:text-emerald-400">Reliability Score</Label>
</div>
<Input
{...register("reliability_score", { valueAsNumber: true })}
disabled={disabled}
type="number"
min="0"
max="100"
className="h-14 rounded-2xl text-2xl font-black text-center"
className="h-12 rounded-xl text-xl font-black text-center bg-white dark:bg-emerald-950/40"
/>
</div>
<div className="space-y-4">
<div className="flex items-center gap-2">
<TrendingUp className="w-4 h-4 text-primary" />
<Label className="text-xs font-black text-muted-foreground/80">Coverage %</Label>
<div className="p-6 bg-blue-50 dark:bg-blue-950/20 rounded-2xl border border-blue-200 dark:border-blue-900">
<div className="flex items-center gap-2 mb-2">
<TrendingUp className="w-4 h-4 text-blue-500" />
<Label className="text-xs font-black text-blue-700 dark:text-blue-400">Coverage %</Label>
</div>
<Input
{...register("shift_coverage_percentage", { valueAsNumber: true })}
disabled={disabled}
type="number"
min="0"
max="100"
className="h-14 rounded-2xl text-2xl font-black text-center"
className="h-12 rounded-xl text-xl font-black text-center bg-white dark:bg-blue-950/40"
/>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 pt-4">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Cancellations</Label>
<Input
{...register("cancellation_count", { valueAsNumber: true })}
type="number"
className="font-medium"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">No Shows</Label>
<Input
{...register("no_show_count", { valueAsNumber: true })}
type="number"
className="font-medium"
/>
</div>
</div>
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40 flex items-center justify-between">
<div className="flex items-center gap-4">
<Controller
name="invoiced"
control={control}
render={({ field }) => (
<Checkbox
id="invoiced"
checked={field.value}
onChange={(e) => field.onChange(e.target.checked)}
className="w-6 h-6 rounded-lg border-2 border-primary/20 data-[state=checked]:bg-primary data-[state=checked]:border-primary"
/>
)}
/>
{/* Location & Department */}
<div>
<Label htmlFor="invoiced" className="font-black text-foreground cursor-pointer">Verified Invoicing</Label>
<p className="text-xs text-muted-foreground font-medium">Mark this member as verified for automatic invoicing.</p>
</div>
</div>
</div>
</TabContent>
)}
{activeTab === "location" && (
<TabContent
id="location"
title="Deployment & Location"
icon={<MapPin className="w-5 h-5" />}
className="p-8 grid grid-cols-1 md:grid-cols-2 gap-8"
>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<MapPin className="w-4 h-4" />
LOCATION & DEPARTMENT
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Department</Label>
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Department</Label>
<Controller
name="department"
control={control}
render={({ field }) => (
<Select onValueChange={field.onChange} value={field.value}>
<SelectTrigger>
<Select onValueChange={disabled ? undefined : field.onChange} value={field.value} disabled={disabled}>
<SelectTrigger disabled={disabled}>
<SelectValue placeholder="Select department" />
</SelectTrigger>
<SelectContent className="rounded-xl glass">
@@ -397,39 +370,338 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Primary City</Label>
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Primary City</Label>
<Input
{...register("city")}
disabled={disabled}
className="font-medium"
placeholder="e.g., San Francisco"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Hub Site</Label>
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Hub Location</Label>
<Input
{...register("hub_location")}
disabled={disabled}
className="font-medium"
/>
</div>
<div className="space-y-2 md:col-span-2">
<Label className="text-xs font-black text-muted-foreground/80">Detailed Address</Label>
<Textarea
{...register("address")}
className="font-medium"
placeholder="Street address, building, etc."
placeholder="Primary hub site"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">English Fluency</Label>
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Reporting Manager</Label>
<Controller
name="manager"
control={control}
render={({ field }) => (
<Select onValueChange={disabled ? undefined : field.onChange} value={field.value} disabled={disabled}>
<SelectTrigger className="font-medium" disabled={disabled}>
<SelectValue placeholder="Select manager" />
</SelectTrigger>
<SelectContent className="rounded-xl glass">
<SelectItem value="Fernando">Fernando</SelectItem>
<SelectItem value="Maria">Maria</SelectItem>
<SelectItem value="Paola">Paola</SelectItem>
</SelectContent>
</Select>
)}
/>
</div>
</div>
</div>
</TabContent>
)}
{activeTab === "documents" && (
<TabContent
id="documents"
title="Staff Documents"
icon={<FileText className="w-5 h-5" />}
className="p-8 space-y-8"
>
{/* Document Upload Section */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<FileText className="w-4 h-4" />
REQUIRED DOCUMENTS
</h3>
<div className="space-y-4">
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40">
<div className="flex items-center justify-between mb-2">
<Label className="font-bold text-foreground">I-9 Form</Label>
<span className="text-xs px-2 py-1 bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400 rounded-lg font-bold">
Pending
</span>
</div>
<p className="text-xs text-muted-foreground">Employment eligibility verification</p>
</div>
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40">
<div className="flex items-center justify-between mb-2">
<Label className="font-bold text-foreground">W-4 Form</Label>
<span className="text-xs px-2 py-1 bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400 rounded-lg font-bold">
Pending
</span>
</div>
<p className="text-xs text-muted-foreground">Tax withholding information</p>
</div>
</div>
</div>
{/* Certifications */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<Award className="w-4 h-4" />
CERTIFICATIONS
</h3>
<div className="space-y-4">
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40">
<div className="flex items-center justify-between mb-2">
<Label className="font-bold text-foreground">Food Handler Certificate</Label>
<span className="text-xs px-2 py-1 bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400 rounded-lg font-bold">
Valid
</span>
</div>
<p className="text-xs text-muted-foreground">Expires: 12/31/2026</p>
</div>
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40">
<div className="flex items-center justify-between mb-2">
<Label className="font-bold text-foreground">Additional Certifications</Label>
<Button type="button" variant="outline" size="sm" disabled={disabled}>
Upload
</Button>
</div>
<p className="text-xs text-muted-foreground">Add any additional certifications or licenses</p>
</div>
</div>
</div>
{/* Notes */}
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Document Notes</Label>
<Textarea
{...register("notes")}
disabled={disabled}
placeholder="Notes about uploaded documents, missing items, or follow-ups needed..."
className="min-h-[100px]"
/>
</div>
</TabContent>
)}
{activeTab === "work_history" && (
<TabContent
id="work_history"
title="Work History"
icon={<Briefcase className="w-5 h-5" />}
className="p-8 space-y-8"
>
{/* Shift Statistics */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<Clock className="w-4 h-4" />
SHIFT STATISTICS
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40">
<Label className="text-xs font-black text-muted-foreground/80 mb-2 block">Total Shifts</Label>
<Input
{...register("total_shifts", { valueAsNumber: true })}
disabled={disabled}
type="number"
className="h-12 rounded-xl text-xl font-black text-center"
/>
</div>
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40">
<Label className="text-xs font-black text-muted-foreground/80 mb-2 block">Cancellations</Label>
<Input
{...register("cancellation_count", { valueAsNumber: true })}
disabled={disabled}
type="number"
className="h-12 rounded-xl text-xl font-black text-center"
/>
</div>
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40">
<Label className="text-xs font-black text-muted-foreground/80 mb-2 block">No Shows</Label>
<Input
{...register("no_show_count", { valueAsNumber: true })}
disabled={disabled}
type="number"
className="h-12 rounded-xl text-xl font-black text-center"
/>
</div>
</div>
</div>
{/* Schedule Information */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<Calendar className="w-4 h-4" />
SCHEDULE INFORMATION
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Last Check-in</Label>
<Input
{...register("check_in")}
disabled={disabled}
type="date"
leadingIcon={<Calendar />}
className="font-medium"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Schedule Days</Label>
<Input
{...register("schedule_days")}
disabled={disabled}
className="font-medium"
placeholder="e.g., M/W/F Only"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Event Location</Label>
<Input
{...register("event_location")}
disabled={disabled}
className="font-medium"
placeholder="Primary event location"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Track</Label>
<Input
{...register("track")}
disabled={disabled}
className="font-medium"
placeholder="Assignment track"
/>
</div>
</div>
</div>
{/* Assignment Details */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<Briefcase className="w-4 h-4" />
ASSIGNMENT DETAILS
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Replaced By</Label>
<Input
{...register("replaced_by")}
disabled={disabled}
className="font-medium"
placeholder="Staff member name"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Action Status</Label>
<Input
{...register("action")}
disabled={disabled}
className="font-medium"
placeholder="Current action status"
/>
</div>
</div>
</div>
{/* Work History Notes */}
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Work History Notes</Label>
<Textarea
{...register("accounting_comments")}
disabled={disabled}
placeholder="Notes about work history, patterns, or observations..."
className="min-h-[100px]"
/>
</div>
</TabContent>
)}
{activeTab === "compliance" && (
<TabContent
id="compliance"
title="Compliance & Verification"
icon={<Shield className="w-5 h-5" />}
className="p-8 space-y-8"
>
{/* Verification Status */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<Shield className="w-4 h-4" />
VERIFICATION STATUS
</h3>
<div className="space-y-4">
<div className="p-6 bg-secondary/20 rounded-2xl border border-border/40 flex items-center justify-between">
<div className="flex items-center gap-4">
<Controller
name="invoiced"
control={control}
render={({ field }) => (
<Checkbox
id="invoiced"
disabled={disabled}
checked={field.value}
onChange={(e) => field.onChange(e.target.checked)}
className="w-6 h-6 rounded-lg border-2 border-primary/20 data-[state=checked]:bg-primary data-[state=checked]:border-primary"
/>
)}
/>
<div>
<Label htmlFor="invoiced" className="font-black text-foreground cursor-pointer">Verified for Invoicing</Label>
<p className="text-xs text-muted-foreground font-medium">Staff member approved for automatic invoicing</p>
</div>
</div>
</div>
<div className="p-6 bg-green-50 dark:bg-green-950/20 rounded-2xl border border-green-200 dark:border-green-900">
<div className="flex items-center gap-3 mb-2">
<div className="w-8 h-8 rounded-full bg-green-500 flex items-center justify-center">
<Shield className="w-4 h-4 text-white" />
</div>
<Label className="font-bold text-green-900 dark:text-green-100">Background Check</Label>
</div>
<p className="text-xs text-green-700 dark:text-green-400">Completed & Approved</p>
</div>
<div className="p-6 bg-amber-50 dark:bg-amber-950/20 rounded-2xl border border-amber-200 dark:border-amber-900">
<div className="flex items-center gap-3 mb-2">
<div className="w-8 h-8 rounded-full bg-amber-500 flex items-center justify-center">
<AlertCircle className="w-4 h-4 text-white" />
</div>
<Label className="font-bold text-amber-900 dark:text-amber-100">Drug Screening</Label>
</div>
<p className="text-xs text-amber-700 dark:text-amber-400">Pending Review</p>
</div>
</div>
</div>
{/* Language Requirements */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<Info className="w-4 h-4" />
LANGUAGE REQUIREMENTS
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">English Proficiency</Label>
<Controller
name="english"
control={control}
render={({ field }) => (
<Select onValueChange={field.onChange} value={field.value}>
<SelectTrigger>
<Select onValueChange={disabled ? undefined : field.onChange} value={field.value} disabled={disabled}>
<SelectTrigger disabled={disabled}>
<SelectValue placeholder="Select level" />
</SelectTrigger>
<SelectContent className="rounded-xl glass">
@@ -443,65 +715,88 @@ export default function StaffForm({ staff, onSubmit, isSubmitting }: StaffFormPr
/>
</div>
<div className="flex items-center gap-3 pt-6">
<div className="flex items-center gap-3 pt-8">
<Controller
name="english_required"
control={control}
render={({ field }) => (
<Checkbox
id="english_required"
disabled={disabled}
checked={field.value}
onChange={(e) => field.onChange(e.target.checked)}
className="w-5 h-5"
/>
)}
/>
<Label htmlFor="english_required" className="text-sm font-bold text-foreground cursor-pointer">Required for role</Label>
<Label htmlFor="english_required" className="text-sm font-bold text-foreground cursor-pointer">
English Required for Role
</Label>
</div>
</div>
</div>
</TabContent>
)}
{activeTab === "additional" && (
<TabContent
id="additional"
title="Notes & Comments"
icon={<Info className="w-5 h-5" />}
className="p-8 space-y-6"
>
{/* Additional Compliance Fields */}
<div>
<h3 className="text-sm font-black text-muted-foreground/80 mb-4 flex items-center gap-2">
<FileText className="w-4 h-4" />
ADDITIONAL INFORMATION
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Staff Notes</Label>
<Label className="text-xs font-black text-muted-foreground/80 pl-1">RO Number</Label>
<Input
{...register("ro")}
disabled={disabled}
className="font-medium"
placeholder="RO reference number"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">MON Reference</Label>
<Input
{...register("mon")}
disabled={disabled}
className="font-medium"
placeholder="Monitoring reference"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Phone (Alt)</Label>
<Input
{...register("phone")}
disabled={disabled}
leadingIcon={<Phone />}
className="font-medium"
placeholder="Alternative contact"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80 pl-1">Address</Label>
<Input
{...register("address")}
disabled={disabled}
leadingIcon={<MapPin />}
className="font-medium"
placeholder="Street address"
/>
</div>
</div>
</div>
{/* Compliance Notes */}
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Compliance Notes</Label>
<Textarea
{...register("notes")}
placeholder="Internal notes about performance, behavior, etc."
disabled={disabled}
placeholder="Compliance-related notes, verification details, or follow-up items..."
className="min-h-[100px]"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Accounting Comments</Label>
<Textarea
{...register("accounting_comments")}
placeholder="Pay rates, bonus structures, or audit notes."
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 pt-4">
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Last Check-in</Label>
<Input
{...register("check_in")}
type="date"
leadingIcon={<Calendar />}
className="font-medium"
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-black text-muted-foreground/80">Schedule Override</Label>
<Input
{...register("schedule_days")}
className="font-medium"
placeholder="e.g., M/W/F Only"
/>
</div>
</div>
</TabContent>
)}
</AnimatePresence>