From 10a67bd32bd5579010b9260730179c6f91c82494 Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Fri, 23 Aug 2024 18:10:11 +0100 Subject: [PATCH] Implemented album picker --- docker/api/Dockerfile | 2 +- docker/ui/Dockerfile | 2 +- .../Controllers/AlbumsController.cs | 16 +++ .../MusicCatalogue.Api.csproj | 6 +- .../Interfaces/IAlbumManager.cs | 1 + .../Database/AlbumManager.cs | 23 ++++ .../components/albums/albumPicker.js | 104 ++++++++++++++++++ .../components/albums/albumPicker.module.css | 22 ++++ .../components/albums/albumPickerAlbumRow.js | 39 +++++++ .../components/componentPicker.js | 3 + src/music-catalogue-ui/components/menuBar.js | 3 + .../components/reports/genreAlbumsReport.js | 4 +- .../components/reports/reports.module.css | 2 +- .../helpers/api/apiAlbums.js | 21 ++++ src/music-catalogue-ui/helpers/navigation.js | 1 + 15 files changed, 241 insertions(+), 8 deletions(-) create mode 100644 src/music-catalogue-ui/components/albums/albumPicker.js create mode 100644 src/music-catalogue-ui/components/albums/albumPicker.module.css create mode 100644 src/music-catalogue-ui/components/albums/albumPickerAlbumRow.js diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index 97a64da..a6df1fb 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.32.0.0 /opt/musiccatalogue.api +COPY musiccatalogue.api-1.33.0.0 /opt/musiccatalogue.api WORKDIR /opt/musiccatalogue.api/bin ENTRYPOINT [ "./MusicCatalogue.Api" ] diff --git a/docker/ui/Dockerfile b/docker/ui/Dockerfile index cc2902a..d1acd84 100644 --- a/docker/ui/Dockerfile +++ b/docker/ui/Dockerfile @@ -1,5 +1,5 @@ FROM node:20-alpine -COPY musiccatalogue.ui-1.32.0.0 /opt/musiccatalogue.ui +COPY musiccatalogue.ui-1.33.0.0 /opt/musiccatalogue.ui WORKDIR /opt/musiccatalogue.ui RUN npm install RUN npm run build diff --git a/src/MusicCatalogue.Api/Controllers/AlbumsController.cs b/src/MusicCatalogue.Api/Controllers/AlbumsController.cs index b32faac..fce62b8 100644 --- a/src/MusicCatalogue.Api/Controllers/AlbumsController.cs +++ b/src/MusicCatalogue.Api/Controllers/AlbumsController.cs @@ -40,6 +40,22 @@ public async Task> GetAlbumByIdAsync(int id) return album; } + [HttpGet] + [Route("random")] + public async Task> GetRandomAlbum() + { + var album = await _factory.Albums.GetRandomAsync(x => !(x.IsWishListItem ?? false)); + return album; + } + + [HttpGet] + [Route("random/{genreId}")] + public async Task> GetRandomAlbum(int genreId) + { + var album = await _factory.Albums.GetRandomAsync(x => !(x.IsWishListItem ?? false) && (x.GenreId == genreId)); + return album; + } + /// /// Return a list of albums for the specified artist, filtering for items that are on/not on /// the wishlist based on the arguments diff --git a/src/MusicCatalogue.Api/MusicCatalogue.Api.csproj b/src/MusicCatalogue.Api/MusicCatalogue.Api.csproj index ff2de42..d281009 100644 --- a/src/MusicCatalogue.Api/MusicCatalogue.Api.csproj +++ b/src/MusicCatalogue.Api/MusicCatalogue.Api.csproj @@ -2,9 +2,9 @@ net8.0 - 1.32.0.0 - 1.32.0.0 - 1.32.0 + 1.33.0.0 + 1.33.0.0 + 1.33.0 enable enable diff --git a/src/MusicCatalogue.Entities/Interfaces/IAlbumManager.cs b/src/MusicCatalogue.Entities/Interfaces/IAlbumManager.cs index 5244827..19d3548 100644 --- a/src/MusicCatalogue.Entities/Interfaces/IAlbumManager.cs +++ b/src/MusicCatalogue.Entities/Interfaces/IAlbumManager.cs @@ -29,6 +29,7 @@ Task AddAsync( int? retailerId); Task GetAsync(Expression> predicate); + Task GetRandomAsync(Expression> predicate); Task> ListAsync(Expression> predicate); Task DeleteAsync(int albumId); } diff --git a/src/MusicCatalogue.Logic/Database/AlbumManager.cs b/src/MusicCatalogue.Logic/Database/AlbumManager.cs index 1d19e54..5b7e9ec 100644 --- a/src/MusicCatalogue.Logic/Database/AlbumManager.cs +++ b/src/MusicCatalogue.Logic/Database/AlbumManager.cs @@ -39,6 +39,29 @@ public async Task> ListAsync(Expression> predicate .Include(x => x.Tracks) .ToListAsync(); + /// + /// Return a randomly selected album from those matching the predicate + /// + /// + /// + public async Task GetRandomAsync(Expression> predicate) + { + Album? album = null; + + // Get a list of albums matching the predicate + var albums = await ListAsync(predicate); + + // If there are any, pick one at random + var numberOfAlbums = albums.Count; + if (numberOfAlbums > 0) + { + var index = new Random().Next(0, numberOfAlbums); + album = albums[index]; + } + + return album; + } + /// /// Add an album, if it doesn't already exist /// diff --git a/src/music-catalogue-ui/components/albums/albumPicker.js b/src/music-catalogue-ui/components/albums/albumPicker.js new file mode 100644 index 0000000..d548bc8 --- /dev/null +++ b/src/music-catalogue-ui/components/albums/albumPicker.js @@ -0,0 +1,104 @@ +import React, { useCallback, useState } from "react"; +import styles from "./albumPicker.module.css"; +import { apiFetchRandomAlbum } from "@/helpers/api/apiAlbums"; +import AlbumPickerAlbumRow from "./albumPickerAlbumRow"; +import GenreSelector from "../genres/genreSelector"; +import { apiFetchArtistById } from "@/helpers/api/apiArtists"; + +/** + * Component to pick a random album, optionally for a specified genre + * @param {*} logout + * @returns + */ +const AlbumPicker = ({ logout }) => { + const [genre, setGenre] = useState(null); + const [details, setDetails] = useState({ album: null, artist: null }); + + // Callback to request a random album from the API + const pickAlbumCallback = useCallback( + async (e) => { + // Prevent the default action associated with the click event + e.preventDefault(); + + // Request a random album, optionally filtering by the selected genre, and + // retrieve the artist details + const genreId = genre != null ? genre.id : null; + const fetchedAlbum = await apiFetchRandomAlbum(genreId, logout); + if (fetchedAlbum != null) { + const fetchedArtist = await apiFetchArtistById( + fetchedAlbum.artistId, + logout + ); + setDetails({ album: fetchedAlbum, artist: fetchedArtist }); + } else { + setDetails({ album: null, artist: null }); + } + }, + [genre, logout] + ); + + return ( + <> +
+
Album Picker
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + {details.album != null && ( + + { + + } + + )} +
ArtistTitleGenreReleasedPurchasedPriceRetailer
+ + ); +}; + +export default AlbumPicker; diff --git a/src/music-catalogue-ui/components/albums/albumPicker.module.css b/src/music-catalogue-ui/components/albums/albumPicker.module.css new file mode 100644 index 0000000..78513b4 --- /dev/null +++ b/src/music-catalogue-ui/components/albums/albumPicker.module.css @@ -0,0 +1,22 @@ +.albumPickerFormContainer { + display: flex; + justify-content: center; + align-items: center; +} + +.albumPickerForm { + width: 100vw; + padding-top: 20px; + padding-bottom: 20px; +} + +.albumPickerLabel { + margin-right: 20px; + font-size: 14px; + font-weight: 600; + color: rgb(34, 34, 34); +} + +.alunmPickerGenreSelector { + width: 200px; +} diff --git a/src/music-catalogue-ui/components/albums/albumPickerAlbumRow.js b/src/music-catalogue-ui/components/albums/albumPickerAlbumRow.js new file mode 100644 index 0000000..abe96e4 --- /dev/null +++ b/src/music-catalogue-ui/components/albums/albumPickerAlbumRow.js @@ -0,0 +1,39 @@ +import CurrencyFormatter from "../common/currencyFormatter"; +import DateFormatter from "../common/dateFormatter"; + +/** + * Component to render a row containing the details of a single album in a + * genre + * @param {*} album + * @param {*} artist + * @returns + */ +const AlbumPickerAlbumRow = ({ album, artist }) => { + const purchaseDate = new Date(album.purchased); + + return ( + + {artist.name} + {album.title} + {album.genre.name} + {album.released > 0 ? {album.released} : } + {purchaseDate > 1900 ? ( + + + + ) : ( + + )} + {album.price > 0 ? ( + + + + ) : ( + + )} + {album.retailer != null ? {album.retailer.name} : } + + ); +}; + +export default AlbumPickerAlbumRow; diff --git a/src/music-catalogue-ui/components/componentPicker.js b/src/music-catalogue-ui/components/componentPicker.js index 6bc3aa1..4524bac 100644 --- a/src/music-catalogue-ui/components/componentPicker.js +++ b/src/music-catalogue-ui/components/componentPicker.js @@ -26,6 +26,7 @@ import ManufacturerEditor from "./manufacturers/manufacturerEditor"; import EquipmentList from "./equipment/equipmentList"; import EquipmentPurchaseDetails from "./equipment/equpimentPurchaseDetails"; import EquipmentEditor from "./equipment/equipmentEditor"; +import AlbumPicker from "./albums/albumPicker"; /** * Component using the current context to select and render the current page @@ -84,6 +85,8 @@ const ComponentPicker = ({ context, navigate, logout }) => { logout={logout} /> ); + case pages.albumPicker: + return ; case pages.tracks: return ( {
+ navigate({ page: pages.albumPicker })}> + Album Picker + navigate({ page: pages.artists, filter: "A" })}> Artists diff --git a/src/music-catalogue-ui/components/reports/genreAlbumsReport.js b/src/music-catalogue-ui/components/reports/genreAlbumsReport.js index 3f75a1e..14d1757 100644 --- a/src/music-catalogue-ui/components/reports/genreAlbumsReport.js +++ b/src/music-catalogue-ui/components/reports/genreAlbumsReport.js @@ -1,6 +1,6 @@ import React, { useCallback, useState } from "react"; import styles from "./reports.module.css"; -import "react-datepicker/dist/react-datepicker.css"; +// import "react-datepicker/dist/react-datepicker.css"; import { apiGenreAlbumsReport } from "@/helpers/api/apiReports"; import GenreAlbumRow from "./genreAlbumRow"; import ReportExportControls from "./reportExportControls"; @@ -91,7 +91,7 @@ const GenreAlbumsReport = ({ logout }) => {
-
+
{ + // Call the API to get the details for a randomly selected album + const baseUrl = `${config.api.baseUrl}/albums/random`; + const url = genreId != null ? `${baseUrl}/${genreId}` : baseUrl; + const response = await fetch(url, { + method: "GET", + headers: apiGetHeaders(), + }); + + const album = await apiReadResponseData(response, logout); + return album; +}; + export { apiCreateAlbum, apiUpdateAlbum, @@ -274,4 +294,5 @@ export { apiLookupAlbum, apiSetAlbumWishListFlag, apiSetAlbumPurchaseDetails, + apiFetchRandomAlbum, }; diff --git a/src/music-catalogue-ui/helpers/navigation.js b/src/music-catalogue-ui/helpers/navigation.js index c117367..a6bd47a 100644 --- a/src/music-catalogue-ui/helpers/navigation.js +++ b/src/music-catalogue-ui/helpers/navigation.js @@ -7,6 +7,7 @@ const pages = { albums: "Albums", albumEditor: "AlbumEditor", albumPurchaseDetails: "AlbumPurchaseDetails", + albumPicker: "AlbumPicker", wishlistAlbums: "WishlistAlbums", tracks: "Tracks", trackEditor: "TrackEditor",