import { useState } from 'react' import { format } from 'date-fns' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { guessDateFromPath, type DateGuess, } from '../../lib/guessDateFromPath' import type { Photo } from '../../types/photo' interface BulkTakenAtEditorProps { disabled: boolean selectedCount: number collectPhotos: () => Photo[] onApplyUniform: (iso: string) => void onApplyMap: (map: Record) => void } /** Bulk Date Taken sub-panel used by RightSidebar in multi-select mode. * Two modes share one UI: * 1. Apply-one: user types a datetime, clicks Apply, every selected * photo is rewritten to that date. * 2. Guess-from-path: we run `guessDateFromPath` against each selected * photo's filepath, show a preview of the hits + misses, and let * the user commit the per-photo map in one round-trip. */ export function BulkTakenAtEditor({ disabled, selectedCount, collectPhotos, onApplyUniform, onApplyMap, }: BulkTakenAtEditorProps) { const [uniformDraft, setUniformDraft] = useState('') const [preview, setPreview] = useState< | { hits: { photo: Photo; guess: DateGuess }[] misses: Photo[] } | null >(null) const handleGuess = () => { const photos = collectPhotos() const hits: { photo: Photo; guess: DateGuess }[] = [] const misses: Photo[] = [] for (const p of photos) { const g = guessDateFromPath(p.filepath) if (g) hits.push({ photo: p, guess: g }) else misses.push(p) } setPreview({ hits, misses }) } const handleApplyPreview = () => { if (!preview) return const map: Record = {} for (const { photo, guess } of preview.hits) { map[photo.id] = guess.date.toISOString() } if (Object.keys(map).length === 0) return onApplyMap(map) setPreview(null) } const handleApplyUniform = () => { if (!uniformDraft) return const parsed = new Date(uniformDraft) if (Number.isNaN(parsed.getTime())) return onApplyUniform(parsed.toISOString()) } return (
{/* Apply-one row */}
setUniformDraft(e.target.value)} disabled={disabled} className="h-7 flex-1 text-xs" />
{/* Guess-from-path preview */} {preview === null ? ( ) : (
{preview.hits.length} will update ·{' '} {preview.misses.length} skipped
{preview.hits.length > 0 && (
    {preview.hits.slice(0, 5).map(({ photo, guess }) => (
  • {photo.filename} {' → '} {format(guess.date, 'yyyy-MM-dd')}
  • ))} {preview.hits.length > 5 && (
  • …and {preview.hits.length - 5} more
  • )}
)}
)}
) }