Добавлены модели и функциональность для управления сотрудниками, включая создание, обновление и удаление сотрудников через GraphQL. Обновлены компоненты для отображения списка сотрудников и их расписания, улучшен интерфейс взаимодействия с пользователем. Реализованы функции экспорта отчетов в CSV и TXT форматах, добавлены новые интерфейсы и типы данных для сотрудников.
This commit is contained in:
@ -6,6 +6,7 @@ import { Button } from '@/components/ui/button'
|
||||
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
@ -18,7 +19,9 @@ import {
|
||||
User,
|
||||
Briefcase,
|
||||
Save,
|
||||
X
|
||||
X,
|
||||
Trash2,
|
||||
UserX
|
||||
} from 'lucide-react'
|
||||
|
||||
// Интерфейс сотрудника
|
||||
@ -27,7 +30,7 @@ interface Employee {
|
||||
firstName: string
|
||||
lastName: string
|
||||
position: string
|
||||
department: string
|
||||
department?: string
|
||||
phone: string
|
||||
email: string
|
||||
avatar?: string
|
||||
@ -95,10 +98,12 @@ const mockEmployees: Employee[] = [
|
||||
|
||||
interface EmployeesListProps {
|
||||
searchQuery: string
|
||||
employees: Employee[]
|
||||
onEditEmployee: (employee: Employee) => void
|
||||
onDeleteEmployee: (employeeId: string) => void
|
||||
}
|
||||
|
||||
export function EmployeesList({ searchQuery }: EmployeesListProps) {
|
||||
const [employees, setEmployees] = useState<Employee[]>(mockEmployees)
|
||||
export function EmployeesList({ searchQuery, employees, onEditEmployee, onDeleteEmployee }: EmployeesListProps) {
|
||||
const [selectedEmployee, setSelectedEmployee] = useState<Employee | null>(null)
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false)
|
||||
|
||||
@ -106,7 +111,7 @@ export function EmployeesList({ searchQuery }: EmployeesListProps) {
|
||||
const filteredEmployees = employees.filter(employee =>
|
||||
`${employee.firstName} ${employee.lastName}`.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
employee.position.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
employee.department.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
(employee.department && employee.department.toLowerCase().includes(searchQuery.toLowerCase()))
|
||||
)
|
||||
|
||||
const getStatusBadge = (status: Employee['status']) => {
|
||||
@ -133,18 +138,11 @@ export function EmployeesList({ searchQuery }: EmployeesListProps) {
|
||||
}
|
||||
|
||||
const handleEditEmployee = (employee: Employee) => {
|
||||
setSelectedEmployee(employee)
|
||||
setIsEditModalOpen(true)
|
||||
onEditEmployee(employee)
|
||||
}
|
||||
|
||||
const handleSaveEmployee = () => {
|
||||
if (selectedEmployee) {
|
||||
setEmployees(prev =>
|
||||
prev.map(emp => emp.id === selectedEmployee.id ? selectedEmployee : emp)
|
||||
)
|
||||
setIsEditModalOpen(false)
|
||||
setSelectedEmployee(null)
|
||||
}
|
||||
const handleDeleteEmployee = (employee: Employee) => {
|
||||
onDeleteEmployee(employee.id)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -214,14 +212,48 @@ export function EmployeesList({ searchQuery }: EmployeesListProps) {
|
||||
<h3 className="text-white font-semibold text-lg truncate">
|
||||
{employee.firstName} {employee.lastName}
|
||||
</h3>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="text-white/60 hover:text-white hover:bg-white/10 h-8 w-8 p-0"
|
||||
onClick={() => handleEditEmployee(employee)}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="flex gap-1">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="text-white/60 hover:text-white hover:bg-white/10 h-8 w-8 p-0"
|
||||
onClick={() => handleEditEmployee(employee)}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="text-red-400/60 hover:text-red-300 hover:bg-red-500/10 h-8 w-8 p-0"
|
||||
>
|
||||
<UserX className="h-4 w-4" />
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent className="glass-card border-white/10">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle className="text-white">Уволить сотрудника?</AlertDialogTitle>
|
||||
<AlertDialogDescription className="text-white/70">
|
||||
Вы уверены, что хотите уволить {employee.firstName} {employee.lastName}?
|
||||
Это действие изменит статус сотрудника на "Неактивен" и удалит его из активного списка.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel className="glass-secondary text-white hover:text-white">
|
||||
Отмена
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={() => handleDeleteEmployee(employee)}
|
||||
className="bg-red-600 hover:bg-red-700 text-white"
|
||||
>
|
||||
Уволить
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-purple-300 font-medium mb-1">{employee.position}</p>
|
||||
@ -389,11 +421,11 @@ export function EmployeesList({ searchQuery }: EmployeesListProps) {
|
||||
|
||||
<div className="flex gap-2 pt-4">
|
||||
<Button
|
||||
onClick={handleSaveEmployee}
|
||||
onClick={() => setIsEditModalOpen(false)}
|
||||
className="glass-button flex-1"
|
||||
>
|
||||
<Save className="h-4 w-4 mr-2" />
|
||||
Сохранить
|
||||
Закрыть
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
|
Reference in New Issue
Block a user