Skip to content

Commit

Permalink
feat(user): more deeplinks on user page
Browse files Browse the repository at this point in the history
  • Loading branch information
stijnvdkolk committed Feb 11, 2024
1 parent 847f22f commit 59aa23f
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 31 deletions.
12 changes: 12 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ module.exports = withBundleAnalyzer({
source: '/:id/tracks',
destination: '/user/:id/tracks',
},
{
source: '/:id/listeningClocks',
destination: '/user/:id/listeningClocks',
},
{
source: '/:id/genres',
destination: '/user/:id/genres',
},
{
source: '/:id/recentStreams',
destination: '/user/:id/recentStreams',
},
];
},
generateBuildId: () => nextBuildId({ dir: __dirname }),
Expand Down
5 changes: 2 additions & 3 deletions src/components/User/TopAlbums.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { TopAlbum, UserPublic } from '@statsfm/statsfm.js';
import type { RefObject } from 'react';
import { useState, type FC, useEffect } from 'react';
import { event } from 'nextjs-google-analytics';
import type { UserPageCarouselsWithGrid } from '@/utils';
import { Carousel } from '../Carousel';
import Scope from '../PrivacyScope';
import {
Expand All @@ -26,7 +25,7 @@ export const TopAlbums: FC<{
timeframe: TimeframeSelection;
albumRef: RefObject<HTMLElement>;
userProfile: UserPublic;
activeCarousel: UserPageCarouselsWithGrid | null;
activeCarousel: boolean;
}> = ({ albumRef, userProfile, timeframe, activeCarousel }) => {
const api = useApi();
const { user: currentUser } = useAuth();
Expand Down Expand Up @@ -60,7 +59,7 @@ export const TopAlbums: FC<{
const isCurrentUser = currentUser?.id === userProfile.id;

return (
<Carousel gridMode={activeCarousel === 'albums'} itemHeight={255}>
<Carousel gridMode={activeCarousel} itemHeight={255}>
<Section
ref={albumRef}
title="Top albums"
Expand Down
8 changes: 3 additions & 5 deletions src/components/User/TopArtists.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useApi, useAuth } from '@/hooks';
import formatter from '@/utils/formatter';
import type { TopArtist, UserPublic } from '@statsfm/statsfm.js';
import type { RefObject } from 'react';
import { useState, type FC, useEffect } from 'react';
import { useState, type FC, useEffect, type RefObject } from 'react';
import { event } from 'nextjs-google-analytics';
import type { UserPageCarouselsWithGrid } from '@/utils';
import { Carousel } from '../Carousel';
import Scope from '../PrivacyScope';
import {
Expand All @@ -26,7 +24,7 @@ export const TopArtists: FC<{
timeframe: TimeframeSelection;
artistRef: RefObject<HTMLElement>;
userProfile: UserPublic;
activeCarousel: UserPageCarouselsWithGrid | null;
activeCarousel: boolean;
}> = ({ artistRef, userProfile, timeframe, activeCarousel }) => {
const api = useApi();
const { user: currentUser } = useAuth();
Expand Down Expand Up @@ -60,7 +58,7 @@ export const TopArtists: FC<{
const isCurrentUser = currentUser?.id === userProfile.id;

return (
<Carousel gridMode={activeCarousel === 'artists'} itemHeight={262}>
<Carousel gridMode={activeCarousel} itemHeight={262}>
<Section
ref={artistRef}
title="Top artists"
Expand Down
4 changes: 3 additions & 1 deletion src/components/User/TopGenres.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import { NotEnoughData } from './NotEnoughData';
export const TopGenres: FC<{
timeframe: TimeframeSelection;
userProfile: UserPublic;
}> = ({ userProfile, timeframe }) => {
topGenresRef: React.RefObject<HTMLElement>;
}> = ({ userProfile, timeframe, topGenresRef: ref }) => {
const api = useApi();
const { user: currentUser } = useAuth();
const [topGenres, setTopGenres] = useState<TopGenre[]>([]);
Expand All @@ -38,6 +39,7 @@ export const TopGenres: FC<{
isCurrentUser ? 'Your' : `${userProfile.displayName}'s`
} top genres ${getTimeframeText(timeframe)}`}
scope="topGenres"
ref={ref}
>
<Scope value="topGenres">
<ChipGroup
Expand Down
8 changes: 3 additions & 5 deletions src/components/User/TopTracks.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useApi, useAuth } from '@/hooks';
import formatter from '@/utils/formatter';
import type { TopTrack, UserPublic } from '@statsfm/statsfm.js';
import type { RefObject } from 'react';
import { useState, type FC, useEffect } from 'react';
import { useState, type FC, useEffect, type RefObject } from 'react';
import { event } from 'nextjs-google-analytics';
import type { UserPageCarouselsWithGrid } from '@/utils';
import { Carousel } from '../Carousel';
import Scope from '../PrivacyScope';
import {
Expand All @@ -26,7 +24,7 @@ export const TopTracks: FC<{
timeframe: TimeframeSelection;
trackRef: RefObject<HTMLElement>;
userProfile: UserPublic;
activeCarousel: UserPageCarouselsWithGrid | null;
activeCarousel: boolean;
}> = ({ trackRef, userProfile, timeframe, activeCarousel }) => {
const api = useApi();
const { user: currentUser } = useAuth();
Expand Down Expand Up @@ -60,7 +58,7 @@ export const TopTracks: FC<{
const isCurrentUser = currentUser?.id === userProfile.id;

return (
<Carousel gridMode={activeCarousel === 'tracks'} itemHeight={276}>
<Carousel gridMode={activeCarousel} itemHeight={276}>
<Section
ref={trackRef}
title="Top tracks"
Expand Down
54 changes: 38 additions & 16 deletions src/pages/user/[id]/[[...deeplink]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {
TopGenres,
TopTracks,
} from '@/components/User';
import { clockProps, type UserPageCarouselsWithGrid } from '@/utils';
import { clockProps, type UserScrollIntoView } from '@/utils';
import dynamic from 'next/dynamic';
import type { TimeframeSelection } from '@/components/User/utils';
import { getTimeframeOptions, getTimeframeText } from '@/components/User/utils';
Expand All @@ -51,18 +51,25 @@ type Props = SSRProps & {
userProfile: statsfm.UserPublic;
friendStatus: statsfm.FriendStatus;
friendCount: number;
activeCarousel: UserPageCarouselsWithGrid | null;
scrollIntoView: UserScrollIntoView | null;
};

function activeGridModeFromDeepLink(
function activeScrollIntoViewFromDeepLink(
deeplink: string | string[] | undefined
): UserPageCarouselsWithGrid | null {
): UserScrollIntoView | null {
if (typeof deeplink !== 'object') return null;
if (deeplink.length !== 1) return null;

const [id] = deeplink;
// TODO: this should rewrite or redirect
if (id !== 'tracks' && id !== 'albums' && id !== 'artists') return null;
if (
id !== 'genres' &&
id !== 'tracks' &&
id !== 'albums' &&
id !== 'artists' &&
id !== 'listeningClocks' &&
id !== 'recentStreams'
)
return null;

return id;
}
Expand All @@ -77,10 +84,13 @@ export const getServerSideProps: GetServerSideProps<Props> = async (ctx) => {
throw new Error('no param id recieved');
}

const activeCarousel = activeGridModeFromDeepLink(deeplink);
const scrollIntoView = activeScrollIntoViewFromDeepLink(deeplink);

const userProfile = await api.users.get(id).catch(() => {});
if (!userProfile) return { notFound: true };
if (!userProfile)
return {
notFound: true,
};

const user = await fetchUser(ctx);

Expand All @@ -105,11 +115,11 @@ export const getServerSideProps: GetServerSideProps<Props> = async (ctx) => {

return {
props: {
activeCarousel,
userProfile,
user,
friendStatus,
friendCount,
scrollIntoView,
},
};
};
Expand Down Expand Up @@ -199,7 +209,7 @@ const User: NextPage<Props> = ({
userProfile: user,
friendStatus,
friendCount,
activeCarousel,
scrollIntoView,
}) => {
const api = useApi();
const router = useRouter();
Expand All @@ -221,6 +231,9 @@ const User: NextPage<Props> = ({
const topTracksRef = useRef<HTMLElement>(null);
const topAlbumsRef = useRef<HTMLElement>(null);
const topArtistsRef = useRef<HTMLElement>(null);
const topGenresRef = useRef<HTMLElement>(null);
const listeningClocksRef = useRef<HTMLElement>(null);
const recentStreamsRef = useRef<HTMLElement>(null);

const isCurrentUser = currentUser?.id === user.id;

Expand Down Expand Up @@ -268,13 +281,16 @@ const User: NextPage<Props> = ({
}, [timeframe, user]);

useEffect(() => {
const refs: Record<UserPageCarouselsWithGrid, RefObject<HTMLElement>> = {
const refs: Record<UserScrollIntoView, RefObject<HTMLElement>> = {
tracks: topTracksRef,
albums: topAlbumsRef,
artists: topArtistsRef,
genres: topGenresRef,
listeningClocks: listeningClocksRef,
recentStreams: recentStreamsRef,
};

if (activeCarousel) refs[activeCarousel].current?.scrollIntoView();
if (scrollIntoView) refs[scrollIntoView].current?.scrollIntoView();
}, []);

// TODO: improvements
Expand Down Expand Up @@ -499,28 +515,32 @@ const User: NextPage<Props> = ({
)}
</section>

<TopGenres timeframe={timeframe} userProfile={user} />
<TopGenres
timeframe={timeframe}
userProfile={user}
topGenresRef={topGenresRef}
/>

<TopTracks
timeframe={timeframe}
userProfile={user}
trackRef={topTracksRef}
activeCarousel={activeCarousel}
activeCarousel={scrollIntoView === 'tracks'}
/>

<TopArtists
timeframe={timeframe}
userProfile={user}
artistRef={topArtistsRef}
activeCarousel={activeCarousel}
activeCarousel={scrollIntoView === 'artists'}
/>

{user.isPlus && (
<TopAlbums
timeframe={timeframe}
userProfile={user}
albumRef={topAlbumsRef}
activeCarousel={activeCarousel}
activeCarousel={scrollIntoView === 'albums'}
/>
)}

Expand All @@ -535,6 +555,7 @@ const User: NextPage<Props> = ({
} listening habits throughout the day ${getTimeframeText(
timeframe
)} `}
ref={listeningClocksRef}
>
<Scope value="streamStats">
<div className="flex-1 content-center text-center">
Expand All @@ -555,6 +576,7 @@ const User: NextPage<Props> = ({
isCurrentUser ? 'Your' : `${user.displayName}'s`
} recently played tracks`}
scope="recentlyPlayed"
ref={recentStreamsRef}
>
{({ headerRef }) => (
<Scope value="recentlyPlayed">
Expand Down
8 changes: 7 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@ export * from './AppConfig';
export * from './dayjs';
export * from './clocks';

export type UserPageCarouselsWithGrid = 'tracks' | 'albums' | 'artists';
export type UserScrollIntoView =
| 'genres'
| 'tracks'
| 'albums'
| 'artists'
| 'listeningClocks'
| 'recentStreams';

0 comments on commit 59aa23f

Please sign in to comment.