feat(crm): Complete Admin Action Center & Reliability Overhaul

- Added ActionCenterWidget, DetailDrawer, AgentSelectionModal
- Implemented global ErrorBoundary and Chatbot resilience
- Updated documentation (README, Structure, Status, Overview)
- Refined responsive design and modal portals
This commit is contained in:
Satyam
2026-02-11 18:33:04 +05:30
parent bfc90b668b
commit be828b205d
7 changed files with 676 additions and 12 deletions
@@ -0,0 +1,83 @@
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
);
};