Skip to content

Commit

Permalink
MRTK-26: implements artist spotlight with API data (#656)
Browse files Browse the repository at this point in the history
* implements artist spotlight with API data

* moves artist logic to artist module

* moves just released logic to own component

* only features artists with marketplace sales

* updates artist skeleton styling

* removes errant code

* minor updates
  • Loading branch information
scandycuz authored May 26, 2024
1 parent 703828a commit 5030e20
Show file tree
Hide file tree
Showing 15 changed files with 294 additions and 68 deletions.
2 changes: 2 additions & 0 deletions apps/marketplace/src/api/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* back-end expects for recaptcha action argument.
*/
export const recaptchaEndpointActionMap: Record<string, string> = {
getArtist: "get_artist",
getArtists: "get_artists",
getSale: "get_sale",
getSales: "get_sales",
};
2 changes: 1 addition & 1 deletion apps/marketplace/src/api/newm/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const api = createApi({
baseQuery,
endpoints: () => ({}),
reducerPath: "newmApi",
tagTypes: [Tags.Sale],
tagTypes: [Tags.Sale, Tags.Artist],
});

export default api;
1 change: 1 addition & 0 deletions apps/marketplace/src/api/newm/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export enum Tags {
Artist = "Artist",
Sale = "Sale",
}
2 changes: 1 addition & 1 deletion apps/marketplace/src/app/artist/[artistId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { mockArtist } from "../../../temp/data";

interface ArtistProps {
readonly params: {
readonly id: string;
readonly artistId: string;
};
}

Expand Down
14 changes: 3 additions & 11 deletions apps/marketplace/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
"use client";
import { FunctionComponent } from "react";
import { Box, Container } from "@mui/material";
import { ArtistSpotlight, Sales } from "../components";
import { useGetSalesQuery } from "../modules/sale";
import { Container } from "@mui/material";
import { ArtistSpotlight, RecentSongs } from "../components";

const Home: FunctionComponent = () => {
const { data, isLoading } = useGetSalesQuery({
limit: 8,
sortOrder: "desc",
});

return (
<Container sx={ { flexGrow: 1 } }>
<Box mt={ [7.5, 5.5, 10] }>
<Sales isLoading={ isLoading } sales={ data } title="JUST RELEASED" />
</Box>
<RecentSongs />

<ArtistSpotlight />
</Container>
Expand Down
70 changes: 17 additions & 53 deletions apps/marketplace/src/components/ArtistSpotlight.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,25 @@
import { FunctionComponent, useEffect, useState } from "react";
import { Grid, Stack, Typography } from "@mui/material";
import { useRouter } from "next/navigation";
import Artist from "./Artist";
import { mockArtists } from "../temp/data";
import { FunctionComponent } from "react";
import { Stack } from "@mui/material";
import Artists from "./Artists";
import { useGetArtistsQuery } from "../modules/artist";

const ArtistSpotlight: FunctionComponent = () => {
const router = useRouter();

// TEMP: simulate data loading
const [isLoading, setIsLoading] = useState(true);

const handleSelectArtist = (id: string) => {
router.push(`/artist/${id}`);
};

// TEMP: simulate data loading
useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
// TODO: update params to only return artists with sales when API updated
const { isLoading, data: artists = [] } = useGetArtistsQuery({
limit: 10,
sortOrder: "desc",
});

return (
<Stack mb={ 8 }>
<Stack alignItems="center" mb={ 3.5 } mt={ 17 }>
<Typography fontSize={ ["24px", "24px", "32px"] } variant="h3">
ARTIST SPOTLIGHT
</Typography>
</Stack>

<Grid justifyContent="center" rowGap={ 5 } container>
{ mockArtists.map(
({ id, profileImageUrl, firstName, lastName, songCount }, idx) => {
return (
<Grid
display="flex"
justifyContent="center"
key={ id }
lg={ 2.4 }
md={ 3 }
sm={ 4 }
xs={ 6 }
item
>
<Artist
imageUrl={ profileImageUrl }
isLoading={ isLoading }
orientation="column"
subtitle={ `${songCount} songs` }
title={ `${firstName} ${lastName}` }
onSelectArtist={ () => handleSelectArtist(id) }
/>
</Grid>
);
}
) }
</Grid>
<Artists
artists={ artists }
isLoading={ isLoading }
itemOrientation="column"
numSkeletons={ 10 }
title="ARTIST SPOTLIGHT"
hasTitle
/>
</Stack>
);
};
Expand Down
80 changes: 80 additions & 0 deletions apps/marketplace/src/components/Artists.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { FunctionComponent } from "react";
import { Grid, Stack, Typography } from "@mui/material";
import { useRouter } from "next/navigation";
import ArtistsSkeleton from "./skeletons/ArtistsSkeleton";
import Artist from "./Artist";
import { Artist as ArtistItem } from "../modules/artist";

interface ArtistsProps {
readonly artists?: ReadonlyArray<ArtistItem>;
readonly hasTitle?: boolean;
readonly isLoading?: boolean;
readonly itemOrientation: "row" | "column";
readonly numSkeletons?: number;
readonly title?: string;
}

const Artists: FunctionComponent<ArtistsProps> = ({
hasTitle = true,
isLoading = false,
itemOrientation,
numSkeletons = 10,
artists = [],
title,
}) => {
const router = useRouter();

const handleSelectArtist = (id: string) => {
router.push(`/artist/${id}`);
};

if (isLoading) {
return (
<Stack alignItems="center" mb={ 3.5 } mt={ 17 }>
<ArtistsSkeleton
hasTitle={ hasTitle }
itemOrientation={ itemOrientation }
numItems={ numSkeletons }
/>
</Stack>
);
}

return (
<Stack>
<Stack alignItems="center" mb={ 3.5 } mt={ 17 }>
<Typography fontSize={ ["24px", "24px", "32px"] } variant="h3">
ARTIST SPOTLIGHT
</Typography>
</Stack>

<Grid justifyContent="flex-start" rowGap={ 5 } container>
{ artists.map(({ id, pictureUrl, name, marketplaceSongCount }, idx) => {
return (
<Grid
display="flex"
justifyContent="center"
key={ id }
lg={ 2.4 }
md={ 3 }
sm={ 4 }
xs={ 6 }
item
>
<Artist
imageUrl={ pictureUrl }
isLoading={ isLoading }
orientation="column"
subtitle={ `${marketplaceSongCount} songs` }
title={ name }
onSelectArtist={ () => handleSelectArtist(id) }
/>
</Grid>
);
}) }
</Grid>
</Stack>
);
};

export default Artists;
19 changes: 19 additions & 0 deletions apps/marketplace/src/components/RecentSongs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Box } from "@mui/material";
import { FunctionComponent } from "react";
import Sales from "./Sales";
import { useGetSalesQuery } from "../modules/sale/api";

const RecentSongs: FunctionComponent = () => {
const { data, isLoading } = useGetSalesQuery({
limit: 8,
sortOrder: "desc",
});

return (
<Box mt={ [7.5, 5.5, 10] }>
<Sales isLoading={ isLoading } sales={ data } title="JUST RELEASED" />
</Box>
);
};

export default RecentSongs;
3 changes: 2 additions & 1 deletion apps/marketplace/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
export * from "./Artist";
export * from "./skeletons/index";
export { default as Artist } from "./Artist";
export { default as ArtistsSkeleton } from "./skeletons/ArtistsSkeleton";
export { default as ArtistSongs } from "./ArtistSongs";
export { default as ArtistSpotlight } from "./ArtistSpotlight";
export { default as Footer } from "./footer/Footer";
export { default as Header } from "./header/Header";
export { default as SaleSkeleton } from "./skeletons/SaleSkeleton";
export { default as MoreSongs } from "./MoreSongs";
export { default as RecentSongs } from "./RecentSongs";
export { default as Sale } from "./Sale";
export { default as SaleMetadata } from "./SaleMetadata";
export { default as SearchResults } from "./SearchResults";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const ArtistSkeleton: FunctionComponent<ArtistSkeletonProps> = ({
orientation,
}) => (
<Stack
alignItems="center"
direction={ orientation }
p={ 1.5 }
spacing={ orientation === "column" ? 1.25 : 4 }
Expand Down
44 changes: 44 additions & 0 deletions apps/marketplace/src/components/skeletons/ArtistsSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Box, Grid, Skeleton, Stack } from "@mui/material";
import { FunctionComponent } from "react";
import ArtistSkeleton from "./ArtistSkeleton";

interface SalesSkeletonProps {
readonly hasTitle?: boolean;
readonly itemOrientation: "column" | "row";
readonly numItems?: number;
}

const SalesSkeleton: FunctionComponent<SalesSkeletonProps> = ({
hasTitle = true,
numItems = 10,
itemOrientation,
}) => {
return (
<Stack alignItems="center">
{ hasTitle && (
<Box mb={ 3.5 }>
<Skeleton height={ 76 } width={ 480 } />
</Box>
) }

<Grid justifyContent="flex-start" pb={ 1 } rowGap={ 1.5 } container>
{ new Array(numItems).fill(null).map((_, idx) => {
return (
<Grid
key={ idx }
lg={ itemOrientation === "column" ? 2.4 : 3 }
md={ 3 }
sm={ 4 }
xs={ 6 }
item
>
<ArtistSkeleton orientation={ itemOrientation } />
</Grid>
);
}) }
</Grid>
</Stack>
);
};

export default SalesSkeleton;
1 change: 0 additions & 1 deletion apps/marketplace/src/components/skeletons/index.ts

This file was deleted.

64 changes: 64 additions & 0 deletions apps/marketplace/src/modules/artist/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {
GetArtistResponse,
GetArtistsParams,
GetArtistsResponse,
} from "./types";
import { newmApi } from "../../api";
import { setToastMessage } from "../ui";
import { Tags } from "../../api/newm/types";

export const extendedApi = newmApi.injectEndpoints({
endpoints: (build) => ({
getArtist: build.query<GetArtistResponse, string>({
async onQueryStarted(body, { dispatch, queryFulfilled }) {
try {
await queryFulfilled;
} catch (error) {
dispatch(
setToastMessage({
message: "An error occurred while fetching artist",
severity: "error",
})
);
}
},

providesTags: [Tags.Artist],

query: (id) => ({
method: "GET",
url: `v1/marketplace/artists/${id}`,
}),
}),
getArtists: build.query<GetArtistsResponse, GetArtistsParams | void>({
async onQueryStarted(body, { dispatch, queryFulfilled }) {
try {
await queryFulfilled;
} catch (error) {
dispatch(
setToastMessage({
message: "An error occurred while fetching artists",
severity: "error",
})
);
}
},

providesTags: [Tags.Artist],

query: ({ ids, genres, ...rest } = {}) => ({
method: "GET",
params: {
...(ids ? { ids: ids.join(",") } : {}),
...(genres ? { genres: genres.join(",") } : {}),
...rest,
},
url: "v1/marketplace/artists",
}),
}),
}),
});

export const { useGetArtistsQuery, useGetArtistQuery } = extendedApi;

export default extendedApi;
2 changes: 2 additions & 0 deletions apps/marketplace/src/modules/artist/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./api";
export * from "./types";
Loading

0 comments on commit 5030e20

Please sign in to comment.