Skip to content

Commit

Permalink
Added album list by artist
Browse files Browse the repository at this point in the history
  • Loading branch information
davewalker5 committed Oct 10, 2023
1 parent 58a3f08 commit 33feb05
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 52 deletions.
36 changes: 36 additions & 0 deletions src/music-catalogue-ui/components/albumList.js
Original file line number Diff line number Diff line change
@@ -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 <StatusIndicator currentStatus={currentStatus} />;

return (
<>
<div className="row mb-2">
<h5 className="themeFontColor text-center">Albums</h5>
</div>
<table className="table table-hover">
<thead>
<tr>
<th>Album Title</th>
<th>Artist</th>
<th>Genre</th>
<th>Released</th>
</tr>
</thead>
<tbody>
{albums.map((a) => (
<AlbumRow key={a.id} artist={artist} album={a} navgate={navigate} />
))}
</tbody>
</table>
</>
);
};

export default AlbumList;
14 changes: 14 additions & 0 deletions src/music-catalogue-ui/components/albumRow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import pages from "@/helpers/navigation";

const AlbumRow = ({ artist, album, navigate }) => {
return (
<tr onClick={() => navigate(pages.tracks, album)}>
<td>{artist.name}</td>
<td>{album.title}</td>
<td>{album.genre}</td>
<td>{album.released}</td>
</tr>
);
};

export default AlbumRow;
43 changes: 19 additions & 24 deletions src/music-catalogue-ui/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<navigationContext.Provider value={page}>
<Banner>
<div>Personal Music Catalogue</div>
</Banner>
<ComponentPicker currentPage={page.current} />
</navigationContext.Provider>
<>
<Banner navigate={navigate} />
<ComponentPicker context={context} navigate={navigate} />
</>
);
};

export { navigationContext };
export default App;
5 changes: 2 additions & 3 deletions src/music-catalogue-ui/components/artistList.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 <StatusIndicator currentStatus={currentStatus} />;

Expand All @@ -23,7 +22,7 @@ const ArtistList = ({ onSelected }) => {
</thead>
<tbody>
{artists.map((a) => (
<ArtistRow key={a.id} artist={a} onSelected={onSelected} />
<ArtistRow key={a.id} artist={a} navigate={navigate} />
))}
</tbody>
</table>
Expand Down
8 changes: 2 additions & 6 deletions src/music-catalogue-ui/components/artistRow.js
Original file line number Diff line number Diff line change
@@ -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 (
<tr onClick={() => navigate(pages.albums, artist)}>
<tr onClick={() => navigate(pages.albums, artist, null)}>
<td>{artist.name}</td>
</tr>
);
Expand Down
15 changes: 5 additions & 10 deletions src/music-catalogue-ui/components/banner.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
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 (
<header className="row mb-4">
<div className="col-2">
<img
src="./logo.png"
alt="Music Catalogue"
className={styles.logo}
onClick={() => navigate(pages.artists)}
onClick={() => navigate(pages.artists, null, null)}
/>
</div>
<div className="col-9 mt-5">
<div className={styles.title}>{children}</div>
<div className={styles.title}>
<div>Personal Music Catalogue</div>
</div>
</div>
</header>
);
Expand Down
9 changes: 5 additions & 4 deletions src/music-catalogue-ui/components/componentPicker.js
Original file line number Diff line number Diff line change
@@ -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 <ArtistList />;
return <ArtistList navigate={navigate} />;
case pages.albums:
return <span></span>;
return <AlbumList artist={context.artist} navigate={navigate} />;
case pages.tracks:
return <span></span>;
default:
Expand Down
25 changes: 23 additions & 2 deletions src/music-catalogue-ui/helpers/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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 };
6 changes: 3 additions & 3 deletions src/music-catalogue-ui/helpers/constants.js
Original file line number Diff line number Diff line change
@@ -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 };
34 changes: 34 additions & 0 deletions src/music-catalogue-ui/hooks/useAlbums.js
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 33feb05

Please sign in to comment.