import React, { useState, useEffect } from 'react'; import { WorkPhoto } from '../../types'; import { apiClient } from '../../services/apiClient'; import { Plus, Loader2, Image as ImageIcon, Calendar, Building2, FileText, X } from 'lucide-react'; const UPLOADS_BASE = (import.meta.env.VITE_API_BASE_URL || 'http://localhost:4000/api').replace(/\/api\/?$/, '') || 'http://localhost:4000'; export const WorkPhotosDirectory: React.FC = () => { const [photos, setPhotos] = useState([]); const [isLoading, setIsLoading] = useState(true); const [loadError, setLoadError] = useState(null); const [showCreateForm, setShowCreateForm] = useState(false); const loadPhotos = async () => { try { setIsLoading(true); setLoadError(null); const data = await apiClient.get('/pr/work-photos'); setPhotos(Array.isArray(data) ? data : []); } catch (err: any) { console.error('Error loading work photos:', err); setPhotos([]); setLoadError(err?.message || 'Не удалось загрузить список. Проверьте подключение к серверу.'); } finally { setIsLoading(false); } }; useEffect(() => { loadPhotos(); }, []); const handleDelete = async (id: number) => { if (!confirm('Удалить запись из справочника?')) return; try { await apiClient.delete(`/pr/work-photos/${id}`); await loadPhotos(); } catch (err) { console.error('Error deleting work photo:', err); alert('Ошибка удаления'); } }; return (

Справочник фотоотчётов (до / после)

{showCreateForm && ( setShowCreateForm(false)} onSuccess={() => { setShowCreateForm(false); loadPhotos(); }} /> )} {loadError && (

{loadError}

)} {isLoading ? (
) : photos.length === 0 && !loadError ? (

Записей пока нет

Добавьте фотоотчёт с полями: фото до, фото после, описание работы, дата работы, дом.

) : photos.length === 0 ? null : (
{photos.map((photo) => ( ))}
Фото до Фото после Описание работы Дата работы Дом
{(photo as any).photoBeforeUrl || photo.photoBeforeUrl ? ( До ) : (
)}
{(photo as any).photoAfterUrl || photo.photoAfterUrl ? ( После ) : (
)}
{(photo as any).workName || photo.workName} {((photo as any).description || photo.description) && (

{(photo as any).description || photo.description}

)}
{new Date((photo as any).workDate || photo.workDate).toLocaleDateString('ru-RU', { day: 'numeric', month: 'short', year: 'numeric' })} {(photo as any).address || photo.address || (photo as any).buildingId || photo.buildingId || '—'}
)}
); }; interface WorkPhotoCreateFormProps { onClose: () => void; onSuccess: () => void; } const WorkPhotoCreateForm: React.FC = ({ onClose, onSuccess }) => { const [formData, setFormData] = useState({ building_id: '', work_name: '', work_date: new Date().toISOString().split('T')[0], description: '', }); const [photoBefore, setPhotoBefore] = useState(null); const [photoAfter, setPhotoAfter] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [buildings, setBuildings] = useState<{ id: string; address?: string }[]>([]); useEffect(() => { apiClient.get<{ id: string; passport?: { address?: string } }[]>('/buildings').then((list) => { setBuildings((list || []).map((b) => ({ id: b.id, address: b.passport?.address }))); }).catch(() => setBuildings([])); }, []); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.building_id || !formData.work_name || !formData.work_date) { alert('Заполните: дом, описание работы, дата работы'); return; } if (!photoBefore || !photoAfter) { alert('Загрузите оба фото: «До» и «После»'); return; } try { setIsSubmitting(true); const fd = new FormData(); fd.append('building_id', formData.building_id); fd.append('work_name', formData.work_name); fd.append('work_date', formData.work_date); if (formData.description) fd.append('description', formData.description); fd.append('photo_before', photoBefore); fd.append('photo_after', photoAfter); const API_BASE = import.meta.env.VITE_API_BASE_URL || 'http://localhost:4000/api'; const res = await fetch(`${API_BASE}/pr/work-photos`, { method: 'POST', body: fd }); if (!res.ok) throw new Error('Ошибка создания'); onSuccess(); } catch (err) { console.error(err); alert('Не удалось создать запись'); } finally { setIsSubmitting(false); } }; return (

Новая запись в справочнике

setFormData({ ...formData, work_name: e.target.value })} className="w-full p-3 border border-slate-200 rounded-xl text-sm" placeholder="Например: Ремонт подъезда" required />
setFormData({ ...formData, work_date: e.target.value })} className="w-full p-3 border border-slate-200 rounded-xl text-sm" required />