chore: [app dir bootstrapping 4] check nullability of navigation hook return values (#12005)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
@@ -26,9 +26,6 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function CancelBooking(props: Props) {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const asPath = `${pathname}?${searchParams.toString()}`;
|
||||
const [cancellationReason, setCancellationReason] = useState<string>("");
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
@@ -44,6 +41,7 @@ export default function CancelBooking(props: Props) {
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{error && (
|
||||
@@ -100,7 +98,8 @@ export default function CancelBooking(props: Props) {
|
||||
});
|
||||
|
||||
if (res.status >= 200 && res.status < 300) {
|
||||
router.replace(asPath);
|
||||
// tested by apps/web/playwright/booking-pages.e2e.ts
|
||||
router.refresh();
|
||||
} else {
|
||||
setLoading(false);
|
||||
setError(
|
||||
|
||||
@@ -222,9 +222,9 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
||||
onChange={(event) => {
|
||||
event.preventDefault();
|
||||
// Reset payment status
|
||||
const _searchParams = new URLSearchParams(searchParams);
|
||||
const _searchParams = new URLSearchParams(searchParams ?? undefined);
|
||||
_searchParams.delete("paymentStatus");
|
||||
if (searchParams.toString() !== _searchParams.toString()) {
|
||||
if (searchParams?.toString() !== _searchParams.toString()) {
|
||||
router.replace(`${pathname}?${_searchParams.toString()}`);
|
||||
}
|
||||
setInputUsernameValue(event.target.value);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
|
||||
export default function useIsBookingPage() {
|
||||
export default function useIsBookingPage(): boolean {
|
||||
const pathname = usePathname();
|
||||
const isBookingPage = ["/booking/", "/cancel", "/reschedule"].some((route) => pathname?.startsWith(route));
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const userParam = searchParams.get("user");
|
||||
const teamParam = searchParams.get("team");
|
||||
const userParam = Boolean(searchParams?.get("user"));
|
||||
const teamParam = Boolean(searchParams?.get("team"));
|
||||
|
||||
return !!(isBookingPage || userParam || teamParam);
|
||||
return isBookingPage || userParam || teamParam;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export default function useRouterQuery<T extends string>(name: T) {
|
||||
const searchParams = useSearchParams();
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
|
||||
const setQuery = (newValue: string | number | null | undefined) => {
|
||||
const _searchParams = new URLSearchParams(searchParams);
|
||||
_searchParams.set(name, newValue as string);
|
||||
router.replace(`${pathname}?${_searchParams.toString()}`);
|
||||
};
|
||||
const setQuery = useCallback(
|
||||
(newValue: string | number | null | undefined) => {
|
||||
const _searchParams = new URLSearchParams(searchParams ?? undefined);
|
||||
_searchParams.set(name, newValue as string);
|
||||
router.replace(`${pathname}?${_searchParams.toString()}`);
|
||||
},
|
||||
[name, pathname, router, searchParams]
|
||||
);
|
||||
|
||||
return { [name]: searchParams.get(name), setQuery } as {
|
||||
return { [name]: searchParams?.get(name), setQuery } as {
|
||||
[K in T]: string | undefined;
|
||||
} & { setQuery: typeof setQuery };
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ export default function Custom404() {
|
||||
const [url, setUrl] = useState(`${WEBSITE_URL}/signup`);
|
||||
useEffect(() => {
|
||||
const { isValidOrgDomain, currentOrgDomain } = orgDomainConfig(window.location.host);
|
||||
const [routerUsername] = pathname?.replace("%20", "-").split(/[?#]/);
|
||||
if (!isValidOrgDomain || !currentOrgDomain) {
|
||||
const [routerUsername] = pathname?.replace("%20", "-").split(/[?#]/) ?? [];
|
||||
if (routerUsername && (!isValidOrgDomain || !currentOrgDomain)) {
|
||||
const splitPath = routerUsername.split("/");
|
||||
if (splitPath[1] === "team" && splitPath.length === 3) {
|
||||
// Accessing a non-existent team
|
||||
@@ -66,13 +66,12 @@ export default function Custom404() {
|
||||
setUrl(`${WEBSITE_URL}/signup?username=${routerUsername.replace("/", "")}`);
|
||||
}
|
||||
} else {
|
||||
setUsername(currentOrgDomain);
|
||||
setUsername(currentOrgDomain ?? "");
|
||||
setCurrentPageType(pageType.ORG);
|
||||
setUrl(
|
||||
`${WEBSITE_URL}/signup?callbackUrl=settings/organizations/new%3Fslug%3D${currentOrgDomain.replace(
|
||||
"/",
|
||||
""
|
||||
)}`
|
||||
`${WEBSITE_URL}/signup?callbackUrl=settings/organizations/new%3Fslug%3D${
|
||||
currentOrgDomain?.replace("/", "") ?? ""
|
||||
}`
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
@@ -83,7 +83,7 @@ inferSSRProps<typeof _getServerSideProps> & WithNonceProps<{}>) {
|
||||
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
let callbackUrl = searchParams.get("callbackUrl") || "";
|
||||
let callbackUrl = searchParams?.get("callbackUrl") || "";
|
||||
|
||||
if (/"\//.test(callbackUrl)) callbackUrl = callbackUrl.substring(1);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function Authorize() {
|
||||
const state = searchParams?.get("state") as string;
|
||||
const scope = searchParams?.get("scope") as string;
|
||||
|
||||
const queryString = searchParams.toString();
|
||||
const queryString = searchParams?.toString();
|
||||
|
||||
const [selectedAccount, setSelectedAccount] = useState<{ value: string; label: string } | null>();
|
||||
const scopes = scope ? scope.toString().split(",") : [];
|
||||
|
||||
@@ -24,7 +24,7 @@ function useSetStep() {
|
||||
const searchParams = useSearchParams();
|
||||
const pathname = usePathname();
|
||||
const setStep = (newStep = 1) => {
|
||||
const _searchParams = new URLSearchParams(searchParams);
|
||||
const _searchParams = new URLSearchParams(searchParams ?? undefined);
|
||||
_searchParams.set("step", newStep.toString());
|
||||
router.replace(`${pathname}?${_searchParams.toString()}`);
|
||||
};
|
||||
|
||||
@@ -164,7 +164,7 @@ export default function Verify() {
|
||||
e.preventDefault();
|
||||
setSecondsLeft(30);
|
||||
// Update query params with t:timestamp, shallow: true doesn't re-render the page
|
||||
const _searchParams = new URLSearchParams(searchParams.toString());
|
||||
const _searchParams = new URLSearchParams(searchParams?.toString());
|
||||
_searchParams.set("t", `${Date.now()}`);
|
||||
router.replace(`${pathname}?${_searchParams.toString()}`);
|
||||
return await sendVerificationLogin(customer.email, customer.username);
|
||||
|
||||
@@ -155,7 +155,7 @@ export default function Success(props: SuccessProps) {
|
||||
const [calculatedDuration, setCalculatedDuration] = useState<number | undefined>(undefined);
|
||||
const { requiresLoginToUpdate } = props;
|
||||
function setIsCancellationMode(value: boolean) {
|
||||
const _searchParams = new URLSearchParams(searchParams);
|
||||
const _searchParams = new URLSearchParams(searchParams ?? undefined);
|
||||
|
||||
if (value) {
|
||||
_searchParams.set("cancel", "true");
|
||||
|
||||
@@ -298,7 +298,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
|
||||
// inject selection data into url for correct router history
|
||||
const openDuplicateModal = (eventType: EventType, group: EventTypeGroup) => {
|
||||
const newSearchParams = new URLSearchParams(searchParams);
|
||||
const newSearchParams = new URLSearchParams(searchParams ?? undefined);
|
||||
function setParamsIfDefined(key: string, value: string | number | boolean | null | undefined) {
|
||||
if (value) newSearchParams.set(key, value.toString());
|
||||
if (value === null) newSearchParams.delete(key);
|
||||
|
||||
@@ -134,7 +134,15 @@ function PaymentChecker(props: PaymentCheckerProps) {
|
||||
const bookingSuccessRedirect = useBookingSuccessRedirect();
|
||||
const utils = trpc.useContext();
|
||||
const { t } = useLocale();
|
||||
|
||||
useEffect(() => {
|
||||
if (searchParams === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// use closure to ensure non-nullability
|
||||
const sp = searchParams;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
(async () => {
|
||||
if (props.booking.status === "ACCEPTED") {
|
||||
@@ -153,7 +161,7 @@ function PaymentChecker(props: PaymentCheckerProps) {
|
||||
location: string;
|
||||
} = {
|
||||
uid: props.booking.uid,
|
||||
email: searchParams.get("email"),
|
||||
email: sp.get("email"),
|
||||
location: t("web_conferencing_details_to_follow"),
|
||||
};
|
||||
|
||||
@@ -165,6 +173,7 @@ function PaymentChecker(props: PaymentCheckerProps) {
|
||||
}
|
||||
})();
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [
|
||||
bookingSuccessRedirect,
|
||||
@@ -178,5 +187,6 @@ function PaymentChecker(props: PaymentCheckerProps) {
|
||||
t,
|
||||
utils.viewer.bookings,
|
||||
]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -30,15 +30,20 @@ export default function AlbySetup(props: IAlbySetupProps) {
|
||||
|
||||
function AlbySetupCallback() {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const params = useSearchParams();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchParams) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.opener) {
|
||||
setError("Something went wrong. Opener not available. Please contact support@getalby.com");
|
||||
return;
|
||||
}
|
||||
|
||||
const code = params.get("code");
|
||||
const error = params.get("error");
|
||||
const code = searchParams?.get("code");
|
||||
const error = searchParams?.get("error");
|
||||
|
||||
if (!code) {
|
||||
setError("declined");
|
||||
@@ -54,7 +59,7 @@ function AlbySetupCallback() {
|
||||
payload: { code },
|
||||
});
|
||||
window.close();
|
||||
}, []);
|
||||
}, [searchParams]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -48,7 +48,7 @@ export const useOpenModal = () => {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const openModal = (option: z.infer<typeof newFormModalQuerySchema>) => {
|
||||
const newQuery = new URLSearchParams(searchParams);
|
||||
const newQuery = new URLSearchParams(searchParams ?? undefined);
|
||||
newQuery.set("dialog", "new-form");
|
||||
Object.keys(option).forEach((key) => {
|
||||
newQuery.set(key, option[key as keyof typeof option] || "");
|
||||
|
||||
@@ -301,7 +301,7 @@ const usePrefilledResponse = (form: Props["form"]) => {
|
||||
|
||||
// Prefill the form from query params
|
||||
form.fields?.forEach((field) => {
|
||||
const valuesFromQuery = searchParams?.getAll(getFieldIdentifier(field)).filter(Boolean);
|
||||
const valuesFromQuery = searchParams?.getAll(getFieldIdentifier(field)).filter(Boolean) ?? [];
|
||||
// We only want to keep arrays if the field is a multi-select
|
||||
const value = valuesFromQuery.length > 1 ? valuesFromQuery : valuesFromQuery[0];
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ interface EditModalState extends Pick<App, "keys"> {
|
||||
const AdminAppsListContainer = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const { t } = useLocale();
|
||||
const category = searchParams.get("category") || AppCategories.calendar;
|
||||
const category = searchParams?.get("category") || AppCategories.calendar;
|
||||
|
||||
const { data: apps, isLoading } = trpc.viewer.appsRouter.listLocal.useQuery(
|
||||
{ category },
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ function OverlayCalendarSwitch({ enabled }: OverlayCalendarSwitchProps) {
|
||||
// Toggle query param for overlay calendar
|
||||
const toggleOverlayCalendarQueryParam = useCallback(
|
||||
(state: boolean) => {
|
||||
const current = new URLSearchParams(Array.from(searchParams.entries()));
|
||||
const current = new URLSearchParams(Array.from(searchParams?.entries() ?? []));
|
||||
if (state) {
|
||||
current.set("overlayCalendar", "true");
|
||||
localStorage.setItem("overlayCalendarSwitchDefault", "true");
|
||||
@@ -121,7 +121,7 @@ export function OverlayCalendarContainer() {
|
||||
const { data: session, status: sessionStatus } = useSession();
|
||||
const setOverlayBusyDates = useOverlayCalendarStore((state) => state.setOverlayBusyDates);
|
||||
const switchEnabled =
|
||||
searchParams.get("overlayCalendar") === "true" ||
|
||||
searchParams?.get("overlayCalendar") === "true" ||
|
||||
localStorage.getItem("overlayCalendarSwitchDefault") === "true";
|
||||
|
||||
const selectedDate = useBookerStore((state) => state.selectedDate);
|
||||
|
||||
@@ -62,7 +62,7 @@ export const useScheduleForEvent = ({
|
||||
shallow
|
||||
);
|
||||
const searchParams = useSearchParams();
|
||||
const rescheduleUid = searchParams.get("rescheduleUid");
|
||||
const rescheduleUid = searchParams?.get("rescheduleUid");
|
||||
|
||||
const pathname = usePathname();
|
||||
|
||||
@@ -78,6 +78,6 @@ export const useScheduleForEvent = ({
|
||||
rescheduleUid,
|
||||
month: monthFromStore ?? month,
|
||||
duration: durationFromStore ?? duration,
|
||||
isTeamEvent: pathname.indexOf("/team/") !== -1 || isTeam,
|
||||
isTeamEvent: pathname?.indexOf("/team/") !== -1 || isTeam,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ export const EventMembers = ({ schedulingType, users, profile, entity }: EventMe
|
||||
image: "logo" in profile && profile.logo ? `${profile.logo}` : undefined,
|
||||
alt: profile.name || undefined,
|
||||
href: profile.username
|
||||
? `${CAL_URL}${pathname.indexOf("/team/") !== -1 ? "/team" : ""}/${profile.username}`
|
||||
? `${CAL_URL}${pathname?.indexOf("/team/") !== -1 ? "/team" : ""}/${profile.username}`
|
||||
: undefined,
|
||||
});
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ const MembersView = () => {
|
||||
const { t, i18n } = useLocale();
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const teamId = Number(searchParams.get("id"));
|
||||
const teamId = Number(searchParams?.get("id"));
|
||||
const session = useSession();
|
||||
const utils = trpc.useContext();
|
||||
const [offset, setOffset] = useState<number>(1);
|
||||
@@ -74,6 +74,7 @@ const MembersView = () => {
|
||||
const { data: team, isLoading: isTeamLoading } = trpc.viewer.organizations.getOtherTeam.useQuery(
|
||||
{ teamId },
|
||||
{
|
||||
enabled: !Number.isNaN(teamId),
|
||||
onError: () => {
|
||||
router.push("/settings");
|
||||
},
|
||||
@@ -86,13 +87,14 @@ const MembersView = () => {
|
||||
distinctUser: true,
|
||||
},
|
||||
{
|
||||
enabled: searchParams !== null,
|
||||
enabled: !Number.isNaN(teamId),
|
||||
}
|
||||
);
|
||||
const { data: membersFetch, isLoading: isLoadingMembers } =
|
||||
trpc.viewer.organizations.listOtherTeamMembers.useQuery(
|
||||
{ teamId, limit, offset: (offset - 1) * limit },
|
||||
{
|
||||
enabled: !Number.isNaN(teamId),
|
||||
onError: () => {
|
||||
router.push("/settings");
|
||||
},
|
||||
@@ -101,12 +103,8 @@ const MembersView = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (membersFetch) {
|
||||
if (membersFetch.length < limit) {
|
||||
setLoadMore(false);
|
||||
} else {
|
||||
setLoadMore(true);
|
||||
}
|
||||
setMembers(members.concat(membersFetch));
|
||||
setLoadMore(membersFetch.length >= limit);
|
||||
setMembers((m) => m.concat(membersFetch));
|
||||
}
|
||||
}, [membersFetch]);
|
||||
|
||||
|
||||
@@ -77,11 +77,11 @@ const OtherTeamProfileView = () => {
|
||||
resolver: zodResolver(teamProfileFormSchema),
|
||||
});
|
||||
const searchParams = useSearchParams();
|
||||
const teamId = Number(searchParams.get("id"));
|
||||
const teamId = Number(searchParams?.get("id"));
|
||||
const { data: team, isLoading } = trpc.viewer.organizations.getOtherTeam.useQuery(
|
||||
{ teamId: teamId },
|
||||
{
|
||||
enabled: !!teamId,
|
||||
enabled: !Number.isNaN(teamId),
|
||||
onError: () => {
|
||||
router.push("/settings");
|
||||
},
|
||||
|
||||
@@ -81,12 +81,17 @@ const PaymentForm = (props: Props) => {
|
||||
const handleSubmit = async (ev: SyntheticEvent) => {
|
||||
ev.preventDefault();
|
||||
|
||||
if (!stripe || !elements) return;
|
||||
if (!stripe || !elements || searchParams === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState({ status: "processing" });
|
||||
|
||||
let payload;
|
||||
const params: {
|
||||
[k: string]: any;
|
||||
uid: string;
|
||||
email: string | null;
|
||||
location?: string;
|
||||
} = {
|
||||
uid: props.booking.uid,
|
||||
email: searchParams.get("email"),
|
||||
|
||||
@@ -17,7 +17,10 @@ const UsersAddView = () => {
|
||||
onSuccess: async () => {
|
||||
showToast("User added successfully", "success");
|
||||
await utils.viewer.users.list.invalidate();
|
||||
router.replace(pathname?.replace("/add", ""));
|
||||
|
||||
if (pathname !== null) {
|
||||
router.replace(pathname.replace("/add", ""));
|
||||
}
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error(err.message);
|
||||
|
||||
@@ -520,18 +520,19 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
(state) => [state.month, state.selectedDatesAndTimes],
|
||||
shallow
|
||||
);
|
||||
const eventId = searchParams.get("eventId");
|
||||
const eventId = searchParams?.get("eventId");
|
||||
const parsedEventId = parseInt(eventId ?? "", 10);
|
||||
const calLink = decodeURIComponent(embedUrl);
|
||||
const { data: eventTypeData } = trpc.viewer.eventTypes.get.useQuery(
|
||||
{ id: parseInt(eventId as string) },
|
||||
{ enabled: !!eventId && embedType === "email", refetchOnWindowFocus: false }
|
||||
{ id: parsedEventId },
|
||||
{ enabled: !Number.isNaN(parsedEventId) && embedType === "email", refetchOnWindowFocus: false }
|
||||
);
|
||||
|
||||
const s = (href: string) => {
|
||||
const _searchParams = new URLSearchParams(searchParams);
|
||||
const [a, b] = href.split("=");
|
||||
_searchParams.set(a, b);
|
||||
return `${pathname?.split("?")[0]}?${_searchParams.toString()}`;
|
||||
return `${pathname?.split("?")[0] ?? ""}?${_searchParams.toString()}`;
|
||||
};
|
||||
const parsedTabs = tabs.map((t) => ({ ...t, href: s(t.href) }));
|
||||
const embedCodeRefs: Record<(typeof tabs)[0]["name"], RefObject<HTMLTextAreaElement>> = {};
|
||||
|
||||
@@ -8,21 +8,22 @@ import { trpc } from "@calcom/trpc";
|
||||
import type { FilterContextType } from "./provider";
|
||||
import { FilterProvider } from "./provider";
|
||||
|
||||
const querySchema = z.object({
|
||||
startTime: z.string().nullable(),
|
||||
endTime: z.string().nullable(),
|
||||
teamId: z.coerce.number().nullable(),
|
||||
userId: z.coerce.number().nullable(),
|
||||
memberUserId: z.coerce.number().nullable(),
|
||||
eventTypeId: z.coerce.number().nullable(),
|
||||
filter: z.enum(["event-type", "user"]).nullable(),
|
||||
});
|
||||
|
||||
export function FiltersProvider({ children }: { children: React.ReactNode }) {
|
||||
// searchParams to get initial values from query params
|
||||
const utils = trpc.useContext();
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const querySchema = z.object({
|
||||
startTime: z.string().nullable(),
|
||||
endTime: z.string().nullable(),
|
||||
teamId: z.coerce.number().nullable(),
|
||||
userId: z.coerce.number().nullable(),
|
||||
memberUserId: z.coerce.number().nullable(),
|
||||
eventTypeId: z.coerce.number().nullable(),
|
||||
filter: z.enum(["event-type", "user"]).nullable(),
|
||||
});
|
||||
|
||||
let startTimeParsed,
|
||||
endTimeParsed,
|
||||
@@ -33,13 +34,13 @@ export function FiltersProvider({ children }: { children: React.ReactNode }) {
|
||||
memberUserIdParsed;
|
||||
|
||||
const safe = querySchema.safeParse({
|
||||
startTime: searchParams.get("startTime"),
|
||||
endTime: searchParams.get("endTime"),
|
||||
teamId: searchParams.get("teamId"),
|
||||
userId: searchParams.get("userId"),
|
||||
eventTypeId: searchParams.get("eventTypeId"),
|
||||
filter: searchParams.get("filter"),
|
||||
memberUserId: searchParams.get("memberUserId"),
|
||||
startTime: searchParams?.get("startTime") ?? null,
|
||||
endTime: searchParams?.get("endTime") ?? null,
|
||||
teamId: searchParams?.get("teamId") ?? null,
|
||||
userId: searchParams?.get("userId") ?? null,
|
||||
eventTypeId: searchParams?.get("eventTypeId") ?? null,
|
||||
filter: searchParams?.get("filter") ?? null,
|
||||
memberUserId: searchParams?.get("memberUserId") ?? null,
|
||||
});
|
||||
|
||||
if (!safe.success) {
|
||||
@@ -119,7 +120,7 @@ export function FiltersProvider({ children }: { children: React.ReactNode }) {
|
||||
initialConfig,
|
||||
} = newConfigFilters;
|
||||
const [startTime, endTime] = dateRange || [null, null];
|
||||
const newSearchParams = new URLSearchParams(searchParams.toString());
|
||||
const newSearchParams = new URLSearchParams(searchParams?.toString() ?? undefined);
|
||||
function setParamsIfDefined(key: string, value: string | number | boolean | null | undefined) {
|
||||
if (value !== undefined && value !== null) newSearchParams.set(key, value.toString());
|
||||
}
|
||||
|
||||
@@ -509,7 +509,7 @@ export type NavigationItemType = {
|
||||
}: {
|
||||
item: Pick<NavigationItemType, "href">;
|
||||
isChild?: boolean;
|
||||
pathname: string;
|
||||
pathname: string | null;
|
||||
}) => boolean;
|
||||
};
|
||||
|
||||
@@ -527,7 +527,7 @@ const navigation: NavigationItemType[] = [
|
||||
href: "/bookings/upcoming",
|
||||
icon: Calendar,
|
||||
badge: <UnconfirmedBookingBadge />,
|
||||
isCurrent: ({ pathname }) => pathname?.startsWith("/bookings"),
|
||||
isCurrent: ({ pathname }) => pathname?.startsWith("/bookings") ?? false,
|
||||
},
|
||||
{
|
||||
name: "availability",
|
||||
@@ -547,7 +547,7 @@ const navigation: NavigationItemType[] = [
|
||||
icon: Grid,
|
||||
isCurrent: ({ pathname: path, item }) => {
|
||||
// During Server rendering path is /v2/apps but on client it becomes /apps(weird..)
|
||||
return path?.startsWith(item.href) && !path?.includes("routing-forms/");
|
||||
return (path?.startsWith(item.href) ?? false) && !(path?.includes("routing-forms/") ?? false);
|
||||
},
|
||||
child: [
|
||||
{
|
||||
@@ -556,7 +556,9 @@ const navigation: NavigationItemType[] = [
|
||||
isCurrent: ({ pathname: path, item }) => {
|
||||
// During Server rendering path is /v2/apps but on client it becomes /apps(weird..)
|
||||
return (
|
||||
path?.startsWith(item.href) && !path?.includes("routing-forms/") && !path?.includes("/installed")
|
||||
(path?.startsWith(item.href) ?? false) &&
|
||||
!(path?.includes("routing-forms/") ?? false) &&
|
||||
!(path?.includes("/installed") ?? false)
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -564,7 +566,8 @@ const navigation: NavigationItemType[] = [
|
||||
name: "installed_apps",
|
||||
href: "/apps/installed/calendar",
|
||||
isCurrent: ({ pathname: path }) =>
|
||||
path?.startsWith("/apps/installed/") || path?.startsWith("/v2/apps/installed/"),
|
||||
(path?.startsWith("/apps/installed/") ?? false) ||
|
||||
(path?.startsWith("/v2/apps/installed/") ?? false),
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -577,7 +580,7 @@ const navigation: NavigationItemType[] = [
|
||||
name: "Routing Forms",
|
||||
href: "/apps/routing-forms/forms",
|
||||
icon: FileText,
|
||||
isCurrent: ({ pathname }) => pathname?.startsWith("/apps/routing-forms/"),
|
||||
isCurrent: ({ pathname }) => pathname?.startsWith("/apps/routing-forms/") ?? false,
|
||||
},
|
||||
{
|
||||
name: "workflows",
|
||||
@@ -631,7 +634,7 @@ function useShouldDisplayNavigationItem(item: NavigationItemType) {
|
||||
}
|
||||
|
||||
const defaultIsCurrent: NavigationItemType["isCurrent"] = ({ isChild, item, pathname }) => {
|
||||
return isChild ? item.href === pathname : item.href ? pathname?.startsWith(item.href) : false;
|
||||
return isChild ? item.href === pathname : item.href ? pathname?.startsWith(item.href) ?? false : false;
|
||||
};
|
||||
|
||||
const NavigationItem: React.FC<{
|
||||
|
||||
@@ -12,7 +12,7 @@ import { subscriberUrlReserved } from "../lib/subscriberUrlReserved";
|
||||
|
||||
const EditWebhook = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const id = searchParams.get("id");
|
||||
const id = searchParams?.get("id");
|
||||
|
||||
if (!id) return <SkeletonContainer />;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export const useBookingSuccessRedirect = () => {
|
||||
...query,
|
||||
...bookingExtraParams,
|
||||
},
|
||||
searchParams,
|
||||
searchParams: searchParams ?? undefined,
|
||||
});
|
||||
window.parent.location.href = `${url.toString()}?${newSearchParams.toString()}`;
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user