From aa9ab0152320b983f75560b6f32aa1bd207da1ac Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 15 Nov 2025 09:29:39 +0000 Subject: [PATCH] Create DirectoryWidget for STAFF dashboard cgen-af537e4c87db4dcdbf57edbef0f0cf3b --- client/components/DirectoryWidget.tsx | 165 ++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 client/components/DirectoryWidget.tsx diff --git a/client/components/DirectoryWidget.tsx b/client/components/DirectoryWidget.tsx new file mode 100644 index 00000000..5557e458 --- /dev/null +++ b/client/components/DirectoryWidget.tsx @@ -0,0 +1,165 @@ +import { useState } from "react"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Input } from "@/components/ui/input"; +import { Users, Search, Phone, Mail, MapPin } from "lucide-react"; + +export interface DirectoryMember { + id: string; + name: string; + role: string; + department?: string; + email?: string; + phone?: string; + location?: string; + avatar_url?: string; + employment_type: "employee" | "contractor"; +} + +interface DirectoryWidgetProps { + members: DirectoryMember[]; + title?: string; + description?: string; + showEmployeeOnly?: boolean; + showContractorOnly?: boolean; +} + +export function DirectoryWidget({ + members, + title = "Team Directory", + description = "Find team members and contact information", + showEmployeeOnly = false, + showContractorOnly = false, +}: DirectoryWidgetProps) { + const [searchQuery, setSearchQuery] = useState(""); + + const filteredMembers = members.filter((member) => { + const matchesSearch = + member.name.toLowerCase().includes(searchQuery.toLowerCase()) || + member.role.toLowerCase().includes(searchQuery.toLowerCase()) || + member.department?.toLowerCase().includes(searchQuery.toLowerCase()); + + if (showEmployeeOnly) { + return matchesSearch && member.employment_type === "employee"; + } + if (showContractorOnly) { + return matchesSearch && member.employment_type === "contractor"; + } + return matchesSearch; + }); + + const employeeCount = members.filter(m => m.employment_type === "employee").length; + const contractorCount = members.filter(m => m.employment_type === "contractor").length; + + return ( + + + + + {title} + + {description} + + + {/* Stats */} +
+
+

Employees

+

{employeeCount}

+
+
+

Contractors

+

{contractorCount}

+
+
+ + {/* Search */} +
+ + setSearchQuery(e.target.value)} + className="pl-10 bg-black/30 border-gray-500/20" + /> +
+ + {/* Members List */} + {filteredMembers.length === 0 ? ( +
+ +

No members found

+
+ ) : ( +
+ {filteredMembers.map((member) => ( +
+ {/* Header */} +
+ {member.avatar_url ? ( + {member.name} + ) : ( +
+ + {member.name.charAt(0).toUpperCase()} + +
+ )} + +
+

{member.name}

+

{member.role}

+ {member.department && ( +

{member.department}

+ )} +
+ + + {member.employment_type} + +
+ + {/* Contact Info */} +
+ {member.email && ( +
+ + {member.email} +
+ )} + {member.phone && ( +
+ + {member.phone} +
+ )} + {member.location && ( +
+ + {member.location} +
+ )} +
+
+ ))} +
+ )} +
+
+ ); +} + +export default DirectoryWidget;