import React, { useState } from 'react'; import { Vacancy } from '../../types'; import { X, Briefcase, DollarSign, FileText, Users, Calendar, AlertCircle } from 'lucide-react'; import { authFetch } from '../../services/apiClient'; interface VacancyFormModalProps { vacancy?: Vacancy | null; onClose: () => void; onSave: (vacancy: Vacancy) => void; } export const VacancyFormModal: React.FC = ({ vacancy, onClose, onSave }) => { const isEditMode = !!vacancy; const [formData, setFormData] = useState({ position: vacancy?.position || '', department: vacancy?.department || '', status: vacancy?.status || 'active' as 'urgent' | 'active' | 'paused' | 'closed', salary: vacancy?.salary || '', description: vacancy?.description || '', requirements: vacancy?.requirements || '', conditions: vacancy?.conditions || '', responsibilities: vacancy?.responsibilities || '', postedDate: vacancy?.postedDate || new Date().toISOString().split('T')[0], closingDate: vacancy?.closingDate || '', }); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.position || !formData.department || !formData.description) { alert('Заполните обязательные поля: позиция, отдел и описание'); return; } try { const apiBaseUrl = import.meta.env.VITE_API_BASE_URL; const apiUrl = (import.meta.env.DEV || !apiBaseUrl) ? `/api/vacancies${isEditMode ? `/${vacancy.id}` : ''}` : `${apiBaseUrl}/vacancies${isEditMode ? `/${vacancy.id}` : ''}`; const method = isEditMode ? 'PUT' : 'POST'; const body = { ...(isEditMode ? {} : { id: `vac-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` }), position: formData.position.trim(), department: formData.department.trim(), status: formData.status, salary: formData.salary.trim() || null, description: formData.description.trim(), requirements: formData.requirements.trim() || null, conditions: formData.conditions.trim() || null, responsibilities: formData.responsibilities.trim() || null, postedDate: formData.postedDate, closingDate: formData.closingDate.trim() || null, }; const response = await authFetch(apiUrl, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); if (!response.ok) { let errorMessage = `Ошибка ${response.status}: ${response.statusText}`; try { // Сначала читаем как текст, затем пытаемся распарсить как JSON const text = await response.text(); if (text) { try { const errorData = JSON.parse(text); errorMessage = errorData.error || errorData.message || text; } catch { // Если не JSON, используем текст как есть errorMessage = text; } } } catch (textError) { // Если не удалось прочитать ответ, используем дефолтное сообщение console.error('Failed to read error response:', textError); } throw new Error(errorMessage); } const savedVacancy = await response.json(); onSave(savedVacancy); } catch (error) { console.error('Error saving vacancy:', error); let errorMessage = 'Ошибка при сохранении вакансии'; if (error instanceof Error) { errorMessage = error.message; // Проверяем на сетевые ошибки if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) { errorMessage = 'Ошибка сети. Проверьте подключение к серверу.'; } } alert(errorMessage); } }; return (
e.stopPropagation()} > {/* Header */}

{isEditMode ? 'Редактирование вакансии' : 'Создание новой вакансии'}

{/* Form */}
{/* Основная информация */}

Основная информация

setFormData({ ...formData, position: e.target.value })} placeholder="Слесарь-сантехник (4-5 разряд)" className="w-full p-3 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-primary-500 outline-none" required />
setFormData({ ...formData, department: e.target.value })} placeholder="Тех. отдел" className="w-full p-3 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-primary-500 outline-none" required />
setFormData({ ...formData, salary: e.target.value })} placeholder="55 000 - 65 000 ₽" className="w-full p-3 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-primary-500 outline-none" />
setFormData({ ...formData, postedDate: e.target.value })} className="w-full p-3 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-primary-500 outline-none" />
setFormData({ ...formData, closingDate: e.target.value })} className="w-full p-3 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-primary-500 outline-none" />
{/* Описание */}

Описание вакансии