// Side-by-side photo comparison for a match: the visitor's own images on the left, the candidate // dog's on the right, each column scrolling independently so two photos can be lined up. Shared by // the home-page tool (uploaded images) and the sample-dog profile (that dog's bundled images). import type { DogPhoto, PhotoSearchMatch } from "../types"; import { estimatedBreeds } from "./MatchCard"; function pct(score: number): string { return `${(score * 100).toFixed(1)}%`; } /** Wrap plain image URLs (e.g. object URLs from an upload) as the photo shape this modal renders. */ export function photosFromUrls(urls: string[]): DogPhoto[] { return urls.map((src, i) => ({ id: i, url: src, thumb_url: src, is_primary: i === 0 })); } export default function ComparePhotosModal({ match, queryPhotos, queryLabel, isCorrect = false, onClose, }: { match: PhotoSearchMatch; queryPhotos: DogPhoto[]; queryLabel: string; /** Sample dogs know their planted twin, so a confirmed match can be badged. */ isCorrect?: boolean; onClose: () => void; }) { return (
e.stopPropagation()} >

Compare · {pct(match.score)} match {isCorrect && ✓ Correct match}

{estimatedBreeds(match.dog.predicted_breeds)} {match.dog.zip ? ` · ZIP ${match.dog.zip}` : ""} {match.distance_miles != null ? ` · ${match.distance_miles} mi away` : ""}

); } function PhotoColumn({ label, photos }: { label: string; photos: DogPhoto[] }) { return (

{label} ({photos.length})

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

No images.

}
); }