diff --git a/packages/lib/hooks/useRouterQuery.ts b/packages/lib/hooks/useRouterQuery.ts index 587bd8083e..5a923f284d 100644 --- a/packages/lib/hooks/useRouterQuery.ts +++ b/packages/lib/hooks/useRouterQuery.ts @@ -3,8 +3,13 @@ import { useSearchParams } from "next/navigation"; /** * An alternative to Object.fromEntries that allows duplicate keys. */ -function fromEntriesWithDuplicateKeys(entries: ReturnType["entries"]>) { +function fromEntriesWithDuplicateKeys(entries: IterableIterator<[string, string]> | null) { const result: Record = {}; + + if (entries === null) { + return result; + } + // Consider setting atleast ES2015 as target // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -31,6 +36,6 @@ function fromEntriesWithDuplicateKeys(entries: ReturnType { const searchParams = useSearchParams(); - const routerQuery = fromEntriesWithDuplicateKeys(searchParams.entries()); + const routerQuery = fromEntriesWithDuplicateKeys(searchParams?.entries() ?? null); return routerQuery; }; diff --git a/packages/lib/hooks/useTypedQuery.ts b/packages/lib/hooks/useTypedQuery.ts index ab42038580..7fb61414d0 100644 --- a/packages/lib/hooks/useTypedQuery.ts +++ b/packages/lib/hooks/useTypedQuery.ts @@ -96,7 +96,9 @@ export function useTypedQuery(schema: T) { // Remove all query params from the URL function removeAllQueryParams() { - router.replace(pathname); + if (pathname !== null) { + router.replace(pathname); + } } return { diff --git a/packages/lib/next-seo.config.ts b/packages/lib/next-seo.config.ts index 78442c38df..edff0d59f4 100644 --- a/packages/lib/next-seo.config.ts +++ b/packages/lib/next-seo.config.ts @@ -47,6 +47,12 @@ export const seoConfig: { * @param path NextJS' useRouter().asPath * @returns */ -export const buildCanonical = ({ origin, path }: { origin: Location["origin"]; path: Router["asPath"] }) => { +export const buildCanonical = ({ + origin, + path, +}: { + origin: Location["origin"]; + path: Router["asPath"] | null; +}) => { return `${origin}${path === "/" ? "" : path}`.split("?")[0]; }; diff --git a/packages/ui/components/apps/AllApps.tsx b/packages/ui/components/apps/AllApps.tsx index ce3b821913..4a906b1e87 100644 --- a/packages/ui/components/apps/AllApps.tsx +++ b/packages/ui/components/apps/AllApps.tsx @@ -95,7 +95,9 @@ function CategoryTab({ selectedCategory, categories, searchText }: CategoryTabPr ref={ref}>
  • { - router.replace(pathname); + if (pathname !== null) { + router.replace(pathname); + } }} className={classNames( selectedCategory === null ? "bg-emphasis text-default" : "bg-muted text-emphasis", @@ -108,9 +110,11 @@ function CategoryTab({ selectedCategory, categories, searchText }: CategoryTabPr key={pos} onClick={() => { if (selectedCategory === cat) { - router.replace(pathname); + if (pathname !== null) { + router.replace(pathname); + } } else { - const _searchParams = new URLSearchParams(searchParams); + const _searchParams = new URLSearchParams(searchParams ?? undefined); _searchParams.set("category", cat); router.replace(`${pathname}?${_searchParams.toString()}`); } diff --git a/packages/ui/components/apps/AppCard.tsx b/packages/ui/components/apps/AppCard.tsx index bd03245ba0..4d55813e59 100644 --- a/packages/ui/components/apps/AppCard.tsx +++ b/packages/ui/components/apps/AppCard.tsx @@ -190,7 +190,9 @@ const InstallAppButtonChild = ({ const mutation = useAddAppMutation(null, { onSuccess: (data) => { // Refresh SSR page content without actual reload - router.replace(pathname); + if (pathname !== null) { + router.replace(pathname); + } if (data?.setupPending) return; showToast(t("app_successfully_installed"), "success"); }, diff --git a/packages/ui/components/breadcrumb/Breadcrumb.tsx b/packages/ui/components/breadcrumb/Breadcrumb.tsx index 7792657c90..d7c9f9d1d4 100644 --- a/packages/ui/components/breadcrumb/Breadcrumb.tsx +++ b/packages/ui/components/breadcrumb/Breadcrumb.tsx @@ -50,7 +50,7 @@ export const BreadcrumbContainer = () => { useEffect(() => { const rawPath = pathname; // Pathname doesn't include search params anymore - let pathArray = rawPath.split("/"); + let pathArray = rawPath?.split("/") ?? []; pathArray.shift(); pathArray = pathArray.filter((path) => path !== ""); diff --git a/packages/ui/components/createButton/CreateButton.tsx b/packages/ui/components/createButton/CreateButton.tsx index 9d8b70d067..f42b4225e9 100644 --- a/packages/ui/components/createButton/CreateButton.tsx +++ b/packages/ui/components/createButton/CreateButton.tsx @@ -60,7 +60,7 @@ export function CreateButton(props: CreateBtnProps) { // inject selection data into url for correct router history const openModal = (option: Option) => { - const _searchParams = new URLSearchParams(searchParams); + const _searchParams = new URLSearchParams(searchParams ?? undefined); function setParamsIfDefined(key: string, value: string | number | boolean | null | undefined) { if (value !== undefined && value !== null) _searchParams.set(key, value.toString()); } @@ -136,7 +136,7 @@ export function CreateButton(props: CreateBtnProps) { )} - {searchParams.get("dialog") === "new" && CreateDialog} + {searchParams?.get("dialog") === "new" && CreateDialog} ); } diff --git a/packages/ui/components/dialog/Dialog.tsx b/packages/ui/components/dialog/Dialog.tsx index e78b08db9b..7565c0524c 100644 --- a/packages/ui/components/dialog/Dialog.tsx +++ b/packages/ui/components/dialog/Dialog.tsx @@ -28,7 +28,7 @@ export function Dialog(props: DialogProps) { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); - const newSearchParams = new URLSearchParams(searchParams); + const newSearchParams = new URLSearchParams(searchParams ?? undefined); const { children, name, ...dialogProps } = props; // only used if name is set