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,4 +1,4 @@
import type { Media, PaginatedResponse } from "@/domain/types"
import type { Media, MediaDetails, PaginatedResponse } from "@/domain/types"
import apiClient from "@/services/api-client"
type MediaListParams = {
@@ -6,6 +6,16 @@ type MediaListParams = {
limit: number
}
const API_PREFIX = import.meta.env.VITE_PREFIX_PATH || '';
export const processMediaUrls = (media: Media): Media => ({
...media,
file_url: `${API_PREFIX}${media.file_url}`,
thumbnail_url: media.thumbnail_url
? `${API_PREFIX}${media.thumbnail_url}`
: null,
});
/**
* Fetches a paginated list of media.
*/
@@ -13,23 +23,13 @@ export const getMediaList = async ({
page,
limit,
}: MediaListParams): Promise<PaginatedResponse<Media>> => {
const { data } = await apiClient.get('/media', {
const { data } = await apiClient.get("/media", {
params: { page, limit },
})
});
// we need to append base url to file_url and thumbnail_url
const prefix = import.meta.env.VITE_PREFIX_PATH || apiClient.defaults.baseURL;
data.data = data.data.map((media: Media) => ({
...media,
file_url: `${prefix}${media.file_url}`,
thumbnail_url: media.thumbnail_url
? `${prefix}${media.thumbnail_url}`
: null,
}))
return data
}
data.data = data.data.map(processMediaUrls);
return data;
};
/**
* Uploads a new media file.
@@ -38,19 +38,39 @@ export const uploadMedia = async (
file: File,
onProgress: (progress: number) => void,
): Promise<Media> => {
const formData = new FormData()
formData.append('file', file)
const formData = new FormData();
formData.append("file", file);
const { data } = await apiClient.post('/media', formData, {
const { data } = await apiClient.post("/media", formData, {
headers: {
'Content-Type': 'multipart/form-data',
"Content-Type": "multipart/form-data",
},
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / (progressEvent.total ?? 100),
)
onProgress(percentCompleted)
);
onProgress(percentCompleted);
},
})
return data
}
});
// Process the single media object returned by the upload
return processMediaUrls(data);
};
/**
* Fetches the details for a single media item.
*/
export const getMediaDetails = async (
mediaId: string,
): Promise<MediaDetails> => {
const { data } = await apiClient.get(`/media/${mediaId}`);
// Process the nested media object's URLs
data.media = processMediaUrls(data.media);
return data;
};
/**
* Deletes a media item by its ID.
*/
export const deleteMedia = async (mediaId: string): Promise<void> => {
await apiClient.delete(`/media/${mediaId}`);
};