Pick and add-to-heap were two ways of saying "I want to keep this
one". Merging them: P now toggles the selection's membership in the
active heap. The is_picked flag goes away (orphaned in the DB the
same way is_trashed was).
Backend
- Drop is_picked from PhotoBase / PhotoUpdate / PhotoResponse and
from the photos list filter param.
- Drop the is_picked Column from the Photo model (DB column stays
on legacy installs but is no longer read or written).
- Drop the bulk action 'pick' branch.
- New GET /heaps/{id}/photo_ids returns just the flat string list.
Used by the frontend for fast client-side membership lookups
without fetching full photo records.
Frontend
- New hooks/useActiveHeapMembersQuery.ts → returns
{ activeHeap, memberIds: Set<string> }. Subscribes once at the
Timeline level and passes a derived isInActiveHeap bool down to
each PhotoThumbnail (avoids hundreds of thumbnails subscribing
to the same query).
- PhotoThumbnail: replaces the old check-icon Pick affordance with
a clear basket badge in the bottom-right corner — a small filled
pick-colour pill containing a ShoppingBasket icon — visible only
when the photo belongs to the active heap.
- P shortcut (useKeyboardShortcuts) now toggles membership: if every
selected photo is already a member, it removes them; otherwise it
adds the missing ones. T binding removed (P fully replaces it).
- RightSidebar Pick button is now a Pick / Picked toggle bound to
the active heap. Disabled with a hint when no heap is active.
Shows the heap name in its title attr.
- filterStore drops 'picked' and 'unflagged' from FlagFilter.
FilterBar's flag dropdown is now just Any / Discarded.
- LeftSidebar drops the "Flagged" virtual node (it just set
flag=picked, which no longer exists).
- KeyboardHints: P → "Pick → heap".
- Photo TS type drops is_picked.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import { useMemo } from 'react'
|
|
import { useQuery } from '@tanstack/react-query'
|
|
import { useHeapsQuery } from './useHeapsQuery'
|
|
import { heaps as heapsApi } from '../services/api'
|
|
|
|
const EMPTY_SET: ReadonlySet<string> = new Set()
|
|
|
|
/**
|
|
* Returns the photo ids that belong to the active heap as a Set, plus the
|
|
* active heap itself. Used by PhotoThumbnail to render the basket affordance
|
|
* and by the P shortcut to decide between add vs remove.
|
|
*
|
|
* If no heap is active, the Set is empty (and shared across renders).
|
|
*/
|
|
export function useActiveHeapMembers(): {
|
|
activeHeap: ReturnType<typeof useHeapsQuery>['data'] extends (infer T)[] | undefined
|
|
? T | null
|
|
: never
|
|
memberIds: ReadonlySet<string>
|
|
} {
|
|
const { data: heaps } = useHeapsQuery()
|
|
const activeHeap = heaps?.find((h) => h.is_active) ?? null
|
|
|
|
const { data: ids } = useQuery({
|
|
queryKey: ['heap-photo-ids', activeHeap?.id],
|
|
queryFn: () => heapsApi.photoIds(activeHeap!.id),
|
|
enabled: !!activeHeap,
|
|
staleTime: 30_000,
|
|
})
|
|
|
|
const memberIds = useMemo(
|
|
() => (ids ? new Set(ids) : EMPTY_SET),
|
|
[ids]
|
|
)
|
|
|
|
return { activeHeap: activeHeap as any, memberIds }
|
|
}
|
|
|
|
export const ACTIVE_HEAP_MEMBERS_QUERY_KEY_PREFIX = ['heap-photo-ids'] as const
|