Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 49 additions & 17 deletions frontend/js/src/user/stats/UserReports.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ import {
faUser,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useLoaderData, useNavigate, useSearchParams } from "react-router";
import {
Link,
useLoaderData,
useNavigate,
useSearchParams,
} from "react-router";
import { Helmet } from "react-helmet";

import Tooltip from "react-tooltip";
import NiceModal from "@ebay/nice-modal-react";
import { Card } from "react-bootstrap";
import Pill from "../../components/Pill";
import UserListeningActivity from "./components/UserListeningActivity";
import UserTopEntity from "./components/UserTopEntity";
Expand All @@ -37,7 +43,7 @@ export default function UserReports() {
const { user = undefined } = props ?? {};

// Context
const { currentUser } = React.useContext(GlobalAppContext);
const { currentUser, APIService } = React.useContext(GlobalAppContext);

// Router
const navigate = useNavigate();
Expand Down Expand Up @@ -80,6 +86,16 @@ export default function UserReports() {
</button>
);

const encodedUserOrCurrentUserName = user?.name
? encodeURIComponent(user.name)
: encodeURIComponent(currentUser.name);
let albumStatsUrl = "";
if (user) {
albumStatsUrl = `/user/${encodeURIComponent(user.name)}/stats`;
} else {
albumStatsUrl = `/statistics`;
}
albumStatsUrl += `/top-albums/?range=${range}`;
return (
<div data-testid="User Reports">
<Helmet>
Expand Down Expand Up @@ -107,11 +123,7 @@ export default function UserReports() {
type="button"
onClick={() => {
navigate(
`/user/${
user?.name
? encodeURIComponent(user.name)
: encodeURIComponent(currentUser.name)
}/stats/?range=${range}`
`/user/${encodedUserOrCurrentUserName}/stats/?range=${range}`
);
}}
className={`pill secondary ${user ? "active" : ""}`}
Expand All @@ -138,28 +150,48 @@ export default function UserReports() {
<section id="top-entity">
{statsExplanationModalButton}
<div className="row">
<div className="col-md-4">
<div className="col-md-8 col-sm-6 d-flex">
<Card className="flex-grow-1" data-testid="top-release-group">
<h3 className="capitalize-bold text-center">Top albums</h3>
<object
className="p-5 m-auto"
width="100%"
style={{
maxWidth: "600px",
width: "-webkit-fill-available",
}}
aria-label="Album cover grid"
data={`${APIService.APIBaseURI}/art/grid-stats/${encodedUserOrCurrentUserName}/${range}/5/1/600`}
/>
<div className="flex-center gap-3 mb-4">
<Link to={albumStatsUrl} className="btn btn-outline-info">
View more...
</Link>
<Link
to="/explore/art-creator/"
className="btn btn-outline-info"
>
More album grids…
</Link>
</div>
</Card>
</div>
<div className="col-md-4 col-sm-6 d-flex">
<UserTopEntity
range={range}
entity="artist"
user={user}
terminology="artist"
/>
</div>
<div className="col-md-4">
<UserTopEntity
range={range}
entity="release-group"
user={user}
terminology="album"
/>
</div>
<div className="col-md-4">
<div className="col-12">
<UserTopEntity
numberOfEntities={12}
range={range}
entity="recording"
user={user}
terminology="track"
contentCssClassName="top-entity-listencards"
/>
</div>
</div>
Expand Down
9 changes: 8 additions & 1 deletion frontend/js/src/user/stats/components/UserArtistActivity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { useQuery } from "@tanstack/react-query";
import { useNavigate, Link } from "react-router";
import { useMediaQuery } from "react-responsive";
import Card from "../../../components/Card";
import Loader from "../../../components/Loader";
import GlobalAppContext from "../../../utils/GlobalAppContext";
Expand Down Expand Up @@ -49,6 +50,7 @@ function CustomTooltip({
export default function UserArtistActivity(props: UserArtistActivityProps) {
const { APIService } = React.useContext(GlobalAppContext);
const navigate = useNavigate();
const isMobile = useMediaQuery({ maxWidth: 767 });

// Props
const { user, range } = props;
Expand Down Expand Up @@ -189,7 +191,12 @@ export default function UserArtistActivity(props: UserArtistActivityProps) {
)
)}
indexBy="label"
margin={{ top: 20, right: 80, bottom: 100, left: 120 }}
margin={{
top: 20,
right: isMobile ? 0 : 80,
bottom: 100,
left: isMobile ? 20 : 120,
}}
padding={0.2}
layout="vertical"
colors={{ scheme: "nivo" }}
Expand Down
23 changes: 18 additions & 5 deletions frontend/js/src/user/stats/components/UserTopEntity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export type UserTopEntityProps = {
entity: Entity;
user?: ListenBrainzUser;
terminology: string;
contentCssClassName?: string;
numberOfEntities?: number;
};

export type UserTopEntityState = {
Expand All @@ -29,7 +31,14 @@ export type UserTopEntityState = {
export default function UserTopEntity(props: UserTopEntityProps) {
const { APIService } = React.useContext(GlobalAppContext);

const { range, entity, user, terminology } = props;
const {
range,
entity,
user,
terminology,
contentCssClassName,
numberOfEntities = 10,
} = props;

// Loader Data
const { data: loaderData, isLoading: loading } = useQuery({
Expand All @@ -41,7 +50,7 @@ export default function UserTopEntity(props: UserTopEntityProps) {
entity,
range,
0,
10
numberOfEntities
);
return {
data: queryData,
Expand Down Expand Up @@ -74,7 +83,7 @@ export default function UserTopEntity(props: UserTopEntityProps) {
const entityTextOnCard = `${terminology}s`;
if (hasError) {
return (
<Card className="mt-4" data-testid="error-message">
<Card data-testid="error-message">
<h3 className="capitalize-bold text-center">Top {entityTextOnCard}</h3>
<div className="text-center">
<FontAwesomeIcon icon={faExclamationCircle as IconProp} />{" "}
Expand All @@ -85,10 +94,14 @@ export default function UserTopEntity(props: UserTopEntityProps) {
}

return (
<Card className="mt-4" data-testid={`top-${entity}`}>
<Card className="flex-grow-1" data-testid={`top-${entity}`}>
<h3 className="capitalize-bold text-center">Top {entityTextOnCard}</h3>
<Loader isLoading={loading}>
<div style={{ padding: "1em" }} data-testid={`top-${entity}-list`}>
<div
style={{ padding: "1em" }}
data-testid={`top-${entity}-list`}
className={contentCssClassName}
>
{entity === "artist" &&
Object.keys(data).length > 0 &&
(data as UserArtistsResponse).payload.artists.map(
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.