From b7851e6e53e794f5ec2301b3c98435cbf694832a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Wed, 2 Aug 2023 02:35:48 -0700 Subject: [PATCH] refactor: next/router hooks with next/navigation hooks (#9105) Co-authored-by: Alex van Andel Co-authored-by: Peer Richelsen Co-authored-by: Bailey Pumfleet Co-authored-by: Peer Richelsen Co-authored-by: Hariom Balhara --- apps/web/components/AppListCard.tsx | 20 +- apps/web/components/AppsShell.tsx | 26 - apps/web/components/BookingsShell.tsx | 31 -- apps/web/components/Embed.tsx | 257 ++++----- apps/web/components/NavTabs.tsx | 99 ---- apps/web/components/SettingsShell.tsx | 60 --- apps/web/components/apps/App.tsx | 491 +----------------- apps/web/components/apps/AppPage.tsx | 367 +++++++++++++ .../components/apps/InstallAppButtonChild.tsx | 124 +++++ .../components/apps/layouts/AppsLayout.tsx | 2 +- .../components/auth/layouts/AdminLayout.tsx | 6 +- .../web/components/booking/AvailableTimes.tsx | 228 -------- .../booking/BookingDescriptionPayment.tsx | 38 -- .../components/booking/BookingListItem.tsx | 21 +- apps/web/components/booking/CancelBooking.tsx | 7 +- apps/web/components/booking/SlotPicker.tsx | 198 ------- apps/web/components/booking/TimeOptions.tsx | 41 -- .../components/booking/TimezoneDropdown.tsx | 26 - apps/web/components/booking/UserAvatars.tsx | 44 -- .../components/eventtype/EventAdvancedTab.tsx | 4 +- .../eventtype/EventTypeSingleLayout.tsx | 4 +- .../steps-views/SetupAvailability.tsx | 5 +- .../steps-views/UserProfile.tsx | 2 +- apps/web/components/setup/StepDone.tsx | 2 +- apps/web/components/team/screens/Team.tsx | 9 +- .../UsernameAvailability/PremiumTextfield.tsx | 16 +- .../ui/UsernameAvailability/index.tsx | 6 +- apps/web/lib/app-providers.tsx | 39 +- apps/web/lib/hooks/usePublicPage.ts | 6 +- apps/web/lib/hooks/useRouterQuery.ts | 33 +- apps/web/lib/hooks/useToggleQuery.tsx | 28 +- apps/web/package.json | 1 - apps/web/pages/404.tsx | 19 +- apps/web/pages/500.tsx | 10 +- apps/web/pages/[user].tsx | 13 +- apps/web/pages/apps/[slug]/[...pages].tsx | 6 +- apps/web/pages/apps/[slug]/setup.tsx | 13 +- apps/web/pages/apps/categories/[category].tsx | 6 +- apps/web/pages/apps/installed/[category].tsx | 7 +- apps/web/pages/auth/error.tsx | 14 +- apps/web/pages/auth/forgot-password/index.tsx | 2 +- apps/web/pages/auth/login.tsx | 7 +- apps/web/pages/auth/logout.tsx | 2 +- apps/web/pages/auth/saml-idp.tsx | 10 +- apps/web/pages/auth/setup/index.tsx | 18 +- apps/web/pages/auth/sso/[provider].tsx | 5 +- apps/web/pages/auth/sso/direct.tsx | 2 +- apps/web/pages/auth/verify-email.tsx | 2 +- apps/web/pages/auth/verify.tsx | 30 +- apps/web/pages/availability/[schedule].tsx | 34 +- apps/web/pages/availability/index.tsx | 2 +- apps/web/pages/booking/[uid].tsx | 33 +- apps/web/pages/bookings/[status].tsx | 8 +- apps/web/pages/event-types/index.tsx | 66 ++- .../web/pages/getting-started/[[...step]].tsx | 17 +- apps/web/pages/settings/billing/index.tsx | 6 +- .../pages/settings/my-account/calendars.tsx | 2 +- .../web/pages/settings/my-account/general.tsx | 11 +- .../settings/organizations/[id]/about.tsx | 6 +- .../settings/organizations/[id]/add-teams.tsx | 9 +- .../organizations/[id]/onboard-admins.tsx | 10 +- .../organizations/[id]/set-password.tsx | 6 +- apps/web/pages/signup.tsx | 16 +- apps/web/pages/team/[slug].tsx | 12 +- apps/web/playwright/event-types.e2e.ts | 2 + .../applecalendar/pages/setup/index.tsx | 2 +- .../caldavcalendar/pages/setup/index.tsx | 2 +- .../app-store/closecom/pages/setup/index.tsx | 2 +- packages/app-store/components.tsx | 2 +- .../pages/setup/index.tsx | 2 +- .../pages/setup/index.tsx | 2 +- .../exchangecalendar/pages/setup/index.tsx | 2 +- .../routing-forms/components/FormActions.tsx | 51 +- .../pages/forms/[...appPages].tsx | 53 +- .../pages/layout-handler/[...appPages].tsx | 14 +- .../pages/routing-link/[...appPages].tsx | 10 +- .../app-store/sendgrid/pages/setup/index.tsx | 2 +- .../components/EventTypeAppCardInterface.tsx | 8 +- .../embeds/embed-core/src/embed-iframe.ts | 40 +- packages/features/apps/AdminAppsList.tsx | 10 +- .../apps/components/DisconnectIntegration.tsx | 8 +- .../BookEventForm/BookEventForm.tsx | 30 +- .../event-meta}/AvailableEventLocations.tsx | 0 .../components/event-meta/Details.tsx | 2 +- .../components/AboutOrganizationForm.tsx | 8 +- .../components/AddNewOrgAdminsForm.tsx | 8 +- .../components/AddNewTeamsForm.tsx | 10 +- .../components/CreateANewOrganizationForm.tsx | 2 +- .../components/OrgUpgradeBanner.tsx | 2 +- .../components/SetPasswordForm.tsx | 8 +- .../pages/settings/appearance.tsx | 2 +- .../organizations/pages/settings/general.tsx | 2 +- .../organizations/pages/settings/profile.tsx | 38 +- .../ee/payments/components/Payment.tsx | 13 +- .../features/ee/sso/page/teams-sso-view.tsx | 9 +- .../features/ee/sso/page/user-sso-view.tsx | 2 +- .../ee/teams/components/AddNewTeamMembers.tsx | 16 +- .../teams/components/CreateANewTeamForm.tsx | 6 +- .../GoogleWorkspaceInviteButton.tsx | 10 +- .../ee/teams/components/TeamListItem.tsx | 8 +- .../ee/teams/components/TeamsListing.tsx | 8 +- .../teams/components/TeamsUpgradeBanner.tsx | 2 +- .../ee/teams/pages/team-appearance-view.tsx | 6 +- .../ee/teams/pages/team-billing-view.tsx | 6 +- .../ee/teams/pages/team-members-view.tsx | 15 +- .../ee/teams/pages/team-profile-view.tsx | 18 +- .../features/ee/users/components/UserForm.tsx | 34 +- .../ee/users/components/UsersTable.tsx | 9 +- .../ee/users/pages/users-add-view.tsx | 5 +- .../ee/users/pages/users-edit-view.tsx | 15 +- .../features/ee/users/server/trpc-router.ts | 3 +- .../ee/workflows/components/EmptyScreen.tsx | 6 +- .../components/EventWorkflowsTab.tsx | 2 +- .../components/WorkflowDetailsPage.tsx | 11 +- .../workflows/components/WorkflowListPage.tsx | 2 +- .../ee/workflows/lib/actionHelperFunctions.ts | 10 +- .../lib/reminders/emailReminderManager.ts | 110 ++-- .../lib/reminders/reminderScheduler.ts | 10 +- .../features/ee/workflows/pages/index.tsx | 13 +- .../features/ee/workflows/pages/workflow.tsx | 26 +- .../components/CreateEventTypeDialog.tsx | 2 +- .../eventtypes/components/DuplicateDialog.tsx | 21 +- .../insights/context/FiltersProvider.tsx | 79 ++- packages/features/kbar/Kbar.tsx | 2 +- .../components/NewScheduleButton.tsx | 2 +- .../settings/layouts/SettingsLayout.tsx | 48 +- .../features/shell/NProgressPageIndicator.tsx | 80 --- packages/features/shell/Shell.tsx | 76 ++- .../webhooks/pages/webhook-edit-view.tsx | 171 +++--- .../webhooks/pages/webhook-new-view.tsx | 9 +- .../features/webhooks/pages/webhooks-view.tsx | 9 +- packages/lib/bookingSuccessRedirect.ts | 68 +-- packages/lib/hooks/useParamsWithFallback.ts | 13 + packages/lib/hooks/useRouterQuery.ts | 36 ++ packages/lib/hooks/useTypedQuery.ts | 34 +- packages/lib/hooks/useUrlMatchesCurrentUrl.ts | 19 + packages/lib/i18n.ts | 8 + packages/lib/package.json | 1 + packages/types/next.d.ts | 7 + packages/ui/components/apps/AllApps.tsx | 23 +- packages/ui/components/apps/AppCard.tsx | 13 +- .../ui/components/breadcrumb/Breadcrumb.tsx | 8 +- .../components/createButton/CreateButton.tsx | 32 +- packages/ui/components/dialog/Dialog.tsx | 50 +- packages/ui/components/dialog/dialog.test.tsx | 18 +- .../ui/components/form/wizard/WizardForm.tsx | 7 +- packages/ui/components/head-seo/HeadSeo.tsx | 4 +- .../navigation/tabs/HorizontalTabItem.tsx | 5 +- .../navigation/tabs/VerticalTabItem.tsx | 6 +- packages/ui/layouts/WizardLayout.tsx | 8 +- packages/ui/package.json | 1 + yarn.lock | 163 +++--- 152 files changed, 1802 insertions(+), 2565 deletions(-) delete mode 100644 apps/web/components/AppsShell.tsx delete mode 100644 apps/web/components/BookingsShell.tsx delete mode 100644 apps/web/components/NavTabs.tsx delete mode 100644 apps/web/components/SettingsShell.tsx create mode 100644 apps/web/components/apps/AppPage.tsx create mode 100644 apps/web/components/apps/InstallAppButtonChild.tsx delete mode 100644 apps/web/components/booking/AvailableTimes.tsx delete mode 100644 apps/web/components/booking/BookingDescriptionPayment.tsx delete mode 100644 apps/web/components/booking/SlotPicker.tsx delete mode 100644 apps/web/components/booking/TimeOptions.tsx delete mode 100644 apps/web/components/booking/TimezoneDropdown.tsx delete mode 100644 apps/web/components/booking/UserAvatars.tsx rename {apps/web/components/booking => packages/features/bookings/components/event-meta}/AvailableEventLocations.tsx (100%) delete mode 100644 packages/features/shell/NProgressPageIndicator.tsx create mode 100644 packages/lib/hooks/useParamsWithFallback.ts create mode 100644 packages/lib/hooks/useRouterQuery.ts create mode 100644 packages/lib/hooks/useUrlMatchesCurrentUrl.ts diff --git a/apps/web/components/AppListCard.tsx b/apps/web/components/AppListCard.tsx index ddc2075fbb..604891a43b 100644 --- a/apps/web/components/AppListCard.tsx +++ b/apps/web/components/AppListCard.tsx @@ -1,4 +1,4 @@ -import { useRouter } from "next/router"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; import type { ReactNode } from "react"; import { useEffect, useRef, useState } from "react"; import { z } from "zod"; @@ -10,7 +10,15 @@ import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery"; import { Badge, ListItemText, Avatar } from "@calcom/ui"; import { AlertCircle } from "@calcom/ui/components/icon"; -type ShouldHighlight = { slug: string; shouldHighlight: true } | { shouldHighlight?: never; slug?: never }; +type ShouldHighlight = + | { + slug: string; + shouldHighlight: true; + } + | { + shouldHighlight?: never; + slug?: never; + }; type AppListCardProps = { logo?: string; @@ -47,14 +55,16 @@ export default function AppListCard(props: AppListCardProps) { const router = useRouter(); const [highlight, setHighlight] = useState(shouldHighlight && hl === slug); const timeoutRef = useRef(null); + const searchParams = useSearchParams(); + const pathname = usePathname(); useEffect(() => { if (shouldHighlight && highlight) { const timer = setTimeout(() => { setHighlight(false); - const url = new URL(window.location.href); - url.searchParams.delete("hl"); - router.replace(url.pathname, undefined, { shallow: true }); + const _searchParams = new URLSearchParams(searchParams); + _searchParams.delete("hl"); + router.replace(`${pathname}?${_searchParams.toString()}`); }, 3000); timeoutRef.current = timer; } diff --git a/apps/web/components/AppsShell.tsx b/apps/web/components/AppsShell.tsx deleted file mode 100644 index 1c6230eaf3..0000000000 --- a/apps/web/components/AppsShell.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { useSession } from "next-auth/react"; -import React from "react"; - -import NavTabs from "./NavTabs"; - -const tabs = [ - { - name: "app_store", - href: "/apps", - }, - { - name: "installed_apps", - href: "/apps/installed", - }, -]; - -export default function AppsShell({ children }: { children: React.ReactNode }) { - const { status } = useSession(); - - return ( - <> -
{status === "authenticated" && }
-
{children}
- - ); -} diff --git a/apps/web/components/BookingsShell.tsx b/apps/web/components/BookingsShell.tsx deleted file mode 100644 index 5382c98aac..0000000000 --- a/apps/web/components/BookingsShell.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from "react"; - -import NavTabs from "./NavTabs"; - -const tabs = [ - { - name: "upcoming", - href: "/bookings/upcoming", - }, - { - name: "recurring", - href: "/bookings/recurring", - }, - { - name: "past", - href: "/bookings/past", - }, - { - name: "cancelled", - href: "/bookings/cancelled", - }, -]; - -export default function BookingsShell({ children }: { children: React.ReactNode }) { - return ( - <> - -
{children}
- - ); -} diff --git a/apps/web/components/Embed.tsx b/apps/web/components/Embed.tsx index cee32c4ad7..8372db4ec6 100644 --- a/apps/web/components/Embed.tsx +++ b/apps/web/components/Embed.tsx @@ -2,8 +2,7 @@ import { Collapsible, CollapsibleContent } from "@radix-ui/react-collapsible"; import classNames from "classnames"; import { useSession } from "next-auth/react"; import type { TFunction } from "next-i18next"; -import type { NextRouter } from "next/router"; -import { useRouter } from "next/router"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; import type { MutableRefObject, RefObject } from "react"; import { createRef, forwardRef, useRef, useState } from "react"; import type { ControlProps } from "react-select"; @@ -13,7 +12,7 @@ import { shallow } from "zustand/shallow"; import type { Dayjs } from "@calcom/dayjs"; import dayjs from "@calcom/dayjs"; import { AvailableTimes } from "@calcom/features/bookings"; -import { useInitializeBookerStore, useBookerStore } from "@calcom/features/bookings/Booker/store"; +import { useBookerStore, useInitializeBookerStore } from "@calcom/features/bookings/Booker/store"; import type { BookerLayout } from "@calcom/features/bookings/Booker/types"; import { useEvent, useScheduleForEvent } from "@calcom/features/bookings/Booker/utils/event"; import { useTimePreferences } from "@calcom/features/bookings/lib/timePreferences"; @@ -21,30 +20,29 @@ import DatePicker from "@calcom/features/calendars/DatePicker"; import { useFlagMap } from "@calcom/features/flags/context/provider"; import { useNonEmptyScheduleDays } from "@calcom/features/schedules"; import { useSlotsForDate } from "@calcom/features/schedules/lib/use-schedule/useSlotsForDate"; -import { CAL_URL } from "@calcom/lib/constants"; -import { APP_NAME, EMBED_LIB_URL, IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants"; +import { APP_NAME, CAL_URL, EMBED_LIB_URL, IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants"; import { weekdayToWeekIndex } from "@calcom/lib/date-fns"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { BookerLayouts } from "@calcom/prisma/zod-utils"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; -import { TimezoneSelect } from "@calcom/ui"; import { Button, + ColorPicker, Dialog, DialogClose, - DialogFooter, DialogContent, + DialogFooter, HorizontalTabs, Label, + Select, showToast, Switch, TextArea, TextField, - ColorPicker, - Select, + TimezoneSelect, } from "@calcom/ui"; -import { Code, Trello, Sun, ArrowLeft, ArrowDown, ArrowUp } from "@calcom/ui/components/icon"; +import { ArrowDown, ArrowLeft, ArrowUp, Code, Sun, Trello } from "@calcom/ui/components/icon"; type EventType = RouterOutputs["viewer"]["eventTypes"]["get"]["eventType"] | undefined; type EmbedType = "inline" | "floating-popup" | "element-click" | "email"; @@ -87,25 +85,31 @@ const getDimension = (dimension: string) => { return dimension; }; -const goto = (router: NextRouter, searchParams: Record) => { - const newQuery = new URLSearchParams(router.asPath.split("?")[1]); - Object.keys(searchParams).forEach((key) => { - newQuery.set(key, searchParams[key]); - }); - router.push(`${router.asPath.split("?")[0]}?${newQuery.toString()}`, undefined, { - shallow: true, - }); -}; +function useRouterHelpers() { + const router = useRouter(); + const searchParams = useSearchParams(); + const pathname = usePathname(); -const removeQueryParams = (router: NextRouter, queryParams: string[]) => { - const params = new URLSearchParams(window.location.search); + const goto = (newSearchParams: Record) => { + const newQuery = new URLSearchParams(searchParams); + Object.keys(newSearchParams).forEach((key) => { + newQuery.set(key, newSearchParams[key]); + }); + router.push(`${pathname}?${newQuery.toString()}`); + }; - queryParams.forEach((param) => { - params.delete(param); - }); + const removeQueryParams = (queryParams: string[]) => { + const params = new URLSearchParams(searchParams); - router.push(`${router.asPath.split("?")[0]}?${params.toString()}`); -}; + queryParams.forEach((param) => { + params.delete(param); + }); + + router.push(`${pathname}?${params.toString()}`); + }; + + return { goto, removeQueryParams }; +} const getQueryParam = (queryParam: string) => { const params = new URLSearchParams(window.location.search); @@ -325,6 +329,8 @@ ${uiInstructionCode}`; }, }; +type EmbedCommonProps = { embedType: EmbedType; calLink: string; previewState: PreviewState }; + const getEmbedTypeSpecificString = ({ embedFramework, embedType, @@ -332,10 +338,7 @@ const getEmbedTypeSpecificString = ({ previewState, }: { embedFramework: EmbedFramework; - embedType: EmbedType; - calLink: string; - previewState: PreviewState; -}) => { +} & EmbedCommonProps) => { const frameworkCodes = Codes[embedFramework]; if (!frameworkCodes) { throw new Error(`No code available for the framework:${embedFramework}`); @@ -823,77 +826,74 @@ const tabs = [ href: "embedTabName=embed-code", icon: Code, type: "code", - Component: forwardRef< - HTMLTextAreaElement | HTMLIFrameElement | null, - { embedType: EmbedType; calLink: string; previewState: PreviewState } - >(function EmbedHtml({ embedType, calLink, previewState }, ref) { - const { t } = useLocale(); - if (ref instanceof Function || !ref) { - return null; - } - if (ref.current && !(ref.current instanceof HTMLTextAreaElement)) { - return null; - } - return ( - <> -
- - {t("place_where_cal_widget_appear", { appName: APP_NAME })} - -
-