Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 70 additions & 29 deletions src/components/Albums/AddToAlbumDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import FolderIcon from '@mui/icons-material/Folder';
import {
CircularProgress, Dialog, DialogContent, DialogTitle, List, ListItemButton,
ListItemIcon, ListItemText, Typography
Button,
Checkbox,
CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, List, ListItemButton,
ListItemIcon, ListItemText, Typography
} from '@mui/material';
import { getAlbums } from 'api/albumApi';
import { Album } from 'models/Album';
Expand All @@ -10,7 +12,7 @@ import * as React from 'react';
type Props = {
open: boolean;
onClose: () => void;
onSelect: (albumId: string) => void;
onSelect: (albumId: string[]) => void;
title?: string;
hideSystemAlbums?: boolean;
};
Expand All @@ -19,18 +21,34 @@ export const AddToAlbumDialog: React.FC<Props> = ({
open,
onClose,
onSelect,
title = 'Choose album',
title = 'Choose album(s)',
hideSystemAlbums = false,
}) => {
const { data: albums, isLoading, isError, error } = getAlbums();

const [selectedIds, setSelectedIds] = React.useState<string[]>([]);
React.useEffect(() => {
if (!open) {
setSelectedIds([]);
}
}, [open]);


const visibleAlbums = React.useMemo<Album[]>(() => {
const list = albums ?? [];
return hideSystemAlbums ? list.filter(a => !a.isSystem) : list;
return hideSystemAlbums ? list.filter((a) => !a.isSystem) : list;
}, [albums, hideSystemAlbums]);

const handlePick = (id: string) => {
onSelect(id);
const handleToggle = (id: string) => {
setSelectedIds((prev) =>
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
);
};

const handleConfirm = () => {
if (selectedIds.length === 0) return;

onSelect(selectedIds);
onClose();
};

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

{!isLoading && !isError && visibleAlbums.length > 0 && (
<List dense disablePadding>
{visibleAlbums.map((album) => (
<ListItemButton
key={album.id}
onClick={() => handlePick(album.id)}
sx={{
borderRadius: 1,
mb: 0.5,
'&:hover': { bgcolor: 'action.hover' },
}}
>
<ListItemIcon>
<FolderIcon />
</ListItemIcon>

<ListItemText
primary={album.name}
secondary={new Date(album.dateCreated).toLocaleDateString()}
primaryTypographyProps={{ noWrap: true, fontWeight: 600 }}
secondaryTypographyProps={{ noWrap: true }}
/>
</ListItemButton>
))}
{visibleAlbums.map((album) => {
const checked = selectedIds.includes(album.id);
return (
<ListItemButton
key={album.id}
onClick={() => handleToggle(album.id)}
selected={checked}
sx={{
borderRadius: 1,
mb: 0.5,
'&:hover': { bgcolor: 'action.hover' },
}}
>
<ListItemIcon sx={{ minWidth: 40 }}>
<Checkbox
edge="start"
checked={checked}
tabIndex={-1}
disableRipple
/>
</ListItemIcon>

<ListItemIcon sx={{ minWidth: 36 }}>
<FolderIcon />
</ListItemIcon>

<ListItemText
primary={album.name}
secondary={new Date(album.dateCreated).toLocaleDateString()}
primaryTypographyProps={{ noWrap: true, fontWeight: 600 }}
secondaryTypographyProps={{ noWrap: true }}
/>
</ListItemButton>
);
})}
</List>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose}>Cancel</Button>
<Button
onClick={handleConfirm}
variant="contained"
disabled={selectedIds.length === 0}
>
Add
</Button>
</DialogActions>
</Dialog>
);
};
Expand Down
13 changes: 8 additions & 5 deletions src/components/ImageGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,14 @@ export const ImageGallery: React.FC<{ albumId?: string }> = ({ albumId }) => {

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

const handleAddToAlbum = (albumIdToAdd: string) => {
if (selectedImages.length === 0) return;
addToAlbumMutation.mutate({
albumId: albumIdToAdd,
objectIds: selectedImages,
const handleAddToAlbum = (albumIdsToAdd: string[]) => {
if (selectedImages.length === 0 || albumIdsToAdd.length === 0) return;

albumIdsToAdd.forEach((albumIdToAdd) => {
addToAlbumMutation.mutate({
albumId: albumIdToAdd,
objectIds: selectedImages,
});
});
};

Expand Down
20 changes: 18 additions & 2 deletions src/pages/Albums/AddAlbumPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,24 @@ const AddAlbumPage = () => {
toast.success('Album deleted.');
navigate('/albums');
},
onError: (err) => {
toast.error(`Error deleting album: ${err?.message ?? 'Error'}`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onError: (err: any) => {
const errors = err?.response?.data?.errors;

const albumNotEmptyMessage: string | undefined =
errors?.AlbumNotEmpty?.[0];

const firstModelError: string | undefined = errors
? Object.values(errors).flat()[0] as string
: undefined;

const apiMessage =
albumNotEmptyMessage ||
firstModelError ||
err?.message ||
'Unexpected error occurred';

toast.error(`Error deleting album: ${apiMessage}`);
},
});
};
Expand Down
Loading