From 091390e025cbd78728b6828d1537454a3fb86fde Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Wed, 4 Sep 2024 00:58:05 +0200 Subject: [PATCH] [FEAT] add edit of album and artist Missing cover that might be studied --- .../src/components/popup/AlbumEditPopUp.tsx | 184 +++++++++++++++++ .../src/components/popup/ArtistEditPopUp.tsx | 187 ++++++++++++++++++ .../src/components/popup/TrackEditPopUp.tsx | 19 +- front2/src/components/track/DisplayTrack.tsx | 4 - front2/src/scene/album/AlbumDetailPage.tsx | 22 ++- .../scene/artist/ArtistAlbumDetailPage.tsx | 48 +++-- front2/src/scene/artist/ArtistDetailPage.tsx | 39 ++-- front2/src/scene/artist/ArtistRoutes.tsx | 2 +- front2/src/service/Track.ts | 2 +- 9 files changed, 449 insertions(+), 58 deletions(-) create mode 100644 front2/src/components/popup/AlbumEditPopUp.tsx create mode 100644 front2/src/components/popup/ArtistEditPopUp.tsx diff --git a/front2/src/components/popup/AlbumEditPopUp.tsx b/front2/src/components/popup/AlbumEditPopUp.tsx new file mode 100644 index 0000000..2fea367 --- /dev/null +++ b/front2/src/components/popup/AlbumEditPopUp.tsx @@ -0,0 +1,184 @@ +import { useRef, useState } from 'react'; + +import { + Button, + Flex, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + Text, + useDisclosure, +} from '@chakra-ui/react'; +import { + MdAdminPanelSettings, + MdDeleteForever, + MdEdit, + MdWarning, +} from 'react-icons/md'; +import { useNavigate, useParams } from 'react-router-dom'; + +import { Album, AlbumResource } from '@/back-api'; +import { FormGroup } from '@/components/form/FormGroup'; +import { FormInput } from '@/components/form/FormInput'; +import { FormTextarea } from '@/components/form/FormTextarea'; +import { useFormidable } from '@/components/form/Formidable'; +import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp'; +import { useAlbumService, useSpecificAlbum } from '@/service/Album'; +import { useServiceContext } from '@/service/ServiceContext'; +import { useCountTracksWithAlbumId } from '@/service/Track'; +import { isNullOrUndefined } from '@/utils/validator'; + +export type AlbumEditPopUpProps = {}; + +export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => { + const { albumId } = useParams(); + const albumIdInt = isNullOrUndefined(albumId) + ? undefined + : parseInt(albumId, 10); + const { session } = useServiceContext(); + const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(albumIdInt); + const { store } = useAlbumService(); + const { dataAlbum } = useSpecificAlbum(albumIdInt); + const [admin, setAdmin] = useState(false); + const navigate = useNavigate(); + const disclosure = useDisclosure(); + const onClose = () => { + navigate('../../', { relative: 'path' }); + }; + const onRemove = () => { + if (isNullOrUndefined(albumIdInt)) { + return; + } + store.remove( + albumIdInt, + AlbumResource.remove({ + restConfig: session.getRestConfig(), + params: { + id: albumIdInt, + }, + }) + ); + onClose(); + }; + const initialRef = useRef(null); + const finalRef = useRef(null); + const form = useFormidable({ + initialValues: dataAlbum, + }); + const onSave = async () => { + if (isNullOrUndefined(albumIdInt)) { + return; + } + const dataThatNeedToBeUpdated = form.getDeltaData({ omit: ['covers'] }); + console.log(`onSave = ${JSON.stringify(dataThatNeedToBeUpdated, null, 2)}`); + store.update( + AlbumResource.patch({ + restConfig: session.getRestConfig(), + data: dataThatNeedToBeUpdated, + params: { + id: albumIdInt, + }, + }) + ); + }; + return ( + + + + Edit Album + + + + {admin && ( + <> + + {dataAlbum?.id} + + {countTracksOfAnAlbum !== 0 && ( + + + + Can not remove album {countTracksOfAnAlbum} track(s) depend + on it. + + + )} + + + + + + )} + {!admin && ( + <> + + + + + )} + + + + {!admin && form.isFormModified && ( + + )} + + + + + ); +}; diff --git a/front2/src/components/popup/ArtistEditPopUp.tsx b/front2/src/components/popup/ArtistEditPopUp.tsx new file mode 100644 index 0000000..858bc1c --- /dev/null +++ b/front2/src/components/popup/ArtistEditPopUp.tsx @@ -0,0 +1,187 @@ +import { useRef, useState } from 'react'; + +import { + Button, + Flex, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + Text, + useDisclosure, +} from '@chakra-ui/react'; +import { + MdAdminPanelSettings, + MdDeleteForever, + MdEdit, + MdWarning, +} from 'react-icons/md'; +import { useNavigate, useParams } from 'react-router-dom'; + +import { Artist, ArtistResource } from '@/back-api'; +import { FormGroup } from '@/components/form/FormGroup'; +import { FormInput } from '@/components/form/FormInput'; +import { FormTextarea } from '@/components/form/FormTextarea'; +import { useFormidable } from '@/components/form/Formidable'; +import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp'; +import { useArtistService, useSpecificArtist } from '@/service/Artist'; +import { useServiceContext } from '@/service/ServiceContext'; +import { useCountTracksOfAnArtist } from '@/service/Track'; +import { isNullOrUndefined } from '@/utils/validator'; + +export type ArtistEditPopUpProps = {}; + +export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => { + const { artistId } = useParams(); + const artistIdInt = isNullOrUndefined(artistId) + ? undefined + : parseInt(artistId, 10); + const { session } = useServiceContext(); + const { countTracksOnAnArtist } = useCountTracksOfAnArtist(artistIdInt); + const { store } = useArtistService(); + const { dataArtist } = useSpecificArtist(artistIdInt); + const [admin, setAdmin] = useState(false); + const navigate = useNavigate(); + const disclosure = useDisclosure(); + const onClose = () => { + navigate('../../', { relative: 'path' }); + }; + const onRemove = () => { + if (isNullOrUndefined(artistIdInt)) { + return; + } + store.remove( + artistIdInt, + ArtistResource.remove({ + restConfig: session.getRestConfig(), + params: { + id: artistIdInt, + }, + }) + ); + onClose(); + }; + const initialRef = useRef(null); + const finalRef = useRef(null); + const form = useFormidable({ + initialValues: dataArtist, + }); + const onSave = async () => { + if (isNullOrUndefined(artistIdInt)) { + return; + } + const dataThatNeedToBeUpdated = form.getDeltaData({ omit: ['covers'] }); + console.log(`onSave = ${JSON.stringify(dataThatNeedToBeUpdated, null, 2)}`); + store.update( + ArtistResource.patch({ + restConfig: session.getRestConfig(), + data: dataThatNeedToBeUpdated, + params: { + id: artistIdInt, + }, + }) + ); + }; + return ( + + + + Edit Artist + + + + {admin && ( + <> + + {dataArtist?.id} + + {countTracksOnAnArtist !== 0 && ( + + + + Can not remove artist {countTracksOnAnArtist} track(s) + depend on it. + + + )} + + + + + + )} + {!admin && ( + <> + + + + + + + + )} + + + + {!admin && form.isFormModified && ( + + )} + + + + + ); +}; diff --git a/front2/src/components/popup/TrackEditPopUp.tsx b/front2/src/components/popup/TrackEditPopUp.tsx index 5719671..fc2fe3e 100644 --- a/front2/src/components/popup/TrackEditPopUp.tsx +++ b/front2/src/components/popup/TrackEditPopUp.tsx @@ -1,9 +1,7 @@ -import { useEffect, useRef, useState } from 'react'; +import { useRef, useState } from 'react'; import { Button, - IconButton, - Input, Modal, ModalBody, ModalCloseButton, @@ -11,21 +9,10 @@ import { ModalFooter, ModalHeader, ModalOverlay, - NumberDecrementStepper, - NumberIncrementStepper, - NumberInput, - NumberInputField, - NumberInputStepper, Text, - Textarea, useDisclosure, } from '@chakra-ui/react'; -import { - MdAdminPanelSettings, - MdDeleteForever, - MdEdit, - MdRemove, -} from 'react-icons/md'; +import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md'; import { useNavigate, useParams } from 'react-router-dom'; import { Track, TrackResource } from '@/back-api'; @@ -37,8 +24,6 @@ import { FormSelectMultiple } from '@/components/form/FormSelectMultiple'; import { FormTextarea } from '@/components/form/FormTextarea'; import { useFormidable } from '@/components/form/Formidable'; import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp'; -import { SelectMultiple } from '@/components/select/SelectMultiple'; -import { SelectSingle } from '@/components/select/SelectSingle'; import { useOrderedAlbums } from '@/service/Album'; import { useOrderedArtists } from '@/service/Artist'; import { useOrderedGenders } from '@/service/Gender'; diff --git a/front2/src/components/track/DisplayTrack.tsx b/front2/src/components/track/DisplayTrack.tsx index 0f30229..c837674 100644 --- a/front2/src/components/track/DisplayTrack.tsx +++ b/front2/src/components/track/DisplayTrack.tsx @@ -1,13 +1,9 @@ -import { Suspense } from 'react'; - import { Flex, Text } from '@chakra-ui/react'; import { LuMusic2, LuPlay } from 'react-icons/lu'; -import { useNavigate } from 'react-router-dom'; import { Track } from '@/back-api'; import { Covers } from '@/components/Cover'; import { ContextMenu, MenuElement } from '@/components/contextMenu/ContextMenu'; -import { DisplayTrackSkeleton } from '@/components/track/DisplayTrackSkeleton'; import { useActivePlaylistService } from '@/service/ActivePlaylist'; export type DisplayTrackProps = { diff --git a/front2/src/scene/album/AlbumDetailPage.tsx b/front2/src/scene/album/AlbumDetailPage.tsx index 542d718..5ad8f71 100644 --- a/front2/src/scene/album/AlbumDetailPage.tsx +++ b/front2/src/scene/album/AlbumDetailPage.tsx @@ -1,12 +1,14 @@ -import { Box, Flex, Text } from '@chakra-ui/react'; +import { Box, Button, Flex, Text } from '@chakra-ui/react'; import { LuDisc3 } from 'react-icons/lu'; +import { MdEdit } from 'react-icons/md'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Covers } from '@/components/Cover'; import { EmptyEnd } from '@/components/EmptyEnd'; import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; -import { TopBar } from '@/components/TopBar/TopBar'; +import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar'; +import { AlbumEditPopUp } from '@/components/popup/AlbumEditPopUp'; import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp'; import { DisplayTrack } from '@/components/track/DisplayTrack'; import { DisplayTrackFull } from '@/components/track/DisplayTrackFull'; @@ -53,7 +55,16 @@ export const AlbumDetailPage = () => { } return ( <> - + + + { { name: 'Edit', onClick: () => { - navigate(`/album/${albumId}/edit/${data.id}`); + navigate(`/album/${albumId}/edit-track/${data.id}`); }, }, { name: 'Add Playlist', onClick: () => {} }, @@ -119,7 +130,8 @@ export const AlbumDetailPage = () => { - } /> + } /> + } /> diff --git a/front2/src/scene/artist/ArtistAlbumDetailPage.tsx b/front2/src/scene/artist/ArtistAlbumDetailPage.tsx index 882119a..c52f66a 100644 --- a/front2/src/scene/artist/ArtistAlbumDetailPage.tsx +++ b/front2/src/scene/artist/ArtistAlbumDetailPage.tsx @@ -1,6 +1,6 @@ import { Box, Button, Flex, Text } from '@chakra-ui/react'; import { LuDisc3, LuUser } from 'react-icons/lu'; -import { MdPerson } from 'react-icons/md'; +import { MdEdit, MdPerson } from 'react-icons/md'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Covers } from '@/components/Cover'; @@ -8,6 +8,7 @@ import { EmptyEnd } from '@/components/EmptyEnd'; import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar'; +import { AlbumEditPopUp } from '@/components/popup/AlbumEditPopUp'; import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp'; import { DisplayTrack } from '@/components/track/DisplayTrack'; import { useActivePlaylistService } from '@/service/ActivePlaylist'; @@ -57,21 +58,31 @@ export const ArtistAlbumDetailPage = () => { <> {dataArtist && ( - + <> + + + )} @@ -129,7 +140,7 @@ export const ArtistAlbumDetailPage = () => { name: 'Edit', onClick: () => { navigate( - `/artist/${artistIdInt}/album/${albumId}/edit/${data.id}` + `/artist/${artistIdInt}/album/${albumId}/edit-track/${data.id}` ); }, }, @@ -141,7 +152,8 @@ export const ArtistAlbumDetailPage = () => { - } /> + } /> + } /> diff --git a/front2/src/scene/artist/ArtistDetailPage.tsx b/front2/src/scene/artist/ArtistDetailPage.tsx index 121b753..24c9886 100644 --- a/front2/src/scene/artist/ArtistDetailPage.tsx +++ b/front2/src/scene/artist/ArtistDetailPage.tsx @@ -1,7 +1,7 @@ import { Button, Flex, Text, Wrap, WrapItem } from '@chakra-ui/react'; import { LuUser } from 'react-icons/lu'; -import { MdGroup } from 'react-icons/md'; -import { useNavigate, useParams } from 'react-router-dom'; +import { MdEdit, MdGroup } from 'react-icons/md'; +import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Covers } from '@/components/Cover'; import { EmptyEnd } from '@/components/EmptyEnd'; @@ -9,6 +9,7 @@ import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar'; import { DisplayAlbumId } from '@/components/album/DisplayAlbumId'; +import { ArtistEditPopUp } from '@/components/popup/ArtistEditPopUp'; import { useSpecificArtist } from '@/service/Artist'; import { useAlbumIdsOfAnArtist } from '@/service/Track'; import { useThemeMode } from '@/utils/theme-tools'; @@ -37,16 +38,27 @@ export const ArtistDetailPage = () => { return ( <> - + <> + + + + { ))} + + } /> + ); diff --git a/front2/src/scene/artist/ArtistRoutes.tsx b/front2/src/scene/artist/ArtistRoutes.tsx index 08a9585..547c3eb 100644 --- a/front2/src/scene/artist/ArtistRoutes.tsx +++ b/front2/src/scene/artist/ArtistRoutes.tsx @@ -10,7 +10,7 @@ export const ArtistRoutes = () => { } /> } /> - } /> + } /> } diff --git a/front2/src/service/Track.ts b/front2/src/service/Track.ts index cb6594d..ad99a14 100644 --- a/front2/src/service/Track.ts +++ b/front2/src/service/Track.ts @@ -73,7 +73,7 @@ export const useTracksOfAnArtist = (idArtist?: number) => { * @param id - Id of the artist. * @returns The number of track present in this artist */ -export const useCountTracksOfAnArtist = (idArtist: number) => { +export const useCountTracksOfAnArtist = (idArtist?: number) => { const { isLoading, tracksOnAnAlbum } = useTracksOfAnAlbum(idArtist); const countTracksOnAnArtist = useMemo( () => tracksOnAnAlbum?.length ?? 0,