feat: Implement person management features

- Added hooks for listing, creating, updating, deleting, sharing, and merging people.
- Introduced a new route for person details and media.
- Implemented clustering faces functionality.
- Created services for person-related API interactions.

feat: Introduce tag management functionality

- Added hooks for listing, adding, and removing tags from media.
- Created services for tag-related API interactions.

feat: Enhance user authentication handling

- Added a hook to fetch current user details.
- Updated auth storage to manage user state more effectively.

feat: Update album management features

- Enhanced album service to return created album details.
- Updated API handlers to return album responses upon creation.
- Modified album repository to return created album.

feat: Implement media management improvements

- Added media details fetching and processing of media URLs.
- Enhanced media upload functionality to return processed media.

feat: Introduce face management features

- Added services for listing faces for media and assigning faces to persons.

fix: Update API client to clear authentication state on 401 errors.
This commit is contained in:
2025-11-16 02:24:50 +01:00
parent f41a3169e9
commit 94b184d3b0
34 changed files with 1300 additions and 281 deletions

View File

@@ -1,58 +1,71 @@
import type { Album, Media } from "@/domain/types"
import apiClient from "@/services/api-client"
import type { Album, AlbumPermission, Media } from "@/domain/types";
import apiClient from "@/services/api-client";
import { processMediaUrls } from "./media-service";
// --- Types ---
export type CreateAlbumPayload = {
name: string
description?: string
}
name: string;
description?: string;
};
/**
* Fetches a list of albums.
* TODO: This should become paginated later.
*/
export const getAlbums = async (): Promise<Album[]> => {
const { data } = await apiClient.get('/albums')
return data
}
/**
* Creates a new album.
*/
export const createAlbum = async (
payload: CreateAlbumPayload,
): Promise<Album> => {
const { data } = await apiClient.post('/albums', payload)
return data
}
/**
* Fetches all media for a specific album.
*/
export const getAlbumMedia = async (albumId: string): Promise<Media[]> => {
const { data } = await apiClient.get(`/albums/${albumId}/media`);
const prefix = import.meta.env.VITE_PREFIX_PATH || apiClient.defaults.baseURL;
const processedMedia = data.map((media: Media) => ({
...media,
file_url: `${prefix}${media.file_url}`,
thumbnail_url: media.thumbnail_url
? `${prefix}${media.thumbnail_url}`
: null,
}));
return processedMedia;
export type UpdateAlbumPayload = Partial<CreateAlbumPayload> & {
is_public?: boolean;
};
export type AddMediaToAlbumPayload = {
media_ids: string[];
};
/**
* Adds a list of media IDs to a specific album.
*/
export type RemoveMediaFromAlbumPayload = {
media_ids: string[];
};
export type ShareAlbumPayload = {
target_user_id: string;
permission: AlbumPermission;
};
export type SetAlbumThumbnailPayload = {
media_id: string;
};
// --- Service Functions ---
export const getAlbums = async (): Promise<Album[]> => {
const { data } = await apiClient.get("/albums");
return data; // Album object doesn't have URLs
};
export const getAlbum = async (albumId: string): Promise<Album> => {
const { data } = await apiClient.get(`/albums/${albumId}`);
return data; // Album object doesn't have URLs
};
export const createAlbum = async (
payload: CreateAlbumPayload,
): Promise<Album> => {
const { data } = await apiClient.post("/albums", payload);
return data;
};
export const updateAlbum = async (
albumId: string,
payload: UpdateAlbumPayload,
): Promise<Album> => {
const { data } = await apiClient.put(`/albums/${albumId}`, payload);
return data;
};
export const deleteAlbum = async (albumId: string): Promise<void> => {
await apiClient.delete(`/albums/${albumId}`);
};
export const getAlbumMedia = async (albumId: string): Promise<Media[]> => {
const { data } = await apiClient.get(`/albums/${albumId}/media`);
return data.map(processMediaUrls); // Process all media URLs
};
export const addMediaToAlbum = async (
albumId: string,
payload: AddMediaToAlbumPayload,
@@ -60,24 +73,23 @@ export const addMediaToAlbum = async (
await apiClient.post(`/albums/${albumId}/media`, payload);
};
/**
* Fetches a single album by its ID.
*/
export const getAlbum = async (albumId: string): Promise<Album> => {
const { data } = await apiClient.get(`/albums/${albumId}`);
return data;
};
export type RemoveMediaFromAlbumPayload = {
media_ids: string[];
};
/**
* Removes a list of media IDs from a specific album.
*/
export const removeMediaFromAlbum = async (
albumId: string,
payload: RemoveMediaFromAlbumPayload,
): Promise<void> => {
await apiClient.delete(`/albums/${albumId}/media`, { data: payload });
};
export const shareAlbum = async (
albumId: string,
payload: ShareAlbumPayload,
): Promise<void> => {
await apiClient.post(`/albums/${albumId}/share`, payload);
};
export const setAlbumThumbnail = async (
albumId: string,
payload: SetAlbumThumbnailPayload,
): Promise<void> => {
await apiClient.put(`/albums/${albumId}/thumbnail`, payload);
};