Skip to content

Commit 222233a

Browse files
authored
Merge pull request #25 from scalefocus/feature/display-error-on-non-empty-album
Display error if the album is not empty
2 parents c2479cc + 01f73ce commit 222233a

File tree

3 files changed

+96
-36
lines changed

3 files changed

+96
-36
lines changed

src/components/Albums/AddToAlbumDialog.tsx

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import FolderIcon from '@mui/icons-material/Folder';
22
import {
3-
CircularProgress, Dialog, DialogContent, DialogTitle, List, ListItemButton,
4-
ListItemIcon, ListItemText, Typography
3+
Button,
4+
Checkbox,
5+
CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, List, ListItemButton,
6+
ListItemIcon, ListItemText, Typography
57
} from '@mui/material';
68
import { getAlbums } from 'api/albumApi';
79
import { Album } from 'models/Album';
@@ -10,7 +12,7 @@ import * as React from 'react';
1012
type Props = {
1113
open: boolean;
1214
onClose: () => void;
13-
onSelect: (albumId: string) => void;
15+
onSelect: (albumId: string[]) => void;
1416
title?: string;
1517
hideSystemAlbums?: boolean;
1618
};
@@ -19,18 +21,34 @@ export const AddToAlbumDialog: React.FC<Props> = ({
1921
open,
2022
onClose,
2123
onSelect,
22-
title = 'Choose album',
24+
title = 'Choose album(s)',
2325
hideSystemAlbums = false,
2426
}) => {
2527
const { data: albums, isLoading, isError, error } = getAlbums();
2628

29+
const [selectedIds, setSelectedIds] = React.useState<string[]>([]);
30+
React.useEffect(() => {
31+
if (!open) {
32+
setSelectedIds([]);
33+
}
34+
}, [open]);
35+
36+
2737
const visibleAlbums = React.useMemo<Album[]>(() => {
2838
const list = albums ?? [];
29-
return hideSystemAlbums ? list.filter(a => !a.isSystem) : list;
39+
return hideSystemAlbums ? list.filter((a) => !a.isSystem) : list;
3040
}, [albums, hideSystemAlbums]);
3141

32-
const handlePick = (id: string) => {
33-
onSelect(id);
42+
const handleToggle = (id: string) => {
43+
setSelectedIds((prev) =>
44+
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
45+
);
46+
};
47+
48+
const handleConfirm = () => {
49+
if (selectedIds.length === 0) return;
50+
51+
onSelect(selectedIds);
3452
onClose();
3553
};
3654

@@ -59,31 +77,54 @@ export const AddToAlbumDialog: React.FC<Props> = ({
5977

6078
{!isLoading && !isError && visibleAlbums.length > 0 && (
6179
<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-
))}
80+
{visibleAlbums.map((album) => {
81+
const checked = selectedIds.includes(album.id);
82+
return (
83+
<ListItemButton
84+
key={album.id}
85+
onClick={() => handleToggle(album.id)}
86+
selected={checked}
87+
sx={{
88+
borderRadius: 1,
89+
mb: 0.5,
90+
'&:hover': { bgcolor: 'action.hover' },
91+
}}
92+
>
93+
<ListItemIcon sx={{ minWidth: 40 }}>
94+
<Checkbox
95+
edge="start"
96+
checked={checked}
97+
tabIndex={-1}
98+
disableRipple
99+
/>
100+
</ListItemIcon>
101+
102+
<ListItemIcon sx={{ minWidth: 36 }}>
103+
<FolderIcon />
104+
</ListItemIcon>
105+
106+
<ListItemText
107+
primary={album.name}
108+
secondary={new Date(album.dateCreated).toLocaleDateString()}
109+
primaryTypographyProps={{ noWrap: true, fontWeight: 600 }}
110+
secondaryTypographyProps={{ noWrap: true }}
111+
/>
112+
</ListItemButton>
113+
);
114+
})}
84115
</List>
85116
)}
86117
</DialogContent>
118+
<DialogActions>
119+
<Button onClick={onClose}>Cancel</Button>
120+
<Button
121+
onClick={handleConfirm}
122+
variant="contained"
123+
disabled={selectedIds.length === 0}
124+
>
125+
Add
126+
</Button>
127+
</DialogActions>
87128
</Dialog>
88129
);
89130
};

src/components/ImageGallery.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,14 @@ export const ImageGallery: React.FC<{ albumId?: string }> = ({ albumId }) => {
276276

277277
const [openAddToAlbumDialog, setOpenAddToAlbumDialog] = React.useState(false);
278278

279-
const handleAddToAlbum = (albumIdToAdd: string) => {
280-
if (selectedImages.length === 0) return;
281-
addToAlbumMutation.mutate({
282-
albumId: albumIdToAdd,
283-
objectIds: selectedImages,
279+
const handleAddToAlbum = (albumIdsToAdd: string[]) => {
280+
if (selectedImages.length === 0 || albumIdsToAdd.length === 0) return;
281+
282+
albumIdsToAdd.forEach((albumIdToAdd) => {
283+
addToAlbumMutation.mutate({
284+
albumId: albumIdToAdd,
285+
objectIds: selectedImages,
286+
});
284287
});
285288
};
286289

src/pages/Albums/AddAlbumPage.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,24 @@ const AddAlbumPage = () => {
2525
toast.success('Album deleted.');
2626
navigate('/albums');
2727
},
28-
onError: (err) => {
29-
toast.error(`Error deleting album: ${err?.message ?? 'Error'}`);
28+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
29+
onError: (err: any) => {
30+
const errors = err?.response?.data?.errors;
31+
32+
const albumNotEmptyMessage: string | undefined =
33+
errors?.AlbumNotEmpty?.[0];
34+
35+
const firstModelError: string | undefined = errors
36+
? Object.values(errors).flat()[0] as string
37+
: undefined;
38+
39+
const apiMessage =
40+
albumNotEmptyMessage ||
41+
firstModelError ||
42+
err?.message ||
43+
'Unexpected error occurred';
44+
45+
toast.error(`Error deleting album: ${apiMessage}`);
3046
},
3147
});
3248
};

0 commit comments

Comments
 (0)