diff --git a/src/music-catalogue-ui/components/albumList.js b/src/music-catalogue-ui/components/albumList.js
new file mode 100644
index 0000000..f82f107
--- /dev/null
+++ b/src/music-catalogue-ui/components/albumList.js
@@ -0,0 +1,36 @@
+import useAlbums from "@/hooks/useAlbums";
+import statuses from "@/helpers/status";
+import AlbumRow from "./albumRow";
+import StatusIndicator from "./statusIndicator";
+
+const AlbumList = ({ artist, navigate }) => {
+ const { albums, setAlbums, currentStatus } = useAlbums(artist.id);
+
+ if (currentStatus !== statuses.loaded)
+ return ;
+
+ return (
+ <>
+
+
Albums
+
+
+
+
+ Album Title |
+ Artist |
+ Genre |
+ Released |
+
+
+
+ {albums.map((a) => (
+
+ ))}
+
+
+ >
+ );
+};
+
+export default AlbumList;
diff --git a/src/music-catalogue-ui/components/albumRow.js b/src/music-catalogue-ui/components/albumRow.js
new file mode 100644
index 0000000..3427205
--- /dev/null
+++ b/src/music-catalogue-ui/components/albumRow.js
@@ -0,0 +1,14 @@
+import pages from "@/helpers/navigation";
+
+const AlbumRow = ({ artist, album, navigate }) => {
+ return (
+ navigate(pages.tracks, album)}>
+ {artist.name} |
+ {album.title} |
+ {album.genre} |
+ {album.released} |
+
+ );
+};
+
+export default AlbumRow;
diff --git a/src/music-catalogue-ui/components/app.js b/src/music-catalogue-ui/components/app.js
index 79e0286..f9153f4 100644
--- a/src/music-catalogue-ui/components/app.js
+++ b/src/music-catalogue-ui/components/app.js
@@ -3,35 +3,30 @@ import Banner from "./banner";
import pages from "@/helpers/navigation";
import ComponentPicker from "./componentPicker";
-// Create a navigation context for the current page to display
-const navigationContext = React.createContext(pages.artists);
-
const App = () => {
- // Function used to change the current page. navTo is the page to navigate
- // to, a member of the pages object. param is a parameter passed to the
- // navigation function e.g. an artist id or an album id
- const navigate = useCallback(
- (navTo, param) => setCurrentPage({ current: navTo, param, navigate }),
- []
- );
-
- // Store the current page and the navigation function in state
- const [page, setCurrentPage] = useState({
- current: pages.artists,
- navigate,
+ const [context, setContext] = useState({
+ page: pages.artists,
+ artist: null,
+ album: null,
});
- // Note that the application provides a navigation context to all children
- // below it in the hierarchy
+ const navigate = useCallback((page, artist, album) => {
+ console.log(page);
+ console.log(artist);
+ console.log(album);
+ setContext({
+ page: page,
+ artist: artist,
+ album: album,
+ });
+ }, []);
+
return (
-
-
- Personal Music Catalogue
-
-
-
+ <>
+
+
+ >
);
};
-export { navigationContext };
export default App;
diff --git a/src/music-catalogue-ui/components/artistList.js b/src/music-catalogue-ui/components/artistList.js
index 9186959..114ca2f 100644
--- a/src/music-catalogue-ui/components/artistList.js
+++ b/src/music-catalogue-ui/components/artistList.js
@@ -3,10 +3,9 @@ import statuses from "@/helpers/status";
import ArtistRow from "./artistRow";
import StatusIndicator from "./statusIndicator";
-const ArtistList = ({ onSelected }) => {
+const ArtistList = ({ navigate }) => {
const { artists, setArtists, currentStatus } = useArtists();
- // Early return = conditional rendering
if (currentStatus !== statuses.loaded)
return ;
@@ -23,7 +22,7 @@ const ArtistList = ({ onSelected }) => {
{artists.map((a) => (
-
+
))}
diff --git a/src/music-catalogue-ui/components/artistRow.js b/src/music-catalogue-ui/components/artistRow.js
index 2547718..a884c5c 100644
--- a/src/music-catalogue-ui/components/artistRow.js
+++ b/src/music-catalogue-ui/components/artistRow.js
@@ -1,12 +1,8 @@
-import { useContext } from "react";
-import { navigationContext } from "./app";
import pages from "@/helpers/navigation";
-const ArtistRow = ({ artist }) => {
- const { navigate } = useContext(navigationContext);
-
+const ArtistRow = ({ artist, navigate }) => {
return (
- navigate(pages.albums, artist)}>
+
navigate(pages.albums, artist, null)}>
{artist.name} |
);
diff --git a/src/music-catalogue-ui/components/banner.js b/src/music-catalogue-ui/components/banner.js
index 238e240..041ab79 100644
--- a/src/music-catalogue-ui/components/banner.js
+++ b/src/music-catalogue-ui/components/banner.js
@@ -1,14 +1,7 @@
-import { useContext } from "react";
import styles from "./banner.module.css";
-import { navigationContext } from "./app";
import pages from "@/helpers/navigation";
-const Banner = ({ children }) => {
- // The navigation context supplies a function that can be used to navigate
- // between pages. For the banner, clicking on the logo always navigates
- // back to the artists page
- const { navigate } = useContext(navigationContext);
-
+const Banner = ({ navigate }) => {
return (
@@ -16,11 +9,13 @@ const Banner = ({ children }) => {
src="./logo.png"
alt="Music Catalogue"
className={styles.logo}
- onClick={() => navigate(pages.artists)}
+ onClick={() => navigate(pages.artists, null, null)}
/>
-
{children}
+
+
Personal Music Catalogue
+
);
diff --git a/src/music-catalogue-ui/components/componentPicker.js b/src/music-catalogue-ui/components/componentPicker.js
index b1f2f9d..2624d04 100644
--- a/src/music-catalogue-ui/components/componentPicker.js
+++ b/src/music-catalogue-ui/components/componentPicker.js
@@ -1,12 +1,13 @@
import pages from "../helpers/navigation";
import ArtistList from "./artistList";
+import AlbumList from "./albumList";
-const ComponentPicker = ({ currentPage }) => {
- switch (currentPage) {
+const ComponentPicker = ({ context, navigate }) => {
+ switch (context.page) {
case pages.artists:
- return ;
+ return ;
case pages.albums:
- return ;
+ return ;
case pages.tracks:
return ;
default:
diff --git a/src/music-catalogue-ui/helpers/api.js b/src/music-catalogue-ui/helpers/api.js
index 84064fd..534392c 100644
--- a/src/music-catalogue-ui/helpers/api.js
+++ b/src/music-catalogue-ui/helpers/api.js
@@ -23,7 +23,7 @@ const apiAuthenticate = async (username, password) => {
return token.replace(/"/g, "");
};
-const apiFetchAllArtists = async (token) => {
+const apiFetchAllArtists = async () => {
// TODO: This call can be removed once user login has been implemented
var token = await apiAuthenticate(username, password);
@@ -44,4 +44,25 @@ const apiFetchAllArtists = async (token) => {
return artists;
};
-export { apiAuthenticate, apiFetchAllArtists };
+const apiFetchAlbumsByArtist = async (artistId) => {
+ // TODO: This call can be removed once user login has been implemented
+ var token = await apiAuthenticate(username, password);
+
+ // Construct the request headers
+ const headers = {
+ Authorization: `Bearer ${token}`,
+ };
+
+ // Call the API to get a list of all artists
+ const url = baseUrl + `/albums/artist/${artistId}`;
+ const response = await fetch(url, {
+ method: "GET",
+ headers: headers,
+ });
+
+ // Get the response content as JSON and return it
+ const albums = await response.json();
+ return albums;
+};
+
+export { apiAuthenticate, apiFetchAllArtists, apiFetchAlbumsByArtist };
diff --git a/src/music-catalogue-ui/helpers/constants.js b/src/music-catalogue-ui/helpers/constants.js
index 80c4b3a..24c72c9 100644
--- a/src/music-catalogue-ui/helpers/constants.js
+++ b/src/music-catalogue-ui/helpers/constants.js
@@ -1,6 +1,6 @@
// This file is temporary, pending implementation of user login
-const username = "a-user";
-const password = "the-password";
-const baseUrl = "http://host:port";
+const username = "dave";
+const password = "password";
+const baseUrl = "http://localhost:8098";
export { baseUrl, username, password };
diff --git a/src/music-catalogue-ui/hooks/useAlbums.js b/src/music-catalogue-ui/hooks/useAlbums.js
new file mode 100644
index 0000000..f10cb6e
--- /dev/null
+++ b/src/music-catalogue-ui/hooks/useAlbums.js
@@ -0,0 +1,34 @@
+import statuses from "@/helpers/status";
+import { useState, useEffect } from "react";
+import { apiFetchAlbumsByArtist } from "@/helpers/api";
+
+const useAlbums = (artistId) => {
+ // Current list of albums and the method to change it
+ const [albums, setAlbums] = useState([]);
+
+ // Current status indicator and the method to change it, defaults to "loading"
+ const [currentStatus, setCurrentStatus] = useState(statuses.isLoading);
+
+ useEffect(() => {
+ const fetchAlbums = async (artistId) => {
+ // Set the "loading" indicator
+ setCurrentStatus(statuses.isLoading);
+
+ try {
+ // Get a list of albums via the service, store it in state and clear the
+ // loading status
+ var fetchedAlbums = await apiFetchAlbumsByArtist(artistId);
+ setAlbums(fetchedAlbums);
+ setCurrentStatus(statuses.loaded);
+ } catch {
+ setCurrentStatus(statuses.hasErrored);
+ }
+ };
+
+ fetchAlbums(artistId);
+ }, []);
+
+ return { albums, setAlbums, currentStatus };
+};
+
+export default useAlbums;