import { useMemo } from 'react'; import { Link, useSearchParams } from 'react-router'; import { ArrowLeft, ImageOff, MoreVertical, Plus } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { useClient } from 'hooks/useClient'; import { AssetViewer } from './AssetViewer'; import { PhotoGrid } from './PhotoGrid'; import { SelectionBar } from './SelectionBar'; import { ALBUM_PARAM, formatDateRange, thumbUrl, toGridAsset } from './shared'; import { useAlbum, useAlbums } from './usePhotosData'; import { useAssetActions } from './useAssetActions'; import { useSelection } from './useSelection'; // Two states in one section, switched by `?album=`: the wall of album covers, and one album's photos. // A separate `/photos/albums/:id` route would work too, but the album is a selection inside the section — the // same shape as `?selected=` elsewhere in the app — and this keeps the nav highlight where it belongs. export const AlbumsSection = () => { const [params] = useSearchParams(); const albumId = params.get(ALBUM_PARAM); return albumId ? : ; }; const AlbumListView = () => { const { token } = useClient(); const { data: albums, isLoading } = useAlbums(); const { createAlbum, deleteAlbum, renameAlbum } = useAssetActions(); const sorted = useMemo(() => [...(albums ?? [])].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)), [albums]); return (

Albums

{sorted.length}
{isLoading &&

Loading…

} {!isLoading && sorted.length === 0 &&

No albums yet.

}
{sorted.map((album) => (
{album.albumThumbnailAssetId ? ( ) : (
)}

{album.albumName}

{album.assetCount} items {album.shared ? ' · shared' : ''}

{ const albumName = window.prompt('Rename album', album.albumName); if (albumName) renameAlbum.mutate({ albumId: album.id, albumName }); }} > Rename window.confirm(`Delete "${album.albumName}"?`) && deleteAlbum.mutate(album.id)} > Delete album
))}
); }; const AlbumDetailView = ({ albumId }: { albumId: string }) => { const { token } = useClient(); const [params] = useSearchParams(); const { data: album, isLoading } = useAlbum(albumId); const assets = useMemo(() => (album?.assets ?? []).map(toGridAsset), [album]); const selection = useSelection(assets.map((asset) => asset.id)); const back = (() => { const next = new URLSearchParams(params); next.delete(ALBUM_PARAM); const search = next.toString(); return search ? `?${search}` : '?'; })(); const range = formatDateRange(album?.startDate, album?.endDate); return (
{selection.isSelecting ? ( ) : (

{album?.albumName ?? 'Album'}

{album?.assetCount ?? 0} items{range ? ` · ${range}` : ''}

)}
{isLoading ? (

Loading…

) : ( This album is empty.

} /> )}
asset.id)} token={token} />
); };