118 lines
7.1 KiB
TypeScript
Executable File
118 lines
7.1 KiB
TypeScript
Executable File
|
||
import React from 'react';
|
||
import { Employee, District } from '../../types';
|
||
import { X, User, Phone, MessageCircle, MapPin } from 'lucide-react';
|
||
|
||
interface Props {
|
||
district: District;
|
||
employees: Employee[];
|
||
onClose: () => void;
|
||
}
|
||
|
||
export const DistrictStaffModal: React.FC<Props> = ({ district, employees, onClose }) => {
|
||
const districtEmployees = employees.filter(emp => {
|
||
const ids = emp.assignedDistrictIds?.length ? emp.assignedDistrictIds : (emp.assignedDistrictId ? [emp.assignedDistrictId] : []);
|
||
return ids.includes(district.id);
|
||
});
|
||
|
||
return (
|
||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4" onClick={onClose}>
|
||
<div
|
||
className="bg-white rounded-2xl shadow-xl max-w-2xl w-full max-h-[90vh] overflow-hidden flex flex-col"
|
||
onClick={(e) => e.stopPropagation()}
|
||
>
|
||
{/* Header */}
|
||
<div className="flex items-center justify-between p-6 border-b border-slate-200">
|
||
<div>
|
||
<h2 className="text-xl font-bold text-slate-800">Персонал участка</h2>
|
||
<p className="text-sm text-slate-500 mt-1">{district.name}</p>
|
||
</div>
|
||
<button
|
||
onClick={onClose}
|
||
className="p-2 hover:bg-slate-100 rounded-lg transition-colors"
|
||
>
|
||
<X className="w-5 h-5 text-slate-500" />
|
||
</button>
|
||
</div>
|
||
|
||
{/* Content */}
|
||
<div className="flex-1 overflow-y-auto p-6">
|
||
{districtEmployees.length === 0 ? (
|
||
<div className="text-center py-12 text-slate-400">
|
||
<User className="w-12 h-12 mx-auto mb-4 opacity-20" />
|
||
<p className="font-bold">На этом участке нет закрепленных сотрудников</p>
|
||
</div>
|
||
) : (
|
||
<div className="space-y-3">
|
||
{districtEmployees.map(emp => (
|
||
<div
|
||
key={emp.id}
|
||
className="flex items-center justify-between p-4 bg-slate-50 rounded-xl border border-slate-100 hover:bg-slate-100 transition-colors"
|
||
>
|
||
<div className="flex items-center gap-3 flex-1">
|
||
<div className="w-12 h-12 rounded-full bg-white flex items-center justify-center text-primary-600 font-black border border-slate-200 shrink-0">
|
||
{emp.photoUrl ? (
|
||
<img
|
||
src={emp.photoUrl.startsWith('http')
|
||
? emp.photoUrl
|
||
: `${import.meta.env.VITE_API_BASE_URL?.replace('/api', '') || 'http://localhost:4000'}${emp.photoUrl}`}
|
||
alt={emp.name}
|
||
className="w-full h-full rounded-full object-cover"
|
||
onError={(e) => {
|
||
const target = e.target as HTMLImageElement;
|
||
target.style.display = 'none';
|
||
const parent = target.parentElement;
|
||
if (parent) {
|
||
const fallback = document.createElement('div');
|
||
fallback.className = 'w-12 h-12 rounded-full bg-white flex items-center justify-center text-primary-600 font-black border border-slate-200';
|
||
fallback.textContent = emp.name.split(' ').map(n => n[0]).join('');
|
||
parent.appendChild(fallback);
|
||
}
|
||
}}
|
||
/>
|
||
) : (
|
||
emp.name.split(' ').map(n => n[0]).join('')
|
||
)}
|
||
</div>
|
||
<div className="flex-1 min-w-0">
|
||
<p className="font-bold text-slate-800 text-sm">{emp.name}</p>
|
||
<p className="text-xs text-slate-500 flex items-center gap-1 mt-1">
|
||
<MapPin className="w-3 h-3"/> {emp.position}
|
||
</p>
|
||
{emp.phone && (
|
||
<p className="text-xs text-slate-400 mt-1">{emp.phone}</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
<div className="flex gap-1 shrink-0">
|
||
{emp.phone && (
|
||
<a
|
||
href={`tel:${emp.phone}`}
|
||
className="p-2 text-emerald-600 hover:bg-emerald-50 rounded-lg transition-colors"
|
||
onClick={(e) => e.stopPropagation()}
|
||
>
|
||
<Phone className="w-4 h-4"/>
|
||
</a>
|
||
)}
|
||
{emp.messengerLogins && emp.messengerLogins.length > 0 && (
|
||
<button
|
||
className="p-2 text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
// Здесь можно добавить логику открытия мессенджера
|
||
}}
|
||
>
|
||
<MessageCircle className="w-4 h-4"/>
|
||
</button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|