From bccb9658090f4abcd9004b1ef0ac61ea9ab4caeb Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Thu, 23 Nov 2023 08:42:12 +0000 Subject: [PATCH] Added the ability to delete tracks from the UI --- docker/api/Dockerfile | 4 +- .../components/deleteTrackActionIcon.js | 45 +++++++++ .../components/trackList.js | 3 + src/music-catalogue-ui/components/trackRow.js | 18 +++- src/music-catalogue-ui/helpers/apiTracks.js | 91 +++++++++++++++++++ 5 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 src/music-catalogue-ui/components/deleteTrackActionIcon.js create mode 100644 src/music-catalogue-ui/helpers/apiTracks.js diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index b43423c..459abe2 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -1,4 +1,4 @@ FROM mcr.microsoft.com/dotnet/core/aspnet:latest -COPY musiccatalogue.api-1.21.0.0 /opt/musiccatalogue.api-1.21.0.0 -WORKDIR /opt/musiccatalogue.api-1.21.0.0/bin +COPY musiccatalogue.api-1.22.0.0 /opt/musiccatalogue.api-1.22.0.0 +WORKDIR /opt/musiccatalogue.api-1.22.0.0/bin ENTRYPOINT [ "./MusicCatalogue.Api" ] diff --git a/src/music-catalogue-ui/components/deleteTrackActionIcon.js b/src/music-catalogue-ui/components/deleteTrackActionIcon.js new file mode 100644 index 0000000..72b09e2 --- /dev/null +++ b/src/music-catalogue-ui/components/deleteTrackActionIcon.js @@ -0,0 +1,45 @@ +import { apiDeleteTrack } from "@/helpers/apiTracks"; +import { apiFetchAlbumById } from "@/helpers/apiAlbums"; +import { useCallback } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faTrashAlt } from "@fortawesome/free-solid-svg-icons"; + +/** + * Icon and associated action to delete a track + * @param {*} track + * @param {*} logout + * @param {*} setTracks + * @returns + */ +const DeleteTrackActionIcon = ({ track, logout, setTracks }) => { + /* Callback to prompt for confirmation and delete an album */ + const confirmDeleteTrack = useCallback(async (e, track) => { + // Prevent the default action associated with the click event + e.preventDefault(); + + // Show a confirmation message and get the user response + const message = `This will delete the track "${track.title}" - click OK to confirm`; + const result = confirm(message); + + // If they've confirmed the deletion ... + if (result) { + // ... cdelete the track and confirm the API call was successful + const result = await apiDeleteTrack(track.id, logout); + if (result) { + // Successful, so get the album from the service and set the tracks to + // the appropriate member of the returned object + var fetchedAlbum = await apiFetchAlbumById(track.albumId, logout); + setTracks(fetchedAlbum.tracks); + } + } + }, []); + + return ( + confirmDeleteTrack(e, track)} + /> + ); +}; + +export default DeleteTrackActionIcon; diff --git a/src/music-catalogue-ui/components/trackList.js b/src/music-catalogue-ui/components/trackList.js index b2f5c0e..9f9147f 100644 --- a/src/music-catalogue-ui/components/trackList.js +++ b/src/music-catalogue-ui/components/trackList.js @@ -43,6 +43,7 @@ const TrackList = ({ artist, album, isWishList, navigate, logout }) => { No. Track Duration + @@ -54,6 +55,8 @@ const TrackList = ({ artist, album, isWishList, navigate, logout }) => { track={t} isWishList={isWishList} navigate={navigate} + logout={logout} + setTracks={setTracks} /> ))} diff --git a/src/music-catalogue-ui/components/trackRow.js b/src/music-catalogue-ui/components/trackRow.js index e4d0e96..6cd1dd1 100644 --- a/src/music-catalogue-ui/components/trackRow.js +++ b/src/music-catalogue-ui/components/trackRow.js @@ -1,3 +1,4 @@ +import DeleteTrackActionIcon from "./deleteTrackActionIcon"; import styles from "./trackRow.module.css"; import pages from "@/helpers/navigation"; @@ -6,7 +7,15 @@ import pages from "@/helpers/navigation"; * @param {*} param0 * @returns */ -const TrackRow = ({ artist, album, track, isWishList, navigate }) => { +const TrackRow = ({ + artist, + album, + track, + isWishList, + navigate, + logout, + setTracks, +}) => { return ( {album.title} @@ -25,6 +34,13 @@ const TrackRow = ({ artist, album, track, isWishList, navigate }) => { {track.number} {track.title} {track.formattedDuration} + + + ); }; diff --git a/src/music-catalogue-ui/helpers/apiTracks.js b/src/music-catalogue-ui/helpers/apiTracks.js new file mode 100644 index 0000000..aedd1d2 --- /dev/null +++ b/src/music-catalogue-ui/helpers/apiTracks.js @@ -0,0 +1,91 @@ +import config from "../config.json"; +import { apiReadResponseData } from "./apiUtils"; +import { apiGetPostHeaders, apiGetHeaders } from "./apiHeaders"; + +/** + * Create a track + * @param {*} title + * @param {*} number + * @param {*} duration + * @param {*} albumId + * @param {*} logout + * @returns + */ +const apiCreateTrack = async (title, number, duration, albumId, logout) => { + // Create the request body + const body = JSON.stringify({ + title: title, + number: number, + duration: duration, + albumId: albumId, + }); + + // Call the API to create the retailer. This will just return the current + // record if it already exists + const url = `${config.api.baseUrl}/tracks`; + const response = await fetch(url, { + method: "POST", + headers: apiGetPostHeaders(), + body: body, + }); + + const track = await apiReadResponseData(response, logout); + return track; +}; + +/** + * Update track details + * @param {*} id + * @param {*} title + * @param {*} number + * @param {*} duration + * @param {*} albumId + * @param {*} logout + * @returns + */ +const apiUpdateTrack = async (id, title, number, duration, albumId, logout) => { + // Construct the body + const body = JSON.stringify({ + id: id, + title: title, + number: number, + duration: duration, + albumId: albumId, + }); + + // Call the API to set the wish list flag for a given album + const url = `${config.api.baseUrl}/tracks`; + const response = await fetch(url, { + method: "PUT", + headers: apiGetPostHeaders(), + body: body, + }); + + const updatedTrack = await apiReadResponseData(response, logout); + return updatedTrack; +}; + +/** + * Delete the track with the specified ID + * @param {*} trackId + * @param {*} logout + * @returns + */ +const apiDeleteTrack = async (trackId, logout) => { + // Call the API to delete the specified album + const url = `${config.api.baseUrl}/tracks/${trackId}`; + const response = await fetch(url, { + method: "DELETE", + headers: apiGetHeaders(), + }); + + if (response.status == 401) { + // Unauthorized so the token's likely expired - force a login + logout(); + } else { + // Return the response status code + return response.ok; + } +}; + +export { apiCreateTrack, apiUpdateTrack, apiDeleteTrack };