Skip to content

Commit c699824

Browse files
committed
feat: add precondition check before setting query strings
1 parent 62a1acc commit c699824

2 files changed

Lines changed: 43 additions & 6 deletions

File tree

frontend/hooks/useQueryFilter.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { selectFilters, setFilter } from "redux/filtersSlice";
44

55
import { useDispatch, useSelector } from "../redux/hooks";
66
import { Filters } from "../types";
7+
import { filterBarDropdown } from "../utils/constants";
78

89
// Type for the keys of the Filters type
910
const queryFilter: (keyof Filters)[] = [
@@ -14,6 +15,21 @@ const queryFilter: (keyof Filters)[] = [
1415
"id",
1516
];
1617

18+
// Create an object that maps each filter key to its values in an array
19+
const validFilterQueries: Partial<Record<keyof Filters, string[]>> =
20+
Object.fromEntries(
21+
filterBarDropdown.map(({ key, items }) => [
22+
key,
23+
items.map((item) => item.value),
24+
])
25+
);
26+
27+
const isValidFilter = (key: keyof Filters, value: string): boolean => {
28+
const isValid = validFilterQueries[key];
29+
if (isValid === undefined) return false;
30+
return isValid.includes(value);
31+
};
32+
1733
// Function to handle query string parameters for filters in page.tsx (browse page)
1834
const useQueryFilter = () => {
1935
const dispatch = useDispatch();
@@ -27,12 +43,24 @@ const useQueryFilter = () => {
2743

2844
// On initial load, apply filters from query parameters to Redux state
2945
useEffect(() => {
46+
const params = new URLSearchParams(searchParams.toString());
47+
let hasInvalidFilter = false;
48+
3049
queryFilter.forEach((key) => {
3150
const value = searchParams.get(key);
32-
if (value) {
51+
if (value && isValidFilter(key, value)) {
3352
dispatch(setFilter({ key, value }));
53+
} else {
54+
params.delete(key);
55+
hasInvalidFilter = true;
3456
}
3557
});
58+
59+
// Check if need to update URL to remove invalid parameters
60+
if (hasInvalidFilter) {
61+
router.replace(`${pathname}?${params.toString()}`, { scroll: false });
62+
}
63+
3664
// eslint-disable-next-line react-hooks/exhaustive-deps
3765
}, [dispatch]); // Apply filters on initial load (when user shares link with query params), and not on subsequent loads
3866

@@ -47,8 +75,8 @@ const useQueryFilter = () => {
4775
const params = new URLSearchParams(searchParams.toString());
4876
queryFilter.forEach((key) => {
4977
const value = filters[key];
50-
if (value) {
51-
// If the filter value exists, apply to query parameters
78+
if (value && isValidFilter(key, value)) {
79+
// If the filter value exists and is a valid filter key, apply to query parameters
5280
params.set(key, value);
5381
} else {
5482
// Remove the key if the filter value is not in the filter

frontend/hooks/useQuerySort.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { usePathname, useRouter, useSearchParams } from "next/navigation";
22
import { useEffect, useRef, useState } from "react";
33

4+
import { sortBarDropdown } from "../utils/constants";
5+
6+
const validSortQueries: string[] = sortBarDropdown.map((item) => item.value);
7+
8+
const isValidSort = (value: string): boolean => {
9+
return validSortQueries.includes(value);
10+
}
11+
412
// Function to handle query string parameters for sorting in page.tsx (browse page)
513
const useQuerySort = (): [string, (sort: string) => void] => {
614
const router = useRouter();
@@ -9,9 +17,10 @@ const useQuerySort = (): [string, (sort: string) => void] => {
917
const initialLoad = useRef(true);
1018

1119
// On initial load, fallback to alphabetical sort if no sort query parameter provided
12-
const [sort, setSort] = useState<string>(
13-
() => searchParams.get("sort") ?? "alphabetical"
14-
);
20+
const [sort, setSort] = useState<string>(() => {
21+
const value = searchParams.get("sort");
22+
return value && isValidSort(value) ? value : "alphabetical"
23+
});
1524

1625
// Apply sort to URL when sort changes
1726
useEffect(() => {

0 commit comments

Comments
 (0)