feat: add functionality to remove media from album, including API integration and UI context menu

This commit is contained in:
2025-11-16 01:47:36 +01:00
parent 07b797b82b
commit f41a3169e9
9 changed files with 169 additions and 17 deletions

View File

@@ -1,9 +1,20 @@
import { AddMediaToAlbumDialog } from "@/components/albums/add-media-to-album-dialog";
import { AuthenticatedImage } from "@/components/media/authenticated-image";
import { MediaViewer } from "@/components/media/media-viewer";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@/components/ui/context-menu";
import type { Media } from "@/domain/types";
import { useGetAlbum, useGetAlbumMedia } from "@/features/albums/use-albums";
import {
useGetAlbum,
useGetAlbumMedia,
useRemoveMediaFromAlbum,
} from "@/features/albums/use-albums";
import { createFileRoute } from "@tanstack/react-router";
import { Eye, Trash2 } from "lucide-react";
import { useState } from "react";
export const Route = createFileRoute("/albums/$albumId")({
@@ -12,11 +23,30 @@ export const Route = createFileRoute("/albums/$albumId")({
function AlbumDetailPage() {
const { albumId } = Route.useParams();
const { data: album, isLoading: isLoadingAlbum } = useGetAlbum(albumId);
const { data: media, isLoading: isLoadingMedia } = useGetAlbumMedia(albumId);
const {
data: album,
isLoading: isLoadingAlbum,
error: albumError,
} = useGetAlbum(albumId);
const {
data: media,
isLoading: isLoadingMedia,
error: mediaError,
} = useGetAlbumMedia(albumId);
const [selectedMedia, setSelectedMedia] = useState<Media | null>(null);
const { mutate: removeMedia, isPending: isRemoving } =
useRemoveMediaFromAlbum();
const isLoading = isLoadingAlbum || isLoadingMedia;
const error = albumError || mediaError;
const handleRemoveMedia = (mediaId: string) => {
removeMedia({
albumId,
payload: { media_ids: [mediaId] },
});
};
return (
<div className="space-y-6">
@@ -28,21 +58,39 @@ function AlbumDetailPage() {
</div>
{isLoading && <p>Loading photos...</p>}
{error && <p>Error loading photos: {error.message}</p>}
{media && media.length > 0 && (
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-2">
{media.map((m) => (
<div
key={m.id}
className="aspect-square bg-gray-200 rounded-md overflow-hidden cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => setSelectedMedia(m)}
>
<AuthenticatedImage
src={m.thumbnail_url ?? m.file_url}
alt={m.original_filename}
className="w-full h-full object-cover"
/>
</div>
<ContextMenu key={m.id}>
<ContextMenuTrigger>
<div
className="aspect-square bg-gray-200 rounded-md overflow-hidden cursor-pointer hover:opacity-80 transition-opacity"
onClick={() => setSelectedMedia(m)}
>
<AuthenticatedImage
src={m.thumbnail_url ?? m.file_url}
alt={m.original_filename}
className="w-full h-full object-cover"
/>
</div>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem onSelect={() => setSelectedMedia(m)}>
<Eye className="mr-2 h-4 w-4" />
View
</ContextMenuItem>
<ContextMenuItem
className="text-destructive focus:text-destructive"
onSelect={() => handleRemoveMedia(m.id)}
disabled={isRemoving}
>
<Trash2 className="mr-2 h-4 w-4" />
Remove from Album
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
))}
</div>
)}