Skip to content

Commit fdd045d

Browse files
authored
Merge pull request #2731 from metabrainz/migrate-user-feed-to-spa
Migrate user dashboard and Explore pages to SPA
2 parents 22edab8 + 148c5c1 commit fdd045d

File tree

101 files changed

+3790
-3804
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+3790
-3804
lines changed

Diff for: frontend/css/listens-page.less

+5
Original file line numberDiff line numberDiff line change
@@ -725,3 +725,8 @@
725725
}
726726
}
727727
}
728+
729+
.user-charts-pill {
730+
color: unset !important;
731+
text-decoration: unset !important;
732+
}

Diff for: frontend/css/new-navbar.less

+1
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ body {
277277
a:visited,
278278
a:visited:hover {
279279
color: @white;
280+
background: initial;
280281
}
281282
}
282283
&.disabled {

Diff for: frontend/js/src/common/listens/ListenCard.tsx

+1-4
Original file line numberDiff line numberDiff line change
@@ -475,10 +475,7 @@ export default class ListenCard extends React.Component<
475475
</div>
476476
)}
477477
</div>
478-
<div
479-
className="small text-muted ellipsis"
480-
title={artistName}
481-
>
478+
<div className="small text-muted ellipsis" title={artistName}>
482479
{getArtistLink(listen)}
483480
</div>
484481
</div>

Diff for: frontend/js/src/error/ErrorBoundary.tsx

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from "react";
2+
import { Helmet } from "react-helmet";
3+
import { isRouteErrorResponse, useRouteError } from "react-router-dom";
4+
5+
const ErrorStatusMessage: { [key: number]: string } = {
6+
400: "Invalid request",
7+
401: "Unauthorized",
8+
403: "Access denied",
9+
404: "Page not found",
10+
413: "Filesize limit exceeded",
11+
500: "Internal server error",
12+
503: "Service unavailable",
13+
};
14+
15+
type RouteError = {
16+
status?: number;
17+
message?: string;
18+
data?: any;
19+
};
20+
21+
export function ErrorBoundary() {
22+
const error = useRouteError() as RouteError;
23+
const errorStatus = error.status || 500;
24+
const errorStatusMessage = ErrorStatusMessage[errorStatus] || "Error";
25+
26+
const errorMessage = error.data?.error || error.message || errorStatusMessage;
27+
28+
return isRouteErrorResponse(error) ? (
29+
<>
30+
<Helmet>
31+
<title>{errorStatusMessage}</title>
32+
</Helmet>
33+
<h2 className="page-title">{errorStatusMessage}</h2>
34+
<p>
35+
<code>{`${errorStatus}: ${errorMessage}`}</code>
36+
</p>
37+
<p>
38+
<a href="/">Back to home page</a>
39+
</p>
40+
</>
41+
) : (
42+
<>
43+
<Helmet>
44+
<title>Error</title>
45+
</Helmet>
46+
<h2 className="page-title">Error Occured!</h2>
47+
</>
48+
);
49+
}
50+
51+
export default ErrorBoundary;

Diff for: frontend/js/src/explore/Explore.tsx

+19-30
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
/* eslint-disable jsx-a11y/anchor-is-valid */
22

3-
import { createRoot } from "react-dom/client";
43
import * as React from "react";
54
import { useContext } from "react";
6-
import { getPageProps } from "../utils/utils";
75

8-
import ErrorBoundary from "../utils/ErrorBoundary";
6+
import { Link } from "react-router-dom";
7+
import { Helmet } from "react-helmet";
98
import GlobalAppContext from "../utils/GlobalAppContext";
109

