Files
photos/frontend/src/useSelection.js
T
nils 72bcd7a385
ci / docker (push) Successful in 13m22s
Client accept/reject votes with keyboard-driven culling
- verdicts table (per link, like ratings), PUT verdict endpoint, typed Verdict enum
- share page: thumbs up/down, verdict filter with counts, view-scoped selection bar
- lightbox: per-page shortcut table (P/X/U, 1-5/0, S), ? help overlay, action
  toast when a keyboard vote auto-advances
- shared useLightbox hook; single keydown subscription reading live state via ref
- album view: per-link thumbs and vote counts; share list shows accept/reject totals
- feedback queries deduped and run concurrently; verdict counts in one scan
2026-07-17 15:55:46 +02:00

36 lines
1.4 KiB
JavaScript

import { useEffect, useState } from 'react'
// Multi-select over a photo list. Selection lives here (not in the gallery)
// so it survives lightbox open/close, and is pruned automatically when
// photos disappear from the list (deletes, polling refreshes).
export default function useSelection(photos) {
const [selected, setSelected] = useState(() => new Set())
useEffect(() => {
setSelected((prev) => {
if (prev.size === 0) return prev
const valid = new Set(photos.map((p) => p.id))
const next = new Set([...prev].filter((id) => valid.has(id)))
return next.size === prev.size ? prev : next
})
}, [photos])
const toggle = (photoId) =>
setSelected((prev) => {
const next = new Set(prev)
if (next.has(photoId)) next.delete(photoId)
else next.add(photoId)
return next
})
// Adds `list` (the caller's currently visible photos) to the selection —
// additive, so selecting all of one filtered view keeps picks from another.
const selectAll = (list) =>
setSelected((prev) => new Set([...prev, ...list.map((p) => p.id)]))
const clear = () => setSelected(new Set())
const selectedBytes = photos.reduce((sum, p) => sum + (selected.has(p.id) ? p.size_bytes : 0), 0)
const totalBytes = photos.reduce((sum, p) => sum + p.size_bytes, 0)
return { selected, toggle, selectAll, clear, selectedBytes, totalBytes }
}