Files
sfera/src/components/employees/day-edit-modal.tsx
Bivekich 9062891b0a feat: Comprehensive employee management system improvements
-  Added compact employee forms (add/edit) with all fields visible
- 🎯 Implemented expandable employee rows with timesheet integration
- 📊 Added real KPI calculation based on work hours, sick days, and overtime
- 📅 Added bulk date selection and editing in calendar
- 🗓️ Implemented day-specific editing modal with hours and overtime tracking
- 💾 Extended database schema with overtimeHours field
- 🎨 Improved UI layout: tabs left, search right, real current date display
- 🧹 Fixed spacing issues and removed unnecessary gaps
- 🔧 Enhanced GraphQL mutations for employee schedule management
2025-07-30 17:33:37 +03:00

186 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useState } from 'react'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Calendar, Clock, Zap, FileText } from 'lucide-react'
interface DayEditModalProps {
isOpen: boolean
onClose: () => void
date: Date
employeeName: string
currentStatus?: string
currentHours?: number
currentOvertime?: number
currentNotes?: string
onSave: (data: {
status: string
hoursWorked?: number
overtimeHours?: number
notes?: string
}) => void
}
const statusOptions = [
{ value: 'WORK', label: 'Рабочий день', color: 'text-green-400' },
{ value: 'WEEKEND', label: 'Выходной', color: 'text-blue-400' },
{ value: 'VACATION', label: 'Отпуск', color: 'text-blue-400' },
{ value: 'SICK', label: 'Больничный', color: 'text-orange-400' },
{ value: 'ABSENT', label: 'Отсутствие', color: 'text-red-400' }
]
export function DayEditModal({
isOpen,
onClose,
date,
employeeName,
currentStatus = 'WORK',
currentHours = 8,
currentOvertime = 0,
currentNotes = '',
onSave
}: DayEditModalProps) {
const [status, setStatus] = useState(currentStatus)
const [hoursWorked, setHoursWorked] = useState(currentHours.toString())
const [overtimeHours, setOvertimeHours] = useState(currentOvertime.toString())
const [notes, setNotes] = useState(currentNotes)
const handleSave = () => {
const data = {
status,
hoursWorked: status === 'WORK' ? parseFloat(hoursWorked) || 0 : undefined,
overtimeHours: status === 'WORK' ? parseFloat(overtimeHours) || 0 : undefined,
notes: notes.trim() || undefined
}
onSave(data)
onClose()
}
const formatDate = (date: Date) => {
return date.toLocaleDateString('ru-RU', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})
}
const isWorkDay = status === 'WORK'
const selectedStatus = statusOptions.find(opt => opt.value === status)
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="glass-card border-white/10 max-w-md">
<DialogHeader>
<DialogTitle className="text-white flex items-center gap-2">
<Calendar className="h-5 w-5 text-purple-400" />
Редактирование дня
</DialogTitle>
</DialogHeader>
<div className="space-y-4">
{/* Информация о дне */}
<div className="bg-white/5 rounded-lg p-3 border border-white/10">
<div className="text-white font-medium">{employeeName}</div>
<div className="text-white/70 text-sm">{formatDate(date)}</div>
</div>
{/* Статус дня */}
<div className="space-y-2">
<Label className="text-white">Статус дня</Label>
<Select value={status} onValueChange={setStatus}>
<SelectTrigger className="glass-secondary border-white/20 text-white">
<SelectValue />
</SelectTrigger>
<SelectContent className="glass-card border-white/10">
{statusOptions.map((option) => (
<SelectItem
key={option.value}
value={option.value}
className={`${option.color} hover:bg-white/10`}
>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* Рабочие часы - только для рабочих дней */}
{isWorkDay && (
<>
<div className="space-y-2">
<Label className="text-white flex items-center gap-2">
<Clock className="h-4 w-4 text-green-400" />
Отработано часов
</Label>
<Input
type="number"
min="0"
max="24"
step="0.5"
value={hoursWorked}
onChange={(e) => setHoursWorked(e.target.value)}
className="glass-secondary border-white/20 text-white"
placeholder="8"
/>
</div>
<div className="space-y-2">
<Label className="text-white flex items-center gap-2">
<Zap className="h-4 w-4 text-yellow-400" />
Переработка (часов)
</Label>
<Input
type="number"
min="0"
max="12"
step="0.5"
value={overtimeHours}
onChange={(e) => setOvertimeHours(e.target.value)}
className="glass-secondary border-white/20 text-white"
placeholder="0"
/>
</div>
</>
)}
{/* Заметки */}
<div className="space-y-2">
<Label className="text-white flex items-center gap-2">
<FileText className="h-4 w-4 text-blue-400" />
Заметки (необязательно)
</Label>
<Input
value={notes}
onChange={(e) => setNotes(e.target.value)}
className="glass-secondary border-white/20 text-white"
placeholder="Дополнительная информация..."
/>
</div>
{/* Кнопки */}
<div className="flex gap-3 pt-4">
<Button
variant="ghost"
onClick={onClose}
className="flex-1 glass-secondary text-white hover:text-white"
>
Отмена
</Button>
<Button
onClick={handleSave}
className="flex-1 bg-purple-600 hover:bg-purple-700 text-white"
>
Сохранить
</Button>
</div>
</div>
</DialogContent>
</Dialog>
)
}