Skip to content

Commit e5c214e

Browse files
committed
feat: enhance podcast context and header to support category filtering and routing
1 parent d1a1ec5 commit e5c214e

File tree

6 files changed

+80
-33
lines changed

6 files changed

+80
-33
lines changed

src/app/podcasts/PodcastsContext.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
"use client";
22

3+
import { useRouter } from "next/navigation";
34
import { DTOChannel, getTotalPages, QueryParamChannels } from "podverse-helpers";
45
import React, { createContext, useContext, useState, ReactNode } from "react";
56
import { apiRequestService } from "../../factories/apiRequestService";
67
import { useAccount } from "../../contexts/Account";
78
import { useSkipInitialEffect } from "../../hooks/useSkipInitialEffect";
8-
import { getCurrentSortAndRange } from "./PodcastsDropdownConfig";
9+
import { getChannelQueryParams } from "./PodcastsDropdownConfig";
910

1011
interface PodcastsContextType {
1112
queryParams: QueryParamChannels;
@@ -28,6 +29,7 @@ export const PodcastsContextProvider = ({ children, initialQueryParams, ssrChann
2829
ssrChannels: DTOChannel[],
2930
ssrTotalPages: number
3031
}) => {
32+
const router = useRouter();
3133
const [queryParams, setQueryParams] = useState<QueryParamChannels>(initialQueryParams);
3234
const [channels, setChannels] = useState<DTOChannel[]>(ssrChannels || []);
3335
const [totalPages, setTotalPages] = useState<number>(ssrTotalPages || 1);
@@ -45,13 +47,30 @@ export const PodcastsContextProvider = ({ children, initialQueryParams, ssrChann
4547
}
4648
}
4749

48-
setShowSubscribeMessage(false);
4950
setIsLoading(true);
50-
const { currentSort, currentRange } = getCurrentSortAndRange({ type: queryParams.type, sort: queryParams.sort, range: queryParams.range });
51-
const response = await apiRequestService.reqChannelGetMany({ ...queryParams, sort: currentSort, range: currentRange });
51+
52+
const { currentSort, currentRange, currentType } = getChannelQueryParams({
53+
type: queryParams.type,
54+
sort: queryParams.sort,
55+
range: queryParams.range,
56+
category: queryParams.category
57+
});
58+
59+
const response = await apiRequestService.reqChannelGetMany({
60+
...queryParams,
61+
type: currentType,
62+
sort: currentSort,
63+
range: currentRange
64+
});
65+
66+
if (!queryParams.category) {
67+
router.replace("/podcasts");
68+
}
69+
5270
const totalPages = getTotalPages(response.meta.count, response.meta.limit);
5371
setTotalPages(totalPages);
5472
setChannels(response.data);
73+
setShowSubscribeMessage(false);
5574
setIsLoading(false);
5675
}
5776
fetchChannels();

src/app/podcasts/PodcastsDropdownConfig.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { QueryParamsChannelsType, QueryParamsChannelsSort, QueryParamsStatsRange } from "podverse-helpers";
1+
import { QueryParamsChannelsType, QueryParamsChannelsSort, QueryParamsStatsRange,
2+
CategoryMappingKeys } from "podverse-helpers";
23

3-
export function getDropdownConfig({ type, sort, tFilters }: {
4+
export function getDropdownConfig({ type, sort, category, tFilters }: {
45
sort?: QueryParamsChannelsSort,
56
type?: QueryParamsChannelsType,
7+
category?: CategoryMappingKeys | null,
68
tFilters: (key: string) => string
79
}) {
810
const sortTop = { label: tFilters("sort.top"), param: "sort", value: "top" };
@@ -27,11 +29,12 @@ export function getDropdownConfig({ type, sort, tFilters }: {
2729
{ label: tFilters("range.all_time"), param: "range", value: "all-time" },
2830
];
2931

30-
if (type === "all" || type === "category") {
32+
let showRangeDropdown = false;
33+
if (type === "all" || category) {
3134
sortDropdownMenuItems = [sortTop];
35+
showRangeDropdown = true;
3236
}
3337

34-
let showRangeDropdown = false;
3538
if (sort === "top") {
3639
showRangeDropdown = true;
3740
}
@@ -40,26 +43,32 @@ export function getDropdownConfig({ type, sort, tFilters }: {
4043
typeMenuItems: typeDropdownMenuItems,
4144
sortMenuItems: sortDropdownMenuItems,
4245
rangeMenuItems: rangeDropdownMenuItems,
43-
showRangeDropdown,
46+
showRangeDropdown
4447
};
4548
}
4649

4750
type QueryParamConfig = {
4851
type?: QueryParamsChannelsType;
4952
sort?: QueryParamsChannelsSort;
5053
range?: QueryParamsStatsRange;
54+
category?: CategoryMappingKeys | null;
5155
}
5256

53-
export function getCurrentSortAndRange({ type, sort, range }: QueryParamConfig) {
57+
export function getChannelQueryParams({ type, sort, range, category }: QueryParamConfig) {
5458
let currentSort = sort;
5559
let currentRange = range;
60+
let currentType = type;
5661

57-
if (type === "all" || type === "category") {
62+
if (category) {
63+
currentType = "category";
64+
currentSort = currentSort || "top";
65+
currentRange = currentRange || "day";
66+
} else if (type === "all") {
5867
currentSort = "top";
5968
currentRange = currentRange || "day";
6069
} else if (type === "subscribed") {
6170
currentSort = currentSort || "alphabetical";
6271
}
6372

64-
return { currentSort, currentRange };
73+
return { currentSort, currentRange, currentType };
6574
}

src/app/podcasts/PodcastsHeader.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ import FilterDropdown from "../../components/FilterDropdown/FilterDropdown";
1414
import Header from "../../components/Header/Header";
1515
import { usePodcastsContext } from "./PodcastsContext";
1616
import { getDropdownConfig } from "./PodcastsDropdownConfig";
17+
import { useRouter } from "next/navigation";
1718

1819
const PodcastsHeader: React.FC = () => {
1920
const { queryParams, setQueryParams } = usePodcastsContext();
20-
const { type, sort, range } = queryParams;
21+
const { type, sort, range, category } = queryParams;
2122
const tMedia = useTranslations('media');
2223
const tFilters = useTranslations('filters');
2324
const { typeMenuItems, sortMenuItems, rangeMenuItems, showRangeDropdown
24-
} = getDropdownConfig({ type, sort, tFilters });
25+
} = getDropdownConfig({ type, sort, category, tFilters });
26+
27+
const router = useRouter();
2528

2629
function isChannelType(val: string): val is QueryParamsChannelsType {
2730
return QUERY_PARAMS_CHANNELS_TYPE_VALUES.includes(val as QueryParamsChannelsType);
@@ -43,10 +46,12 @@ const PodcastsHeader: React.FC = () => {
4346
menuItems={typeMenuItems}
4447
onChange={value => {
4548
if (isChannelType(value)) {
46-
if (value === "all" || value === "category") {
47-
setQueryParams({ ...queryParams, type: value, sort: "top", page: 1 });
49+
if (value === "all") {
50+
setQueryParams({ ...queryParams, type: value, sort: "top", page: 1, category: undefined });
51+
} else if (value === "category") {
52+
router.push("/podcasts/categories");
4853
} else {
49-
setQueryParams({ ...queryParams, type: value, sort: "alphabetical", page: 1 });
54+
setQueryParams({ ...queryParams, type: value, sort: "alphabetical", page: 1, category: undefined });
5055
}
5156
}
5257
}}

src/app/podcasts/PodcastsList.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import LoadingSpinnerOverlay from "../../components/LoadingSpinner/LoadingSpinne
55

66
const PodcastsList: React.FC = () => {
77
const { queryParams, setQueryParams, channels, totalPages, isLoading, showSubscribeMessage } = usePodcastsContext();
8-
const { page = 1 } = queryParams;
8+
const { page = 1, type, category } = queryParams;
99

1010
return (
1111
<>
@@ -15,6 +15,8 @@ const PodcastsList: React.FC = () => {
1515
channels={channels}
1616
totalPages={totalPages}
1717
showSubscribeMessage={showSubscribeMessage}
18+
type={type}
19+
category={category}
1820
/>
1921
<LoadingSpinnerOverlay isLoading={isLoading} />
2022
</>

src/app/podcasts/categories/page.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import CategoriesClient from "../../../clients/CategoriesClient";
2+
3+
export default async function PodcastsCategoriesPage() {
4+
return (
5+
<CategoriesClient
6+
titleKey="podcast.podcasts"
7+
linkPath="/podcasts" />
8+
);
9+
}

src/app/podcasts/page.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { CATEGORY_MAPPING_KEYS, QUERY_PARAMS_STATS_RANGE_VALUES, QUERY_PARAMS_CHANNELS_SORT_VALUES,
2-
QUERY_PARAMS_CHANNELS_TYPE_VALUES, getTotalPages, QueryParamsChannelsType,
3-
QueryParamsChannelsSort, QueryParamsStatsRange } from "podverse-helpers";
2+
QUERY_PARAMS_CHANNELS_TYPE_VALUES, getTotalPages } from "podverse-helpers";
43
import { z } from "zod";
5-
import { getCurrentSortAndRange } from "./PodcastsDropdownConfig";
4+
import { getChannelQueryParams } from "./PodcastsDropdownConfig";
65
import PodcastsClient from "./PodcastsClient";
76
import { getSSRAuthService } from "../../utils/auth/ssrAuth";
87

@@ -18,27 +17,24 @@ export type PodcastPageProps = z.infer<typeof searchParamsSchema>;
1817

1918
export default async function Podcasts({ searchParams }: { searchParams?: Promise<PodcastPageProps> }) {
2019
const { isValidAuthSession, apiRequestService } = await getSSRAuthService();
21-
22-
const defaultValueType: QueryParamsChannelsType = isValidAuthSession ? "subscribed" : "all";
23-
const defaultValueSort: QueryParamsChannelsSort = isValidAuthSession ? "alphabetical" : "top";
24-
const defaultValueRange: QueryParamsStatsRange = "day";
25-
20+
2621
const params = searchParams ? await searchParams : {};
27-
const { page = 1, sort = defaultValueSort, type = defaultValueType, range = defaultValueRange,
28-
category } = await parseSearchParams(params, isValidAuthSession);
22+
const { page = 1, sort, type, range, category } = await parseSearchParams(params, isValidAuthSession);
2923

30-
const { currentSort, currentRange } = getCurrentSortAndRange({ type, sort, range });
24+
const { currentType, currentSort, currentRange } = getChannelQueryParams({ type, sort, range, category });
3125

26+
3227
const response = await apiRequestService.reqChannelGetMany({
3328
page,
3429
sort: currentSort,
35-
type,
36-
range: currentRange
30+
type: currentType,
31+
range: currentRange,
32+
category
3733
});
3834

3935
const ssrChannels = response.data;
4036
const ssrTotalPages = getTotalPages(response.meta.count, response.meta.limit);
41-
37+
4238
return (
4339
<PodcastsClient
4440
initialQueryParams={{ page, type, sort, range, category }}
@@ -54,8 +50,15 @@ async function parseSearchParams(params: PodcastPageProps, isAuthenticated: bool
5450
return {};
5551
}
5652
const data = parsed.data;
57-
if (!data.type) {
53+
54+
if (data.category) {
55+
data.type = "category";
56+
data.sort = "top";
57+
data.range = "day";
58+
} else if (!data.type) {
5859
data.type = isAuthenticated ? "subscribed" : "all";
60+
data.sort = isAuthenticated ? "alphabetical" : "top";
61+
data.range = "day";
5962
}
6063
return data;
6164
}

0 commit comments

Comments
 (0)