import type { PhotosSectionId } from './shared'; import type { TimelineFilter } from './usePhotosData'; import { useCallback, useMemo, useRef, useState } from 'react'; import { Trash2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { useClient } from 'hooks/useClient'; import { AssetViewer } from './AssetViewer'; import { SelectionBar } from './SelectionBar'; import { TimelineGrid } from './TimelineGrid'; import { useAssetActions } from './useAssetActions'; import { useBucketAssets, useTimeBuckets } from './usePhotosData'; import { useSelection } from './useSelection'; // Timeline, Favorites, Archive and Trash are the same screen with a different filter — which is also true in // Immich, and is why the bucket API takes the filter as query params rather than having four endpoints. const FILTERS: Partial> = { timeline: { visibility: 'timeline', withPartners: true, withStacked: true }, favorites: { isFavorite: true, withStacked: true }, archive: { visibility: 'archive', withStacked: true }, trash: { isTrashed: true }, }; const TITLES: Partial> = { timeline: 'Photos', favorites: 'Favorites', archive: 'Archive', trash: 'Trash', }; type TimelineSectionProps = { section: PhotosSectionId }; export const TimelineSection = ({ section }: TimelineSectionProps) => { const { token } = useClient(); const scrollRef = useRef(null); const [loaded, setLoaded] = useState([]); const { emptyTrash } = useAssetActions(); const filter = FILTERS[section] ?? FILTERS.timeline!; const inTrash = section === 'trash'; const { data: buckets, isLoading } = useTimeBuckets(filter); const assetsByBucket = useBucketAssets(filter, loaded); const orderedIds = useMemo( () => (buckets ?? []).flatMap((bucket) => (assetsByBucket[bucket.timeBucket] ?? []).map((asset) => asset.id)), [buckets, assetsByBucket], ); const selection = useSelection(orderedIds); const onBucketVisible = useCallback((bucket: string) => { setLoaded((prev) => (prev.includes(bucket) ? prev : [...prev, bucket])); }, []); const total = (buckets ?? []).reduce((sum, bucket) => sum + bucket.count, 0); return (
{selection.isSelecting ? ( ) : (

{TITLES[section] ?? 'Photos'}

{total.toLocaleString()} items
{inTrash && total > 0 && ( )}
)}
{isLoading &&

Loading…

} {!isLoading && total === 0 &&

Nothing here.

}
); };