"use client"; /* Загрузка фото квартиры к оценке (#394). */ /* eslint-disable @next/next/no-img-element -- фото отдаёт API, next/image тут лишний */ import { useCallback, useEffect, useRef, useState } from "react"; import { API_BASE_URL } from "@/lib/api"; import { getOrCreateSessionId } from "@/lib/sessionId"; const BASE = "/api/v1/trade-in"; const MAX_PHOTOS = 12; interface PhotoMeta { id: string; filename: string | null; content_type: string; size_bytes: number | null; uploaded_at: string; } export function PhotoUpload({ estimateId }: { estimateId: string }) { const [photos, setPhotos] = useState([]); const [uploading, setUploading] = useState(false); const [error, setError] = useState(null); const inputRef = useRef(null); const refresh = useCallback(async () => { try { const r = await fetch(`${API_BASE_URL}${BASE}/estimate/${estimateId}/photos`); if (r.ok) setPhotos((await r.json()) as PhotoMeta[]); } catch { /* список фото некритичен — молча игнорируем */ } }, [estimateId]); useEffect(() => { void refresh(); }, [refresh]); async function handleFiles(files: FileList | null) { if (!files || files.length === 0) return; setUploading(true); setError(null); const sid = getOrCreateSessionId(); for (const file of Array.from(files)) { const form = new FormData(); form.append("file", file); try { const r = await fetch( `${API_BASE_URL}${BASE}/estimate/${estimateId}/photos`, { method: "POST", body: form, headers: sid ? { "X-Session-Id": sid } : {}, }, ); if (!r.ok) setError(`${file.name}: ошибка загрузки (${r.status})`); } catch { setError(`${file.name}: сеть недоступна`); } } setUploading(false); if (inputRef.current) inputRef.current.value = ""; await refresh(); } const full = photos.length >= MAX_PHOTOS; return (

Фото квартиры

{photos.length} / {MAX_PHOTOS}
handleFiles(e.target.files)} /> {uploading && (

Загрузка…

)} {full && !uploading && (

Достигнут лимит {MAX_PHOTOS} фото.

)} {error && (

{error}

)} {photos.length > 0 && (
{photos.map((p) => ( {p.filename ))}
)}
); }