Skip to content

Commit d1a52ad

Browse files
authored
Merge pull request #21 from scalefocus/feature/add-albums
Add Albums functionality
2 parents 367ad35 + d409b17 commit d1a52ad

File tree

18 files changed

+1994
-516
lines changed

18 files changed

+1994
-516
lines changed

package-lock.json

Lines changed: 1002 additions & 442 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,14 @@
4949
]
5050
},
5151
"devDependencies": {
52+
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
5253
"@types/jest": "^27.5.2",
5354
"@types/node": "^16.18.60",
5455
"@types/react": "^18.2.36",
5556
"@types/react-dom": "^18.2.14",
5657
"eslint": "^8.53.0",
5758
"eslint-config-prettier": "^9.0.0",
58-
"eslint-plugin-import": "^2.29.0",
59+
"eslint-plugin-import": "^2.32.0",
5960
"eslint-plugin-simple-import-sort": "^10.0.0",
6061
"husky": "^8.0.3",
6162
"lint-staged": "^15.0.2",

src/api/albumApi.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { useMutation, useQuery } from "@tanstack/react-query";
2+
import { Album, AlbumsResponse } from "models/Album";
3+
import { IGetObjects } from "types/types";
4+
5+
import axiosClient from "./axios";
6+
7+
export async function addAlbum({
8+
name,
9+
isSystem
10+
}: {
11+
name: string;
12+
isSystem: boolean;
13+
}): Promise<Album> {
14+
const res = await axiosClient.post('album', {
15+
name,
16+
isSystem
17+
});
18+
19+
return res.data;
20+
}
21+
22+
export const getAlbums = () =>
23+
useQuery({
24+
queryKey: ['getAlbums'],
25+
queryFn: async (): Promise<Album[]> => {
26+
const res = await axiosClient.get<AlbumsResponse>('album');
27+
return res.data.albums;
28+
},
29+
});
30+
31+
export const deleteAlbum = () =>
32+
useMutation({
33+
mutationFn: async (id: string) => {
34+
await axiosClient.delete(`album/${id}`);
35+
},
36+
});
37+
38+
export async function addObjectsToAlbum(params: { albumId: string; objectIds: string[] }) {
39+
const { albumId, objectIds } = params;
40+
const { data } = await axiosClient.post(
41+
`album/${encodeURIComponent(albumId)}/objects`, objectIds
42+
);
43+
return data;
44+
}
45+
46+
export const getAlbumItems = async ({ albumId }: { albumId: string; }): Promise<IGetObjects> => {
47+
const res = await axiosClient.get(`/album/${albumId}/100`);
48+
return res.data;
49+
};
50+
51+
export const getAlbumById = async ({ albumId }: { albumId: string; }): Promise<Album> => {
52+
const res = await axiosClient.get(`/album/${albumId}`);
53+
return res.data;
54+
};
55+
56+
export async function updateAlbum({ id, name }: {
57+
id: string
58+
name: string;
59+
}): Promise<void> {
60+
const res = await axiosClient.put('album', { id, name });
61+
return res.data;
62+
}
63+
64+
export async function bulkRemoveObjectsFromAlbum(params: { albumId: string; objectIds: string[] }) {
65+
const { albumId, objectIds } = params;
66+
const { data } = await axiosClient.post(
67+
`/albums/${encodeURIComponent(albumId)}/objects:bulk-delete`,
68+
objectIds
69+
);
70+
return data;
71+
}

src/api/api.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useQuery } from '@tanstack/react-query';
22
import axios from 'axios';
3+
import { UploadImageResponse } from 'models/UploadImageResponse';
34

45
import {
56
BASE_URL,
@@ -165,7 +166,7 @@ export async function uploadImage({
165166
}: {
166167
file: File;
167168
objectHash: string;
168-
}): Promise<void> {
169+
}): Promise<UploadImageResponse> {
169170
const res = await axiosClient.post(
170171
'object',
171172
{
@@ -180,7 +181,6 @@ export async function uploadImage({
180181
},
181182
}
182183
);
183-
184184
return res.data;
185185
}
186186

@@ -401,4 +401,4 @@ export const fetchFavoritesIds = async ({
401401
params: { lastId: pageParam, PageSize: NUMBER_OF_OBJECTS_PER_PAGE },
402402
});
403403
return res.data;
404-
};
404+
};
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import FolderIcon from '@mui/icons-material/Folder';
2+
import {
3+
CircularProgress, Dialog, DialogContent, DialogTitle, List, ListItemButton,
4+
ListItemIcon, ListItemText, Typography
5+
} from '@mui/material';
6+
import { getAlbums } from 'api/albumApi';
7+
import { Album } from 'models/Album';
8+
import * as React from 'react';
9+
10+
type Props = {
11+
open: boolean;
12+
onClose: () => void;
13+
onSelect: (albumId: string) => void;
14+
title?: string;
15+
hideSystemAlbums?: boolean;
16+
};
17+
18+
export const AddToAlbumDialog: React.FC<Props> = ({
19+
open,
20+
onClose,
21+
onSelect,
22+
title = 'Choose album',
23+
hideSystemAlbums = false,
24+
}) => {
25+
const { data: albums, isLoading, isError, error } = getAlbums();
26+
27+
const visibleAlbums = React.useMemo<Album[]>(() => {
28+
const list = albums ?? [];
29+
return hideSystemAlbums ? list.filter(a => !a.isSystem) : list;
30+
}, [albums, hideSystemAlbums]);
31+
32+
const handlePick = (id: string) => {
33+
onSelect(id);
34+
onClose();
35+
};
36+
37+
return (
38+
<Dialog
39+
open={open}
40+
onClose={onClose}
41+
fullWidth
42+
maxWidth="xs"
43+
aria-labelledby="select-album-title"
44+
>
45+
<DialogTitle id="select-album-title">{title}</DialogTitle>
46+
47+
<DialogContent dividers>
48+
{isLoading && <CircularProgress size={24} />}
49+
50+
{isError && (
51+
<Typography color="error">
52+
Error loading albums {(error as Error)?.message ?? 'Unknown error'}
53+
</Typography>
54+
)}
55+
56+
{!isLoading && !isError && visibleAlbums.length === 0 && (
57+
<Typography color="text.secondary">There are no albums to pick</Typography>
58+
)}
59+
60+
{!isLoading && !isError && visibleAlbums.length > 0 && (
61+
<List dense disablePadding>
62+
{visibleAlbums.map((album) => (
63+
<ListItemButton
64+
key={album.id}
65+
onClick={() => handlePick(album.id)}
66+
sx={{
67+
borderRadius: 1,
68+
mb: 0.5,
69+
'&:hover': { bgcolor: 'action.hover' },
70+
}}
71+
>
72+
<ListItemIcon>
73+
<FolderIcon />
74+
</ListItemIcon>
75+
76+
<ListItemText
77+
primary={album.name}
78+
secondary={new Date(album.dateCreated).toLocaleDateString()}
79+
primaryTypographyProps={{ noWrap: true, fontWeight: 600 }}
80+
secondaryTypographyProps={{ noWrap: true }}
81+
/>
82+
</ListItemButton>
83+
))}
84+
</List>
85+
)}
86+
</DialogContent>
87+
</Dialog>
88+
);
89+
};
90+
91+
export default AddToAlbumDialog;

0 commit comments

Comments
 (0)