import React, { useState } from "react"; import { Search, Upload, X } from "lucide-react"; import { useParams } from "react-router-dom"; import { eventPhotoApi } from "../api/eventPhoto"; export function EventPhotoSearchPage() { const { eventId = "" } = useParams<{ eventId: string }>(); const [queryFile, setQueryFile] = useState(null); const [searching, setSearching] = useState(false); const [results, setResults] = useState([]); const [error, setError] = useState(null); const handleFileChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0] ?? null; if (!file) return; setQueryFile(file); setResults([]); setError(null); }; const clearFile = () => { setQueryFile(null); setResults([]); setError(null); }; const handleSearch = async () => { if (!eventId) { setError("Missing event id."); return; } if (!queryFile) { setError("Please select a photo."); return; } setSearching(true); setError(null); try { const response = await eventPhotoApi.searchPublicEventPhotos( eventId, queryFile ); if (!response.ok) { let message = response.statusText || "Search failed"; try { const body = await response.json(); message = body?.error?.message || body?.message || message; } catch { // Ignore JSON parse errors and use the default HTTP error } throw new Error(message); } const body = await response.json(); const matches = Array.isArray(body?.data?.matches) ? body.data.matches : []; setResults(matches); if (matches.length === 0 && body?.message) { setError(body.message); } } catch (err) { setError( err instanceof Error ? err.message : "Photo search failed." ); setResults([]); } finally { setSearching(false); } }; return (
{/* Page Header */}
Event Photo Search

Search Event Photos

Upload a photo to find matching photos from this event.

{/* Search Card */}
{/* Card Header */}
Find Photos
Select one photo to search for matching event photos.
{!queryFile ? ( /* Upload Area */ ) : ( /* Selected Photo */
{queryFile.name}
Query photo selected
{/* Search Button */}
)} {error && (
{error}
)}
{/* Loading */} {searching && (
Searching matching photos...
)} {/* Results */} {results.length > 0 && (

Matching Photos

{results.length} matching photo {results.length !== 1 ? "s" : ""} found

{results.map((photo) => (
{photo.url && ( { )}
{photo.originalFileName || "Event photo"}
{typeof photo.similarity === "number" && (
Match:{" "} {( Math.round(photo.similarity * 10) / 10 ).toFixed(1)} %
)}
))}
)} {/* No Results */} {!searching && queryFile && results.length === 0 && !error && (
No matching photos
Search for another photo from this event.
)}
); }