Files
k-photos/k-photos-frontend/hooks/use-albums.ts
Gabriel Kaszewski 957737ac9b feat: frontend MVP — auth, timeline, upload, albums, admin, image viewer
Backend:
- user roles (DB + JWT + first-user-is-admin)
- volume-aware file resolver (multi-volume asset serving)
- directory scanner uses volume URI directly
- date-summary endpoint (capture date from EXIF)
- timeline ordered by capture date
- list endpoints: volumes, plugins, pipelines, library paths
- delete endpoints: volumes, library paths
- configurable upload body limit (MAX_UPLOAD_BYTES)

Frontend:
- auth: login/register, token refresh, role-based admin gate
- timeline: date-grouped grid, infinite scroll, date scrubber
- image viewer: fullscreen zoom/pan/pinch, metadata sidebar
- upload: drag-drop, sequential upload, progress tracking
- albums: create, add/remove photos, asset picker dialog
- admin: storage (import library), jobs (pagination, error details),
  plugins (list + toggle), pipelines, sidecars, duplicates
- multi-select mode with add-to-album action
- TanStack Query for all data fetching
2026-06-01 01:35:43 +02:00

68 lines
1.9 KiB
TypeScript

"use client"
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
import api from "@/lib/api"
import type {
AlbumResponse,
CreateAlbumRequest,
UpdateAlbumRequest,
} from "@/lib/types"
export function useAlbums() {
const qc = useQueryClient()
const query = useQuery({
queryKey: ["albums"],
queryFn: async () => {
const { data } = await api.get<AlbumResponse[]>("/albums")
return data
},
})
const create = useMutation({
mutationFn: async (title: string) => {
const body: CreateAlbumRequest = { title }
const { data } = await api.post<AlbumResponse>("/albums", body)
return data
},
onSuccess: () => qc.invalidateQueries({ queryKey: ["albums"] }),
})
const update = useMutation({
mutationFn: async ({ id, ...updates }: UpdateAlbumRequest & { id: string }) => {
const { data } = await api.put<AlbumResponse>(`/albums/${id}`, updates)
return data
},
onSuccess: () => qc.invalidateQueries({ queryKey: ["albums"] }),
})
const addEntry = useMutation({
mutationFn: async ({ albumId, assetId }: { albumId: string; assetId: string }) => {
await api.post(`/albums/${albumId}/entries`, { asset_id: assetId })
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["albums"] })
qc.invalidateQueries({ queryKey: ["album"] })
},
})
const removeEntry = useMutation({
mutationFn: async ({ albumId, assetId }: { albumId: string; assetId: string }) => {
await api.delete(`/albums/${albumId}/entries/${assetId}`)
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["albums"] })
qc.invalidateQueries({ queryKey: ["album"] })
},
})
return {
albums: query.data ?? [],
isLoading: query.isLoading,
createAlbum: create.mutateAsync,
updateAlbum: update.mutateAsync,
addEntry: addEntry.mutateAsync,
removeEntry: removeEntry.mutateAsync,
}
}