1110
type ExploreCardProps = {
@@ -20,9 +19,9 @@ function ExploreCard(props: ExploreCardProps) {
2019
return (
2120
<div className="explore-card-container">
2221
<div className="explore-card">
23-
<a href={url}>
22+
<Link to={url}>
2423
<div className="explore-card-img-overlay"> </div>
25-
</a>
24+
</Link>
2625
<div className="explore-card-img-clip flex-center">
2726
<img
2827
src={`/static/img/explore/${img_name}`}
@@ -32,7 +31,7 @@ function ExploreCard(props: ExploreCardProps) {
3231
</div>
3332
<div className="explore-card-text">
3433
<div className="explore-card-text-name">
35-
<a href={url}>{name}</a>
34+
<Link to={url}>{name}</Link>
3635
</div>
3736
<div>{desc}</div>
3837
</div>
@@ -41,41 +40,44 @@ function ExploreCard(props: ExploreCardProps) {
4140
);
4241
}
4342

44-
function ExplorePage() {
43+
export default function ExplorePage() {
4544
const { currentUser } = useContext(GlobalAppContext);
4645
return (
4746
<>
47+
<Helmet>
48+
<title>Explore</title>
49+
</Helmet>
4850
<div className="row">
4951
<div>
5052
<ExploreCard
5153
name="Fresh Releases"
5254
desc="Discover"
5355
img_name="fresh-releases.jpg"
54-
url="/explore/fresh-releases"
56+
url="/explore/fresh-releases/"
5557
/>
5658
</div>
5759
<div>
5860
<ExploreCard
5961
name="Hue Sound"
6062
desc="Discover"
6163
img_name="huesound.jpg"
62-
url="/explore/huesound"
64+
url="/explore/huesound/"
6365
/>
6466
</div>
6567
<div>
6668
<ExploreCard
6769
name="Cover Art Collage"
6870
desc="Discover"
6971
img_name="cover-art-collage.jpg"
70-
url="/explore/cover-art-collage"
72+
url="/explore/cover-art-collage/"
7173
/>
7274
</div>
7375
<div>
7476
<ExploreCard
7577
name="Music Neighborhood"
7678
desc="Visualisation"
7779
img_name="music-neighborhood.jpg"
78-
url="/explore/music-neighborhood"
80+
url="/explore/music-neighborhood/"
7981
/>
8082
</div>
8183
{currentUser?.name && (
@@ -84,7 +86,7 @@ function ExplorePage() {
8486
name="Your Year in Music 2023"
8587
desc="Review"
8688
img_name="year-in-music-2023.jpg"
87-
url={`/user/${currentUser.name}/year-in-music/2023`}
89+
url={`/user/${currentUser.name}/year-in-music/2023/`}
8890
/>
8991
</div>
9092
)}
@@ -94,7 +96,7 @@ function ExplorePage() {
9496
name="Your Year in Music 2022"
9597
desc="Review"
9698
img_name="year-in-music-2022.jpg"
97-
url={`/user/${currentUser.name}/year-in-music/2022`}
99+
url={`/user/${currentUser.name}/year-in-music/2022/`}
98100
/>
99101
</div>
100102
)}
@@ -104,7 +106,7 @@ function ExplorePage() {
104106
name="Your Year in Music 2021"
105107
desc="Review"
106108
img_name="year-in-music-2021.jpg"
107-
url={`/user/${currentUser.name}/year-in-music/2021`}
109+
url={`/user/${currentUser.name}/year-in-music/2021/`}
108110
/>
109111
</div>
110112
)}
@@ -113,7 +115,7 @@ function ExplorePage() {
113115
name="Top Similar Users"
114116
desc="Social"
115117
img_name="similar-users.jpg"
116-
url="/explore/similar-users"
118+
url="/explore/similar-users/"
117119
/>
118120
</div>
119121
</div>
@@ -126,28 +128,15 @@ function ExplorePage() {
126128
name="ListenBrainz Radio"
127129
desc="Instant custom playlists"
128130
img_name="lb-radio-beta.jpg"
129-
url="/explore/lb-radio"
131+
url="/explore/lb-radio/"
130132
/>
131133
<ExploreCard
132134
name="Stats art generator"
133135
desc="Visualize and share your stats"
134136
img_name="stats-art-beta.jpg"
135-
url="/explore/art-creator"
137+
url="/explore/art-creator/"
136138
/>
137139
</div>
138140
</>
139141
);
140142
}
141-
142-
document.addEventListener("DOMContentLoaded", async () => {
143-
const { domContainer, globalAppContext } = await getPageProps();
144-
145-
const renderRoot = createRoot(domContainer!);
146-
renderRoot.render(
147-
<ErrorBoundary>
148-
<GlobalAppContext.Provider value={globalAppContext}>
149-
<ExplorePage />
150-
</GlobalAppContext.Provider>
151-
</ErrorBoundary>
152-
);
153-
});

0 commit comments

Comments
 (0)