be828b205d
- Added ActionCenterWidget, DetailDrawer, AgentSelectionModal - Implemented global ErrorBoundary and Chatbot resilience - Updated documentation (README, Structure, Status, Overview) - Refined responsive design and modal portals
84 lines
4.5 KiB
React
84 lines
4.5 KiB
React
import React, { useState } from 'react';
|
|
import { createPortal } from 'react-dom';
|
|
import { Search, User, X, Check } from 'lucide-react';
|
|
import { useMockStore } from '../../data/mockStore';
|
|
|
|
export const AgentSelectionModal = ({ isOpen, onClose, onSelect }) => {
|
|
const { users } = useMockStore();
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
|
|
if (!isOpen) return null;
|
|
|
|
// Filter for Field Agents only
|
|
const agents = users.filter(u =>
|
|
u.role === 'FIELD_AGENT' &&
|
|
(u.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
u.empId.toLowerCase().includes(searchTerm.toLowerCase()))
|
|
);
|
|
|
|
return createPortal(
|
|
<div className="fixed inset-0 z-[60] flex items-end sm:items-center justify-center p-4 sm:p-6">
|
|
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm transition-opacity" onClick={onClose}></div>
|
|
|
|
<div className="relative w-full max-w-md bg-white dark:bg-zinc-900 rounded-t-2xl sm:rounded-2xl shadow-2xl overflow-hidden border border-zinc-200 dark:border-zinc-800 scale-100 animate-in slide-in-from-bottom-10 sm:slide-in-from-bottom-0 sm:zoom-in-95 duration-200 flex flex-col max-h-[85vh]">
|
|
|
|
{/* Header */}
|
|
<div className="p-4 border-b border-zinc-100 dark:border-zinc-800 flex justify-between items-center bg-zinc-50 dark:bg-white/5 flex-shrink-0">
|
|
<h3 className="text-lg font-bold text-zinc-900 dark:text-white">Assign Agent</h3>
|
|
<button onClick={onClose} className="p-2 text-zinc-400 hover:text-zinc-600 dark:hover:text-white bg-zinc-200 dark:bg-white/10 rounded-full active:scale-95">
|
|
<X size={16} />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Search */}
|
|
<div className="p-4 border-b border-zinc-100 dark:border-zinc-800 flex-shrink-0">
|
|
<div className="relative">
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-zinc-400" size={16} />
|
|
<input
|
|
type="text"
|
|
placeholder="Search agents..."
|
|
className="w-full pl-9 pr-4 py-2 bg-zinc-100 dark:bg-black/20 border border-transparent focus:border-blue-500 rounded-xl text-sm outline-none transition-all dark:text-white"
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
autoFocus
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* List */}
|
|
<div className="max-h-[300px] overflow-y-auto">
|
|
{agents.map(agent => (
|
|
<div
|
|
key={agent.id}
|
|
onClick={() => onSelect(agent.id)}
|
|
className="flex items-center justify-between p-4 hover:bg-blue-50 dark:hover:bg-blue-900/10 cursor-pointer transition-colors border-b border-zinc-100 dark:border-zinc-800/50 last:border-0 group"
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center text-blue-600 dark:text-blue-400">
|
|
<User size={18} />
|
|
</div>
|
|
<div>
|
|
<h4 className="font-semibold text-zinc-900 dark:text-white text-sm">{agent.name}</h4>
|
|
<p className="text-xs text-zinc-500">{agent.empId} • {agent.email}</p>
|
|
</div>
|
|
</div>
|
|
<div className="opacity-0 group-hover:opacity-100 transition-opacity">
|
|
<span className="px-3 py-1 bg-blue-600 text-white text-xs font-bold rounded-lg flex items-center gap-1 shadow-sm">
|
|
Select <Check size={12} />
|
|
</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
|
|
{agents.length === 0 && (
|
|
<div className="p-8 text-center text-zinc-400">
|
|
<p className="text-sm">No agents found.</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>,
|
|
document.body
|
|
);
|
|
};
|