Files
auditly/src/components/CompanyWiki/InviteMultipleEmployeesModal.tsx
2025-08-25 10:46:46 -07:00

178 lines
10 KiB
TypeScript

import React, { useState } from 'react';
interface Employee {
id: string;
name: string;
email: string;
avatar?: string;
}
interface InviteMultipleEmployeesModalProps {
isOpen: boolean;
onClose: () => void;
onInviteSelected: (employees: Employee[]) => void;
suggestedEmployees?: Employee[];
}
const defaultSuggestedEmployees: Employee[] = [
{ id: '1', name: 'John Smith', email: 'john@company.com' },
{ id: '2', name: 'Sarah Johnson', email: 'sarah@company.com' },
{ id: '3', name: 'Mike Chen', email: 'mike@company.com' },
{ id: '4', name: 'Emily Davis', email: 'emily@company.com' },
{ id: '5', name: 'Alex Rodriguez', email: 'alex@company.com' },
];
export const InviteMultipleEmployeesModal: React.FC<InviteMultipleEmployeesModalProps> = ({
isOpen,
onClose,
onInviteSelected,
suggestedEmployees = defaultSuggestedEmployees
}) => {
const [searchTerm, setSearchTerm] = useState('');
const [selectedEmployees, setSelectedEmployees] = useState<Employee[]>([]);
const [showDropdown, setShowDropdown] = useState(false);
if (!isOpen) return null;
const filteredEmployees = suggestedEmployees.filter(emp =>
(emp.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
emp.email.toLowerCase().includes(searchTerm.toLowerCase())) &&
!selectedEmployees.find(selected => selected.id === emp.id)
);
const handleEmployeeSelect = (employee: Employee) => {
setSelectedEmployees(prev => [...prev, employee]);
setSearchTerm('');
setShowDropdown(false);
};
const handleEmployeeRemove = (employeeId: string) => {
setSelectedEmployees(prev => prev.filter(emp => emp.id !== employeeId));
};
const handleInvite = () => {
if (selectedEmployees.length > 0) {
onInviteSelected(selectedEmployees);
setSelectedEmployees([]);
setSearchTerm('');
}
};
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="w-[480px] bg-[--Neutrals-NeutralSlate0] dark:bg-[--Neutrals-NeutralSlate0] rounded-3xl shadow-[0px_25px_50px_-12px_rgba(0,0,0,0.25)] flex flex-col justify-start items-start overflow-hidden">
{/* Header */}
<div className="self-stretch p-6 inline-flex justify-between items-center">
<div className="flex justify-start items-center gap-2.5">
<div className="justify-start text-Text-Dark-950 dark:text-[--Neutrals-NeutralSlate50] text-lg font-semibold font-['Inter'] leading-7">
Invite multiple employees
</div>
</div>
<button
onClick={onClose}
className="w-6 h-6 flex justify-center items-center hover:bg-[--Neutrals-NeutralSlate100] dark:hover:bg-[--Neutrals-NeutralSlate700] rounded"
>
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
<path d="M13 1L1 13M1 1L13 13" stroke="#666D80" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</button>
</div>
{/* Search Input with Dropdown */}
<div className="self-stretch px-6 flex flex-col justify-start items-start gap-4">
<div className="self-stretch flex flex-col justify-start items-start gap-1 relative">
<div className="self-stretch justify-start text-[--Neutrals-NeutralSlate950] text-sm font-medium font-['Inter'] leading-tight">
Search employees
</div>
<div className="self-stretch h-10 px-3 py-2 bg-[--Neutrals-NeutralSlate0] rounded-lg border border-Outline-Outline-Gray-300 inline-flex justify-start items-center gap-2">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" className="text-Text-Gray-400">
<path d="M15 15L11.15 11.15M12.6667 7.33333C12.6667 10.2789 10.2789 12.6667 7.33333 12.6667C4.38781 12.6667 2 10.2789 2 7.33333C2 4.38781 4.38781 2 7.33333 2C10.2789 2 12.6667 4.38781 12.6667 7.33333Z" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
<input
type="text"
value={searchTerm}
onChange={(e) => {
setSearchTerm(e.target.value);
setShowDropdown(e.target.value.length > 0);
}}
onFocus={() => setShowDropdown(searchTerm.length > 0)}
placeholder="Type name or email to search..."
className="flex-1 text-[--Neutrals-NeutralSlate950] text-sm font-normal font-['Inter'] leading-tight bg-transparent outline-none placeholder:text-Text-Gray-500"
/>
</div>
{/* Dropdown */}
{showDropdown && filteredEmployees.length > 0 && (
<div className="absolute top-full left-0 right-0 mt-1 bg-[--Neutrals-NeutralSlate0] border border-Outline-Outline-Gray-200 rounded-lg shadow-lg z-10 max-h-48 overflow-y-auto">
{filteredEmployees.map((employee) => (
<button
key={employee.id}
onClick={() => handleEmployeeSelect(employee)}
className="w-full px-3 py-2 text-left hover:bg-[--Neutrals-NeutralSlate50] flex items-center gap-3 border-b border-Text-Gray-100 last:border-b-0"
>
<div className="w-8 h-8 bg-[--Brand-Orange] rounded-full flex items-center justify-center text-white text-sm font-medium">
{employee.name.charAt(0)}
</div>
<div className="flex-1">
<div className="text-sm font-medium text-[--Neutrals-NeutralSlate950]">{employee.name}</div>
<div className="text-xs text-Text-Gray-500">{employee.email}</div>
</div>
</button>
))}
</div>
)}
</div>
{/* Selected Employees */}
{selectedEmployees.length > 0 && (
<div className="self-stretch flex flex-col justify-start items-start gap-2">
<div className="text-sm font-medium text-[--Neutrals-NeutralSlate950]">
Selected ({selectedEmployees.length})
</div>
<div className="self-stretch flex flex-wrap gap-2">
{selectedEmployees.map((employee) => (
<div
key={employee.id}
className="px-3 py-1.5 bg-[--Brand-Orange] bg-opacity-10 rounded-full flex items-center gap-2"
>
<div className="w-5 h-5 bg-[--Brand-Orange] rounded-full flex items-center justify-center text-white text-xs font-medium">
{employee.name.charAt(0)}
</div>
<span className="text-sm text-[--Neutrals-NeutralSlate950]">{employee.name}</span>
<button
onClick={() => handleEmployeeRemove(employee.id)}
className="w-4 h-4 flex items-center justify-center hover:bg-[--Brand-Orange] hover:bg-opacity-20 rounded-full"
>
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M9 3L3 9M3 3L9 9" stroke="#666D80" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</button>
</div>
))}
</div>
</div>
)}
</div>
{/* Footer */}
<div className="self-stretch p-6 inline-flex justify-end items-center">
<div className="flex justify-start items-start gap-3">
<button
onClick={onClose}
className="px-4 py-2 bg-[--Neutrals-NeutralSlate0] rounded-lg border border-Outline-Outline-Gray-300 text-[--Neutrals-NeutralSlate700] text-sm font-medium font-['Inter'] leading-tight hover:bg-[--Neutrals-NeutralSlate50]"
>
Cancel
</button>
<button
onClick={handleInvite}
disabled={selectedEmployees.length === 0}
className="px-4 py-2 bg-[--Brand-Orange] rounded-lg text-[--Neutrals-NeutralSlate0] text-sm font-medium font-['Inter'] leading-tight hover:bg-orange-600 disabled:opacity-50 disabled:cursor-not-allowed"
>
Send Invites ({selectedEmployees.length})
</button>
</div>
</div>
</div>
</div>
);
};