"use client" import { useState, useRef } from 'react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Card } from '@/components/ui/card' import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar' import { User, UserPlus, Phone, Mail, Briefcase, DollarSign, AlertCircle, Save, X, Camera, Calendar, MessageCircle, FileImage, RefreshCw } from 'lucide-react' import { toast } from 'sonner' import { formatPhoneInput, formatSalary, formatNameInput, isValidEmail, isValidPhone, isValidSalary, isValidBirthDate } from '@/lib/input-masks' interface EmployeeCompactFormProps { onSave: (employeeData: { firstName: string lastName: string middleName?: string phone: string email?: string position: string salary?: number avatar?: string birthDate?: string telegram?: string whatsapp?: string passportPhoto?: string hireDate: string }) => void onCancel: () => void isLoading?: boolean } interface ValidationErrors { [key: string]: string } export function EmployeeCompactForm({ onSave, onCancel, isLoading = false }: EmployeeCompactFormProps) { const [formData, setFormData] = useState({ firstName: '', lastName: '', middleName: '', phone: '', email: '', position: '', salary: 0, avatar: '', birthDate: '', telegram: '', whatsapp: '', passportPhoto: '' }) const [errors, setErrors] = useState({}) const [isUploadingAvatar, setIsUploadingAvatar] = useState(false) const [isUploadingPassport, setIsUploadingPassport] = useState(false) const avatarInputRef = useRef(null) const passportInputRef = useRef(null) const validateField = (field: string, value: string | number): string | null => { switch (field) { case 'firstName': case 'lastName': if (!value || String(value).trim() === '') { return field === 'firstName' ? 'Имя обязательно' : 'Фамилия обязательна' } if (String(value).length < 2) { return field === 'firstName' ? 'Имя минимум 2 символа' : 'Фамилия минимум 2 символа' } if (!/^[а-яёА-ЯЁa-zA-Z\s-]+$/.test(String(value))) { return field === 'firstName' ? 'Только буквы, пробелы и дефисы' : 'Только буквы, пробелы и дефисы' } break case 'middleName': if (value && String(value).length > 0) { if (String(value).length < 2) { return 'Отчество минимум 2 символа' } if (!/^[а-яёА-ЯЁa-zA-Z\s-]+$/.test(String(value))) { return 'Только буквы, пробелы и дефисы' } } break case 'position': if (!value || String(value).trim() === '') { return 'Должность обязательна' } if (String(value).length < 2) { return 'Должность минимум 2 символа' } break case 'phone': case 'whatsapp': if (field === 'phone' && (!value || String(value).trim() === '')) { return 'Телефон обязателен' } if (value && String(value).trim() !== '' && !isValidPhone(String(value))) { return 'Некорректный формат телефона' } break case 'email': if (value && String(value).trim() !== '' && !isValidEmail(String(value))) { return 'Некорректный email' } break case 'birthDate': if (value && String(value).trim() !== '') { const validation = isValidBirthDate(String(value)) if (!validation.valid) { return validation.message || 'Некорректная дата рождения' } } break case 'salary': const salaryValidation = isValidSalary(Number(value)) if (!salaryValidation.valid) { return salaryValidation.message || 'Некорректная зарплата' } break } return null } const handleInputChange = (field: string, value: string | number) => { let processedValue = value // Применяем маски ввода if (typeof value === 'string') { switch (field) { case 'phone': case 'whatsapp': processedValue = formatPhoneInput(value) break case 'firstName': case 'lastName': case 'middleName': processedValue = formatNameInput(value) break } } setFormData(prev => ({ ...prev, [field]: processedValue })) // Валидация в реальном времени const error = validateField(field, processedValue) setErrors(prev => ({ ...prev, [field]: error || '' })) } const handleSalaryChange = (value: string) => { const numericValue = parseInt(value.replace(/\D/g, '')) || 0 setFormData(prev => ({ ...prev, salary: numericValue })) const error = validateField('salary', numericValue) setErrors(prev => ({ ...prev, salary: error || '' })) } const handleFileUpload = async (file: File, type: 'avatar' | 'passport') => { const setLoading = type === 'avatar' ? setIsUploadingAvatar : setIsUploadingPassport setLoading(true) try { const formDataUpload = new FormData() formDataUpload.append('file', file) let endpoint: string if (type === 'avatar') { formDataUpload.append('userId', `temp_${Date.now()}`) endpoint = '/api/upload-avatar' } else { // Для фото паспорта используем специальный endpoint для документов formDataUpload.append('documentType', 'passport-photo') endpoint = '/api/upload-employee-document' } const response = await fetch(endpoint, { method: 'POST', body: formDataUpload }) if (!response.ok) { const errorData = await response.json() throw new Error(errorData.error || `Ошибка загрузки ${type === 'avatar' ? 'аватара' : 'паспорта'}`) } const result = await response.json() setFormData(prev => ({ ...prev, [type === 'avatar' ? 'avatar' : 'passportPhoto']: result.url })) toast.success(`${type === 'avatar' ? 'Аватар' : 'Фото паспорта'} успешно загружен`) } catch (error) { console.error(`Error uploading ${type}:`, error) const errorMessage = error instanceof Error ? error.message : `Ошибка при загрузке ${type === 'avatar' ? 'аватара' : 'паспорта'}` toast.error(errorMessage) } finally { setLoading(false) } } const validateForm = (): boolean => { const newErrors: ValidationErrors = {} // Валидируем все поля Object.keys(formData).forEach(field => { const error = validateField(field, formData[field as keyof typeof formData]) if (error) { newErrors[field] = error } }) setErrors(newErrors) return Object.keys(newErrors).filter(key => newErrors[key]).length === 0 } const handleSubmit = (e: React.FormEvent) => { e.preventDefault() if (!validateForm()) { toast.error('Исправьте ошибки в форме') return } // Подготавливаем данные для отправки const employeeData = { firstName: formData.firstName, lastName: formData.lastName, middleName: formData.middleName || undefined, phone: formData.phone, email: formData.email || undefined, position: formData.position, salary: formData.salary || undefined, avatar: formData.avatar || undefined, birthDate: formData.birthDate || undefined, telegram: formData.telegram || undefined, whatsapp: formData.whatsapp || undefined, passportPhoto: formData.passportPhoto || undefined, hireDate: new Date().toISOString().split('T')[0] } onSave(employeeData) } // Компонент для отображения ошибок const ErrorMessage = ({ error }: { error: string }) => { if (!error) return null return (
{error}
) } const getInitials = () => { const first = formData.firstName.charAt(0).toUpperCase() const last = formData.lastName.charAt(0).toUpperCase() return `${first}${last}` } return (
{/* Заголовок */}

Быстрое добавление сотрудника

(табель работы будет доступен после создания)
{/* Аватар с возможностью загрузки */}
{formData.avatar && formData.avatar.trim() !== '' ? ( ) : null} {getInitials() || }
{/* Основные поля в одну строку */}
{/* Имя */}
handleInputChange('firstName', e.target.value)} placeholder="Имя *" className={`glass-input text-white placeholder:text-white/40 h-10 text-sm ${errors.firstName ? 'border-red-400' : ''}`} required />
{/* Фамилия */}
handleInputChange('lastName', e.target.value)} placeholder="Фамилия *" className={`glass-input text-white placeholder:text-white/40 h-10 text-sm ${errors.lastName ? 'border-red-400' : ''}`} required />
{/* Должность */}
handleInputChange('position', e.target.value)} placeholder="Должность *" className={`glass-input text-white placeholder:text-white/40 h-10 text-sm ${errors.position ? 'border-red-400' : ''}`} required />
{/* Телефон */}
handleInputChange('phone', e.target.value)} placeholder="Телефон *" className={`glass-input text-white placeholder:text-white/40 h-10 text-sm ${errors.phone ? 'border-red-400' : ''}`} required />
{/* Email */}
handleInputChange('email', e.target.value)} placeholder="Email" className={`glass-input text-white placeholder:text-white/40 h-10 text-sm ${errors.email ? 'border-red-400' : ''}`} />
{/* Зарплата */}
handleSalaryChange(e.target.value)} placeholder="Зарплата" className={`glass-input text-white placeholder:text-white/40 h-10 text-sm ${errors.salary ? 'border-red-400' : ''}`} />
{/* Кнопки управления */}
{/* Дополнительные поля - всегда видимы */}

Дополнительная информация

{/* Дата рождения */}
handleInputChange('birthDate', e.target.value)} className={`glass-input text-white h-9 text-sm ${errors.birthDate ? 'border-red-400' : ''}`} />
{/* Telegram */}
handleInputChange('telegram', e.target.value)} placeholder="@username" className={`glass-input text-white placeholder:text-white/40 h-9 text-sm ${errors.telegram ? 'border-red-400' : ''}`} />
{/* WhatsApp */}
handleInputChange('whatsapp', e.target.value)} placeholder="+7 (999) 123-45-67" className={`glass-input text-white placeholder:text-white/40 h-9 text-sm ${errors.whatsapp ? 'border-red-400' : ''}`} />
{/* Фото паспорта */}
{formData.passportPhoto && formData.passportPhoto.trim() !== '' ? ( Фото паспорта ) : ( Не загружено )}
{/* Скрытые input для загрузки файлов */} e.target.files?.[0] && handleFileUpload(e.target.files[0], 'avatar')} className="hidden" disabled={isUploadingAvatar} /> e.target.files?.[0] && handleFileUpload(e.target.files[0], 'passport')} className="hidden" disabled={isUploadingPassport} />
) }