From 8ad442f2bedba9d3beca24e98079083f447b525b Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Thu, 20 Mar 2025 20:30:51 -0400 Subject: [PATCH] feat: Upgrade to Next 15 (#18834) * wip * update layoutHOC * wip * remove app router related code no longer used * remove more * await cookies, headers, params, serachparams * update yarn.lock * await cookies, headers, params, serachparams more * update yarn lock again * downgrade next-auth to 4.22.1 * update yarn lock * fix * update yarn lock * fix type checks * update yarn lock * await headers and cookies * restore pages folder * restore yarn.lock * update yarn.lock * await headers and cookies * remove * await params in API routes * updates * restore next.config.js * remove i18n from next.config.js * Fixed tests * Fixed types * Removed duplicate favicon.ico * Fixing more types * ImageResponse moved to next/og * Fixed prisma import issues * dynamic import for @ewsjs/xhr * remove deasync dep * dynamic import for @tryvital/vital-node * fix type checks * add back turbopack command * Type fix * Removed unneeded file * fix turbopack relative path errors * add comments * remove unneeded code * Fixed build errors * await apis * use Promise type in defaultResponderForAppDir util * refactor scim api route * fix type checks * separate app-routing.config into client-config and server-config * wip * refactor routing forms components * revert unneeded changes for easier review * fix * fix * use CustomTrans * fix type * fix unit tests * fix type error * fix build error * fix build error * fix build error * fix warnings * fix warnings * upgrade @tremor/react and tailwindcss * numCols -> numItems * fix forgot-password e2e test * fix 1 more e2e test * fix login e2e test * fix e2e tests * fix e2e tests * clean up * remove error * use tremor/react 2.11.0 * fix * rename CustomTrans to ServerTrans * address comment * fix test * fix ServerTrans * fix * fix type * fix ServerTrans usages 1 * fix translations * fix type checks * fix type checks * link styling * fix --------- Co-authored-by: Keith Williams Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com> --- .env.example | 7 - .../[user]/[type]/embed/page.tsx | 2 +- .../[user]/[type]/page.tsx | 6 +- .../[user]/embed/page.tsx | 2 +- .../(booking-page-wrapper)/[user]/page.tsx | 10 +- .../web/app/(booking-page-wrapper)/layout.tsx | 2 +- .../[orgSlug]/[user]/[type]/embed/page.tsx | 2 +- .../org/[orgSlug]/[user]/[type]/page.tsx | 8 +- .../org/[orgSlug]/[user]/embed/page.tsx | 2 +- .../org/[orgSlug]/[user]/page.tsx | 8 +- .../team/[slug]/[type]/page.tsx | 8 +- .../team/[slug]/[type]/embed/page.tsx | 2 +- .../team/[slug]/[type]/page.tsx | 8 +- .../team/[slug]/embed/page.tsx | 2 +- .../team/[slug]/page.tsx | 8 +- .../(main-nav)/availability/page.tsx | 2 +- .../(main-nav)/bookings/[status]/page.tsx | 2 +- .../(main-nav)/event-types/page.tsx | 2 +- .../(main-nav)/teams/page.tsx | 5 +- .../(use-page-wrapper)/apps/[slug]/page.tsx | 4 +- .../apps/[slug]/setup/page.tsx | 5 +- .../apps/categories/page.tsx | 4 +- .../apps/installation/[[...step]]/page.tsx | 6 +- .../apps/installed/[category]/page.tsx | 2 +- apps/web/app/(use-page-wrapper)/apps/page.tsx | 2 +- .../routing-forms/[...pages]/FormProvider.tsx | 9 + .../apps/routing-forms/[...pages]/page.tsx | 30 +- .../(use-page-wrapper)/auth/error/page.tsx | 2 +- .../auth/forgot-password/[id]/page.tsx | 2 +- .../auth/forgot-password/page.tsx | 2 +- .../(use-page-wrapper)/auth/login/page.tsx | 4 +- .../(use-page-wrapper)/auth/logout/page.tsx | 4 +- .../(use-page-wrapper)/auth/setup/page.tsx | 4 +- .../(use-page-wrapper)/auth/signin/page.tsx | 2 +- .../auth/sso/[provider]/page.tsx | 2 +- .../auth/sso/direct/page.tsx | 2 +- .../auth/verify-email-change/page.tsx | 4 +- .../availability/[schedule]/page.tsx | 8 +- .../booking/[uid]/embed/page.tsx | 2 +- .../(use-page-wrapper)/booking/[uid]/page.tsx | 4 +- .../d/[link]/[slug]/page.tsx | 4 +- .../event-types/[type]/page.tsx | 4 +- .../getting-started/[[...step]]/page.tsx | 2 +- apps/web/app/(use-page-wrapper)/layout.tsx | 2 +- .../(use-page-wrapper)/payment/[uid]/page.tsx | 8 +- .../admin/organizations/[id]/edit/page.tsx | 4 +- .../admin/users/[id]/edit/page.tsx | 4 +- .../settings/(admin-layout)/layout.tsx | 2 +- .../developer/webhooks/[id]/page.tsx | 3 +- .../settings/(settings-layout)/layout.tsx | 2 +- .../settings/license-key/new/page.tsx | 2 +- .../settings/organizations/new/about/page.tsx | 2 +- .../organizations/new/add-teams/page.tsx | 2 +- .../organizations/new/handover/page.tsx | 2 +- .../new/onboard-members/page.tsx | 2 +- .../settings/organizations/new/page.tsx | 2 +- .../organizations/new/status/page.tsx | 2 +- .../settings/platform/new/page.tsx | 2 +- .../app/(use-page-wrapper)/signup/page.tsx | 2 +- .../(use-page-wrapper)/video/[uid]/page.tsx | 2 +- .../video/meeting-ended/[uid]/page.tsx | 2 +- .../video/meeting-not-started/[uid]/page.tsx | 4 +- .../workflows/[workflow]/page.tsx | 6 +- .../app/(use-page-wrapper)/workflows/page.tsx | 2 +- apps/web/app/_types.ts | 6 +- apps/web/app/_utils.tsx | 46 +- .../api/auth/two-factor/totp/disable/route.ts | 2 +- .../api/auth/two-factor/totp/enable/route.ts | 2 +- .../api/auth/two-factor/totp/setup/route.ts | 2 +- .../app/api/availability/calendar/route.ts | 2 +- apps/web/app/api/avatar/[uuid]/route.ts | 4 +- apps/web/app/api/cancel/route.ts | 2 +- apps/web/app/api/customer-card/route.ts | 2 +- .../app/api/defaultResponderForAppDir.test.ts | 9 +- apps/web/app/api/defaultResponderForAppDir.ts | 4 +- apps/web/app/api/future-opt-in/route.ts | 40 - .../app/api/generate-referral-link/route.ts | 4 +- apps/web/app/api/geolocation/route.ts | 2 +- apps/web/app/api/intercom-hash/route.ts | 4 +- apps/web/app/api/link/route.ts | 2 +- apps/web/app/api/logo/route.ts | 2 +- apps/web/app/api/me/route.ts | 2 +- apps/web/app/api/plain-hash/route.ts | 2 +- .../web/app/api/recorded-daily-video/route.ts | 2 +- .../app/api/scim/v2.0/[...directory]/route.ts | 39 +- apps/web/app/api/social/og/image/route.tsx | 16 +- apps/web/app/api/sync/helpscout/route.ts | 2 +- .../web/app/api/teams/[team]/upgrade/route.ts | 6 +- .../teams/googleworkspace/callback/route.ts | 4 +- apps/web/app/api/username/route.ts | 2 +- .../web/app/api/verify-booking-token/route.ts | 2 +- apps/web/app/icons/page.tsx | 1 - apps/web/app/layout.tsx | 62 +- apps/web/app/not-found.tsx | 4 +- apps/web/app/page.tsx | 2 +- apps/web/app/reschedule/[uid]/embed/page.tsx | 2 +- apps/web/app/reschedule/[uid]/page.tsx | 2 +- .../web/app/routing-forms/[...pages]/page.tsx | 4 +- apps/web/components/PageWrapperAppDir.tsx | 2 +- apps/web/components/ServerTrans.tsx | 376 ++++++++++ apps/web/components/booking/CancelBooking.tsx | 5 +- .../steps-views/UserProfile.tsx | 5 +- .../steps-views/UserSettings.tsx | 5 +- .../settings/SecondaryEmailConfirmModal.tsx | 5 +- apps/web/lib/app-providers-app-dir.tsx | 2 +- apps/web/lib/app-providers.tsx | 2 +- .../[[...step]]/getServerSideProps.ts | 4 +- .../[...pages]/getServerSideProps.ts | 2 +- .../tests/recorded-daily-video.test.ts | 5 +- .../[[...step]]/getServerSideProps.tsx | 2 - apps/web/lib/metadata.ts | 64 -- .../reschedule/[uid]/getServerSideProps.ts | 2 +- .../moveTeamToOrg/getServerSideProps.tsx | 2 - .../moveUserToOrg/getServerSideProps.tsx | 5 +- .../removeTeamFromOrg/getServerSideProps.tsx | 5 +- .../removeUserFromOrg/getServerSideProps.tsx | 5 +- apps/web/modules/auth/login-view.tsx | 3 +- .../connect-and-join-view.tsx | 20 +- .../views/event-types-listing-view.tsx | 18 +- .../[[...step]]/onboarding-view.tsx | 2 +- .../teams/new/create-new-team-view.tsx | 3 +- apps/web/modules/signup-view.tsx | 8 +- apps/web/modules/team/team-view.tsx | 3 +- apps/web/next.config.js | 18 +- apps/web/package.json | 9 +- apps/web/pages/404.tsx | 259 ------- apps/web/playwright/booking-seats.e2e.ts | 1 + .../web/playwright/managed-event-types.e2e.ts | 5 +- .../organization/team-management.e2e.ts | 5 +- apps/web/public/favicon.ico | Bin 15086 -> 0 bytes apps/web/public/static/locales/en/common.json | 51 +- apps/web/scripts/vercel-app-router-deploy.sh | 23 - .../[id]/getServerSideProps.tsx | 5 +- apps/web/server/lib/getTranslations.ts | 22 - apps/web/server/lib/ssr.ts | 15 +- apps/web/styles/globals.css | 98 +-- apps/web/test/lib/plainTiers.test.ts | 8 +- .../utils/bookingScenario/bookingScenario.ts | 1 - .../alby/components/AlbyPaymentComponent.tsx | 2 + .../exchangecalendar/lib/CalendarService.ts | 16 +- packages/app-store/locations.ts | 2 +- packages/app-store/make/pages/setup/index.tsx | 35 +- .../getServerSidePropsSingleForm.ts | 1 - .../pages/app-routing.client-config.tsx | 8 + ...nfig.tsx => app-routing.server-config.tsx} | 21 +- .../pages/forms/getServerSideProps.ts | 4 +- .../pages/layout-handler/[...appPages].tsx | 41 -- packages/app-store/server.ts | 2 +- packages/app-store/vital/lib/client.ts | 6 +- packages/app-store/vital/lib/reschedule.ts | 2 +- .../wipemycalother/lib/reschedule.ts | 2 +- .../app-store/zapier/pages/setup/index.tsx | 26 +- packages/emails/email-manager.ts | 2 +- packages/emails/lib/generateIcsFile.ts | 2 +- packages/emails/lib/generateIcsString.ts | 2 +- packages/emails/package.json | 2 +- packages/emails/src/components/AppsStatus.tsx | 2 +- .../emails/src/components/LocationInfo.tsx | 2 +- .../src/components/UserFieldsResponses.tsx | 2 +- packages/emails/src/components/WhenInfo.tsx | 2 +- packages/emails/src/components/WhoInfo.tsx | 2 +- .../AdminOrganizationNotificationEmail.tsx | 20 +- .../src/templates/BaseScheduledEmail.tsx | 2 +- .../src/templates/BrokenIntegrationEmail.tsx | 52 +- .../DailyVideoDownloadRecordingEmail.tsx | 2 +- .../DailyVideoDownloadTranscriptEmail.tsx | 2 +- .../emails/src/templates/DisabledAppEmail.tsx | 2 +- .../src/templates/ForgotPasswordEmail.tsx | 2 +- .../src/templates/MonthlyDigestEmail.tsx | 2 +- .../src/templates/OrgAutoInviteEmail.tsx | 2 +- .../OrganizationAccountVerifyEmail.tsx | 2 +- .../templates/OrganizationAdminNoSlots.tsx | 29 +- .../templates/OrganizationCreationEmail.tsx | 49 +- .../src/templates/SlugReplacementEmail.tsx | 42 +- .../emails/src/templates/TeamInviteEmail.tsx | 127 ++-- .../src/templates/VerifyAccountEmail.tsx | 2 +- .../src/templates/VerifyEmailChangeEmail.tsx | 2 +- packages/emails/templates/_base-email.ts | 2 +- .../emails/templates/account-verify-email.ts | 2 +- .../admin-organization-notification.ts | 2 +- ...ee-daily-video-download-recording-email.ts | 2 +- ...e-daily-video-download-transcript-email.ts | 2 +- .../templates/attendee-scheduled-email.ts | 2 +- .../emails/templates/attendee-verify-email.ts | 2 +- .../booking-redirect-notification.ts | 2 +- .../templates/broken-integration-email.ts | 2 +- .../templates/change-account-email-verify.ts | 2 +- .../emails/templates/disabled-app-email.ts | 2 +- .../emails/templates/forgot-password-email.ts | 2 +- .../emails/templates/org-auto-join-invite.ts | 2 +- .../organization-admin-no-slots-email.ts | 2 +- .../templates/organization-creation-email.ts | 2 +- .../organization-email-verification.ts | 2 +- ...er-daily-video-download-recording-email.ts | 2 +- ...r-daily-video-download-transcript-email.ts | 2 +- .../templates/organizer-scheduled-email.ts | 2 +- .../templates/slug-replacement-email.ts | 2 +- .../emails/templates/team-invite-email.ts | 2 +- .../embed-core/src/useCompatSearchParams.tsx | 3 +- .../features/apps/components/appCard.test.tsx | 18 +- .../features/auth/lib/passwordResetRequest.ts | 3 +- .../BookEventForm/BookEventForm.tsx | 28 +- .../BookEventForm/BookingFields.test.tsx | 3 +- .../Booker/components/OutOfOfficeInSlots.tsx | 8 +- .../Booker/components/hooks/useBookings.ts | 2 + .../components/event-meta/Duration.tsx | 2 +- .../bookings/lib/handleNewBooking/types.ts | 2 +- .../ee/dsync/lib/inviteExistingUserToOrg.ts | 2 +- .../lib/users/inviteExistingUserToOrg.ts | 2 +- .../hooks/useLockedFieldsManager.tsx | 2 +- .../createOrganizationFromOnboarding.test.ts | 26 - .../pages/settings/admin/AdminOrgPage.tsx | 22 +- .../ee/payments/components/Payment.tsx | 2 + .../components/CreateANewPlatformForm.tsx | 3 +- .../ee/teams/components/AddNewTeamMembers.tsx | 5 +- .../components/MemberInvitationModal.tsx | 19 +- .../create-button-with-teams-list.test.tsx | 14 + .../features/ee/workflows/lib/getOptions.ts | 2 +- .../ee/workflows/lib/getWorkflowReminders.ts | 8 +- .../ee/workflows/lib/variableTranslations.ts | 2 +- .../EditWeightsForAllTeamMembers.tsx | 24 +- .../eventtypes/components/HostEditDialogs.tsx | 17 +- .../eventtypes/components/Locations.tsx | 45 +- .../components/WeightDescription.tsx | 22 + .../components/dialogs/DeleteDialog.tsx | 18 +- .../components/dialogs/ManagedEventDialog.tsx | 13 +- .../tabs/advanced/DisableAllEmailsSetting.tsx | 18 +- .../RequiresConfirmationController.tsx | 114 +-- .../components/tabs/apps/EventAppsTab.tsx | 38 +- .../assignment/EventTeamAssignmentTab.tsx | 36 +- .../tabs/webhooks/EventWebhooksTab.tsx | 44 +- .../tabs/workflows/EventWorkfowsTab.tsx | 27 +- .../form-builder/FormBuilderField.tsx | 2 +- .../insights/components/RoutedToPerPeriod.tsx | 2 +- .../settings/BookerLayoutSelector.tsx | 40 +- .../outOfOffice/OutOfOfficeEntriesList.tsx | 15 +- packages/lib/CalEventParser.test.ts | 2 +- packages/lib/CalEventParser.ts | 2 +- packages/lib/bookingSuccessRedirect.ts | 9 +- packages/lib/constants.ts | 10 - packages/lib/crmManager/crmManager.test.ts | 2 +- .../event-types/utils/locationsResolver.ts | 2 +- packages/lib/event.test.ts | 2 +- packages/lib/event.ts | 2 +- packages/lib/getSafe.ts | 6 + packages/lib/hooks/useCompatSearchParams.tsx | 2 + packages/lib/hooks/useLocale.ts | 2 +- packages/lib/hooks/useTelemetry.ts | 5 + packages/lib/package.json | 2 +- packages/lib/recurringStrings.ts | 2 +- packages/lib/server/i18n.ts | 52 +- packages/lib/telemetry.ts | 3 - packages/lib/test/builder.ts | 2 +- .../hooks/usePlatformTabsNavigations.tsx | 2 +- .../event-types/hooks/useTabsNavigations.tsx | 2 +- .../wrappers/EventTypeWebWrapper.tsx | 3 +- packages/prisma/client/index.js | 2 +- packages/prisma/zod-utils.ts | 2 +- .../bookings/requestReschedule.handler.ts | 2 +- .../viewer/teams/inviteMember/utils.ts | 2 +- packages/types/Calendar.d.ts | 2 +- turbo.json | 3 - yarn.lock | 693 +++++++++++++----- 263 files changed, 2002 insertions(+), 1663 deletions(-) create mode 100644 apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/FormProvider.tsx delete mode 100644 apps/web/app/api/future-opt-in/route.ts create mode 100644 apps/web/components/ServerTrans.tsx delete mode 100644 apps/web/lib/metadata.ts delete mode 100644 apps/web/pages/404.tsx delete mode 100644 apps/web/public/favicon.ico delete mode 100755 apps/web/scripts/vercel-app-router-deploy.sh delete mode 100644 apps/web/server/lib/getTranslations.ts create mode 100644 packages/app-store/routing-forms/pages/app-routing.client-config.tsx rename packages/app-store/routing-forms/pages/{app-routing.config.tsx => app-routing.server-config.tsx} (50%) delete mode 100644 packages/app-store/routing-forms/pages/layout-handler/[...appPages].tsx create mode 100644 packages/features/eventtypes/components/WeightDescription.tsx create mode 100644 packages/lib/getSafe.ts create mode 100644 packages/lib/hooks/useTelemetry.ts diff --git a/.env.example b/.env.example index 17d925407d..cb88791eb8 100644 --- a/.env.example +++ b/.env.example @@ -357,13 +357,6 @@ E2E_TEST_OIDC_USER_PASSWORD= # *********************************************************************************************************** -# provide a value between 0 and 100 to ensure the percentage of traffic -# redirected from the legacy to the future pages -AB_TEST_BUCKET_PROBABILITY=50 -APP_ROUTER_APPS_SLUG_SETUP_ENABLED=0 -APP_ROUTER_APPS_ENABLED=0 -APP_ROUTER_TEAM_ENABLED=0 - # disable setry server source maps SENTRY_DISABLE_SERVER_WEBPACK_PLUGIN=1 diff --git a/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx index 0e78ce9f45..6f5d0bdc8d 100644 --- a/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/[user]/[type]/embed/page.tsx @@ -11,7 +11,7 @@ import TypePage, { type PageProps as ClientPageProps } from "~/users/views/users const getData = withEmbedSsrAppDir(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; }; diff --git a/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx index bb0f0f63b4..deb6762d32 100644 --- a/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/[user]/[type]/page.tsx @@ -13,7 +13,7 @@ import type { PageProps as LegacyPageProps } from "~/users/views/users-type-publ import LegacyPage from "~/users/views/users-type-public-view"; export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(legacyCtx); const { booking, isSEOIndexable = true, eventData, isBrandingHidden } = props; @@ -31,7 +31,7 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { })), ], }; - const decodedParams = decodeParams(params); + const decodedParams = decodeParams(await params); const metadata = await generateMeetingMetadata( meeting, (t) => `${rescheduleUid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`, @@ -52,7 +52,7 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(legacyCtx); return ; diff --git a/apps/web/app/(booking-page-wrapper)/[user]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/embed/page.tsx index df9491b2e9..878bc8c508 100644 --- a/apps/web/app/(booking-page-wrapper)/[user]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/[user]/embed/page.tsx @@ -11,7 +11,7 @@ import User, { type PageProps as ClientPageProps } from "~/users/views/users-pub const getData = withEmbedSsrAppDir(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; }; diff --git a/apps/web/app/(booking-page-wrapper)/[user]/page.tsx b/apps/web/app/(booking-page-wrapper)/[user]/page.tsx index 45c57cad0d..0e10610b39 100644 --- a/apps/web/app/(booking-page-wrapper)/[user]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/[user]/page.tsx @@ -13,7 +13,9 @@ import type { PageProps as LegacyPageProps } from "~/users/views/users-public-vi import LegacyPage from "~/users/views/users-public-view"; export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); const { profile, markdownStrippedBio, isOrgSEOIndexable, entity } = props; const isOrg = !!profile?.organization; @@ -31,7 +33,7 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { () => markdownStrippedBio, false, getOrgFullOrigin(entity.orgSlug ?? null), - `/${decodeParams(params).user}` + `/${decodeParams(await params).user}` ); return { @@ -45,7 +47,9 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; diff --git a/apps/web/app/(booking-page-wrapper)/layout.tsx b/apps/web/app/(booking-page-wrapper)/layout.tsx index b96ea2efac..9355b24469 100644 --- a/apps/web/app/(booking-page-wrapper)/layout.tsx +++ b/apps/web/app/(booking-page-wrapper)/layout.tsx @@ -3,7 +3,7 @@ import { headers } from "next/headers"; import PageWrapper from "@components/PageWrapperAppDir"; export default async function BookingPageWrapperLayout({ children }: { children: React.ReactNode }) { - const h = headers(); + const h = await headers(); const nonce = h.get("x-nonce") ?? undefined; return ( diff --git a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx index e137cbaf7a..51d21aeaf0 100644 --- a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/embed/page.tsx @@ -15,7 +15,7 @@ const getData = withEmbedSsrAppDir(getServerSideProps); export type ClientPageProps = UserTypePageProps | TeamTypePageProps; const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); if ((props as TeamTypePageProps)?.teamId) return ; return ; diff --git a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx index 65b7bdf34a..c07628f4cc 100644 --- a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/[type]/page.tsx @@ -17,7 +17,7 @@ export type OrgTypePageProps = UserTypePageProps | TeamTypePageProps; const getData = withAppDirSsr(getServerSideProps); export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(legacyCtx); const { booking, isSEOIndexable = true, eventData, isBrandingHidden } = props; @@ -36,7 +36,7 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { })), ], }; - const decodedParams = decodeParams(params); + const decodedParams = decodeParams(await params); const metadata = await generateMeetingMetadata( meeting, (t) => `${rescheduleUid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`, @@ -56,7 +56,9 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { }; const ServerPage = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); if ((props as TeamTypePageProps)?.teamId) { return ; } diff --git a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/embed/page.tsx index 0b94bc02ee..1818008107 100644 --- a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/embed/page.tsx @@ -15,7 +15,7 @@ const getData = withEmbedSsrAppDir(getServerSideProps); export type ClientPageProps = UserPageProps | TeamPageProps; const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); if ((props as TeamPageProps)?.team) return ; return ; diff --git a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/page.tsx b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/page.tsx index a338de8f77..c25b58f8c3 100644 --- a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/[user]/page.tsx @@ -18,7 +18,7 @@ export type OrgPageProps = UserPageProps | TeamPageProps; const getData = withAppDirSsr(getServerSideProps); export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(legacyCtx); if ((props as TeamPageProps)?.team) { @@ -30,7 +30,7 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { image: getOrgOrTeamAvatar(team), }, }; - const decodedParams = decodeParams(params); + const decodedParams = decodeParams(await params); return { ...(await generateMeetingMetadata( meeting, @@ -78,7 +78,9 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { }; const ServerPage = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); if ((props as TeamPageProps)?.team) { return ; } diff --git a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/instant-meeting/team/[slug]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/instant-meeting/team/[slug]/[type]/page.tsx index 42aadb35fa..ad77d0a307 100644 --- a/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/instant-meeting/team/[slug]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/org/[orgSlug]/instant-meeting/team/[slug]/[type]/page.tsx @@ -12,7 +12,7 @@ import type { Props } from "~/org/[orgSlug]/instant-meeting/team/[slug]/[type]/i import Page from "~/org/[orgSlug]/instant-meeting/team/[slug]/[type]/instant-meeting-view"; export const generateMetadata = async ({ params, searchParams }: _PageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const { isBrandingHidden, eventData } = await getData(context); const profileName = eventData?.profile.name ?? ""; @@ -29,7 +29,7 @@ export const generateMetadata = async ({ params, searchParams }: _PageProps) => })), ], }; - const decodedParams = decodeParams(params); + const decodedParams = decodeParams(await params); const metadata = await generateMeetingMetadata( meeting, () => `${title} | ${profileName}`, @@ -51,7 +51,9 @@ export const generateMetadata = async ({ params, searchParams }: _PageProps) => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: _PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; diff --git a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/embed/page.tsx index 307cc85da4..fdfd8df197 100644 --- a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/embed/page.tsx @@ -10,7 +10,7 @@ import TypePage, { type PageProps as ClientPageProps } from "~/team/type-view"; const getData = withEmbedSsrAppDir(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; }; diff --git a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx index 72016bebc9..6f9436b8a7 100644 --- a/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx @@ -12,7 +12,7 @@ import LegacyPage from "~/team/type-view"; import type { PageProps as LegacyPageProps } from "~/team/type-view"; export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(legacyCtx); const { booking, isSEOIndexable, eventData, isBrandingHidden } = props; @@ -29,7 +29,7 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { })), ], }; - const decodedParams = decodeParams(params); + const decodedParams = decodeParams(await params); const metadata = await generateMeetingMetadata( meeting, (t) => `${booking?.uid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`, @@ -51,7 +51,9 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; export default ServerPage; diff --git a/apps/web/app/(booking-page-wrapper)/team/[slug]/embed/page.tsx b/apps/web/app/(booking-page-wrapper)/team/[slug]/embed/page.tsx index 15d6a21f17..251c2a19c5 100644 --- a/apps/web/app/(booking-page-wrapper)/team/[slug]/embed/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/team/[slug]/embed/page.tsx @@ -10,7 +10,7 @@ import TeamPage, { type PageProps as ClientPageProps } from "~/team/team-view"; const getData = withEmbedSsrAppDir(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; }; diff --git a/apps/web/app/(booking-page-wrapper)/team/[slug]/page.tsx b/apps/web/app/(booking-page-wrapper)/team/[slug]/page.tsx index 70993de138..5f823ff15c 100644 --- a/apps/web/app/(booking-page-wrapper)/team/[slug]/page.tsx +++ b/apps/web/app/(booking-page-wrapper)/team/[slug]/page.tsx @@ -14,7 +14,7 @@ import LegacyPage from "~/team/team-view"; export const generateMetadata = async ({ params, searchParams }: _PageProps) => { const { team, markdownStrippedBio, isSEOIndexable, currentOrgDomain } = await getData( - buildLegacyCtx(headers(), cookies(), params, searchParams) + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) ); const meeting = { @@ -24,7 +24,7 @@ export const generateMetadata = async ({ params, searchParams }: _PageProps) => image: getOrgOrTeamAvatar(team), }, }; - const decodedParams = decodeParams(params); + const decodedParams = decodeParams(await params); const metadata = await generateMeetingMetadata( meeting, (t) => team.name || t("nameless_team"), @@ -45,7 +45,9 @@ export const generateMetadata = async ({ params, searchParams }: _PageProps) => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: _PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; export default ServerPage; diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/availability/page.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/page.tsx index e7d7ac50df..24588e1eb1 100644 --- a/apps/web/app/(use-page-wrapper)/(main-nav)/availability/page.tsx +++ b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/page.tsx @@ -17,7 +17,7 @@ export const generateMetadata = async () => { }; const Page = async () => { - // const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + // const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); // const userId = session?.user?.id; // const orgId = session?.user?.org?.id; // if (!userId || !orgId) { diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/bookings/[status]/page.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/bookings/[status]/page.tsx index 1355403f27..600a981330 100644 --- a/apps/web/app/(use-page-wrapper)/(main-nav)/bookings/[status]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/(main-nav)/bookings/[status]/page.tsx @@ -18,7 +18,7 @@ export const generateMetadata = async () => ); const Page = async ({ params }: PageProps) => { - const parsed = querySchema.safeParse(params); + const parsed = querySchema.safeParse(await params); if (!parsed.success) { redirect("/bookings/upcoming"); } diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/event-types/page.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/event-types/page.tsx index d975c7de60..b54b052147 100644 --- a/apps/web/app/(use-page-wrapper)/(main-nav)/event-types/page.tsx +++ b/apps/web/app/(use-page-wrapper)/(main-nav)/event-types/page.tsx @@ -19,7 +19,7 @@ export const generateMetadata = async () => ); const Page = async ({ params, searchParams }: PageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const session = await getServerSession({ req: context.req }); if (!session?.user?.id) { diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/teams/page.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/teams/page.tsx index 3a5a13b7b3..c70d1f8d46 100644 --- a/apps/web/app/(use-page-wrapper)/(main-nav)/teams/page.tsx +++ b/apps/web/app/(use-page-wrapper)/(main-nav)/teams/page.tsx @@ -16,8 +16,9 @@ export const generateMetadata = async () => (t) => t("create_manage_teams_collaborative") ); -const ServerPage = async ({ searchParams }: ServerPageProps) => { - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); +const ServerPage = async ({ searchParams: _searchParams }: ServerPageProps) => { + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); + const searchParams = await _searchParams; const token = Array.isArray(searchParams?.token) ? searchParams.token[0] : searchParams?.token; const callbackUrl = token ? `/teams?token=${encodeURIComponent(token)}` : null; diff --git a/apps/web/app/(use-page-wrapper)/apps/[slug]/page.tsx b/apps/web/app/(use-page-wrapper)/apps/[slug]/page.tsx index 94b15fd498..52b2bf83fb 100644 --- a/apps/web/app/(use-page-wrapper)/apps/[slug]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/apps/[slug]/page.tsx @@ -12,7 +12,7 @@ const paramsSchema = z.object({ }); export const generateMetadata = async ({ params }: _PageProps) => { - const p = paramsSchema.safeParse(params); + const p = paramsSchema.safeParse(await params); if (!p.success) { return notFound(); @@ -33,7 +33,7 @@ export const generateMetadata = async ({ params }: _PageProps) => { }; async function Page({ params }: _PageProps) { - const p = paramsSchema.safeParse(params); + const p = paramsSchema.safeParse(await params); if (!p.success) { return notFound(); diff --git a/apps/web/app/(use-page-wrapper)/apps/[slug]/setup/page.tsx b/apps/web/app/(use-page-wrapper)/apps/[slug]/setup/page.tsx index 4410b8cc71..338fadcf5c 100644 --- a/apps/web/app/(use-page-wrapper)/apps/[slug]/setup/page.tsx +++ b/apps/web/app/(use-page-wrapper)/apps/[slug]/setup/page.tsx @@ -9,7 +9,8 @@ import { buildLegacyCtx } from "@lib/buildLegacyCtx"; import SetupView, { type PageProps as ClientPageProps } from "~/apps/[slug]/setup/setup-view"; -export const generateMetadata = async ({ params }: ServerPageProps) => { +export const generateMetadata = async ({ params: _params }: ServerPageProps) => { + const params = await _params; const metadata = await _generateMetadata( () => `${params.slug}`, () => "" @@ -26,7 +27,7 @@ export const generateMetadata = async ({ params }: ServerPageProps) => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const { dehydratedState, ...props } = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/apps/categories/page.tsx b/apps/web/app/(use-page-wrapper)/apps/categories/page.tsx index 0f07252b77..d63fd02d17 100644 --- a/apps/web/app/(use-page-wrapper)/apps/categories/page.tsx +++ b/apps/web/app/(use-page-wrapper)/apps/categories/page.tsx @@ -10,7 +10,9 @@ import Page from "~/apps/categories/categories-view"; const getData = withAppDirSsr(getServerSideProps); async function ServerPage({ params, searchParams }: PageProps) { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; } diff --git a/apps/web/app/(use-page-wrapper)/apps/installation/[[...step]]/page.tsx b/apps/web/app/(use-page-wrapper)/apps/installation/[[...step]]/page.tsx index 591b0d52d7..41e30a28be 100644 --- a/apps/web/app/(use-page-wrapper)/apps/installation/[[...step]]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/apps/installation/[[...step]]/page.tsx @@ -10,7 +10,7 @@ import type { OnboardingPageProps } from "~/apps/installation/[[...step]]/step-v import Page from "~/apps/installation/[[...step]]/step-view"; export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const { appMetadata } = await getData(legacyCtx); return await _generateMetadata( @@ -22,7 +22,9 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; export default ServerPage; diff --git a/apps/web/app/(use-page-wrapper)/apps/installed/[category]/page.tsx b/apps/web/app/(use-page-wrapper)/apps/installed/[category]/page.tsx index ff6d563bc9..28c3ca4aab 100644 --- a/apps/web/app/(use-page-wrapper)/apps/installed/[category]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/apps/installed/[category]/page.tsx @@ -19,7 +19,7 @@ export const generateMetadata = async () => { }; const InstalledAppsWrapper = async ({ params }: PageProps) => { - const parsedParams = querySchema.safeParse(params); + const parsedParams = querySchema.safeParse(await params); if (!parsedParams.success) { redirect("/apps/installed/calendar"); diff --git a/apps/web/app/(use-page-wrapper)/apps/page.tsx b/apps/web/app/(use-page-wrapper)/apps/page.tsx index 0117c797c9..8a9a6f027b 100644 --- a/apps/web/app/(use-page-wrapper)/apps/page.tsx +++ b/apps/web/app/(use-page-wrapper)/apps/page.tsx @@ -18,7 +18,7 @@ export const generateMetadata = async () => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/FormProvider.tsx b/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/FormProvider.tsx new file mode 100644 index 0000000000..1e34195c6a --- /dev/null +++ b/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/FormProvider.tsx @@ -0,0 +1,9 @@ +"use client"; + +import { FormProvider as ReactHookFormProvider, useForm } from "react-hook-form"; + +export default function FormProvider({ children }: { children: React.ReactNode }) { + const methods = useForm(); + + return {children}; +} diff --git a/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/page.tsx b/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/page.tsx index cf9817f314..fbb217dce7 100644 --- a/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/page.tsx @@ -3,23 +3,25 @@ import type { PageProps as ServerPageProps } from "app/_types"; import { _generateMetadata } from "app/_utils"; import { cookies, headers } from "next/headers"; -import type { routingServerSidePropsConfig } from "@calcom/app-store/routing-forms/pages/app-routing.config"; -import LayoutHandler from "@calcom/app-store/routing-forms/pages/layout-handler/[...appPages]"; +import { routingFormsComponents } from "@calcom/app-store/routing-forms/pages/app-routing.client-config"; +import type { routingServerSidePropsConfig } from "@calcom/app-store/routing-forms/pages/app-routing.server-config"; import Shell from "@calcom/features/shell/Shell"; import { getServerSideProps } from "@lib/apps/routing-forms/[...pages]/getServerSideProps"; import { buildLegacyCtx } from "@lib/buildLegacyCtx"; +import FormProvider from "./FormProvider"; + const normalizePages = (pages: string[] | string | undefined) => { const normalizedPages = Array.isArray(pages) ? pages : pages?.split("/") ?? []; return { - mainPage: normalizedPages[0], + mainPage: normalizedPages[0] ?? "forms", subPages: normalizedPages.slice(1), }; }; -export const generateMetadata = async ({ params }: { params: { pages: string[] } }) => { - const { mainPage } = normalizePages(params.pages); +export const generateMetadata = async ({ params }: { params: Promise<{ pages: string[] }> }) => { + const { mainPage } = normalizePages((await params).pages); return await _generateMetadata( // TODO: Need to show the actual form name instead of "Form" (t) => (mainPage === "routing-link" ? `Form | Cal.com Forms` : `${t("routing_forms")} | Cal.com Forms`), @@ -32,22 +34,24 @@ type GetServerSidePropsResult = const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); - const { mainPage, subPages } = normalizePages(params.pages); + const { mainPage } = normalizePages((await params).pages); - const componentProps = { - ...props, - pages: subPages, - }; + const Component = await routingFormsComponents[mainPage as keyof typeof routingFormsComponents](); + const FinalComponent = () => ( + + + + ); if (mainPage === "routing-link") { - return ; + return ; } return ( - + ); }; diff --git a/apps/web/app/(use-page-wrapper)/auth/error/page.tsx b/apps/web/app/(use-page-wrapper)/auth/error/page.tsx index da2f209e9f..d5c59e22c8 100644 --- a/apps/web/app/(use-page-wrapper)/auth/error/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/error/page.tsx @@ -21,7 +21,7 @@ const querySchema = z.object({ const ServerPage = async ({ searchParams }: PageProps) => { const t = await getTranslate(); - const { error } = querySchema.parse({ error: searchParams?.error || undefined }); + const { error } = querySchema.parse({ error: (await searchParams)?.error || undefined }); const errorMsg = t("error_during_login") + (error ? ` Error code: ${error}` : ""); return ( diff --git a/apps/web/app/(use-page-wrapper)/auth/forgot-password/[id]/page.tsx b/apps/web/app/(use-page-wrapper)/auth/forgot-password/[id]/page.tsx index 4810f917a4..253dc85651 100644 --- a/apps/web/app/(use-page-wrapper)/auth/forgot-password/[id]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/forgot-password/[id]/page.tsx @@ -19,7 +19,7 @@ export const generateMetadata = async () => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/auth/forgot-password/page.tsx b/apps/web/app/(use-page-wrapper)/auth/forgot-password/page.tsx index 0b656a734f..11ad68f9ea 100644 --- a/apps/web/app/(use-page-wrapper)/auth/forgot-password/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/forgot-password/page.tsx @@ -18,7 +18,7 @@ export const generateMetadata = async () => { }; const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const session = await getServerSession({ req: context.req }); if (session) { diff --git a/apps/web/app/(use-page-wrapper)/auth/login/page.tsx b/apps/web/app/(use-page-wrapper)/auth/login/page.tsx index 9ccefad02c..05c83861b4 100644 --- a/apps/web/app/(use-page-wrapper)/auth/login/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/login/page.tsx @@ -20,7 +20,9 @@ export const generateMetadata = async () => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; diff --git a/apps/web/app/(use-page-wrapper)/auth/logout/page.tsx b/apps/web/app/(use-page-wrapper)/auth/logout/page.tsx index 99639e5e10..f95c2e1957 100644 --- a/apps/web/app/(use-page-wrapper)/auth/logout/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/logout/page.tsx @@ -17,8 +17,8 @@ export const generateMetadata = async () => { const Page = async ({ params, searchParams }: PageProps) => { // cookie will be cleared in `/apps/web/middleware.ts` - const h = headers(); - const context = buildLegacyCtx(h, cookies(), params, searchParams); + const h = await headers(); + const context = buildLegacyCtx(h, await cookies(), await params, await searchParams); await ssrInit(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/auth/setup/page.tsx b/apps/web/app/(use-page-wrapper)/auth/setup/page.tsx index ff6768e7cc..b7042b6829 100644 --- a/apps/web/app/(use-page-wrapper)/auth/setup/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/setup/page.tsx @@ -20,7 +20,9 @@ export const generateMetadata = async () => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; diff --git a/apps/web/app/(use-page-wrapper)/auth/signin/page.tsx b/apps/web/app/(use-page-wrapper)/auth/signin/page.tsx index aac25c869b..9ca95e4908 100644 --- a/apps/web/app/(use-page-wrapper)/auth/signin/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/signin/page.tsx @@ -14,7 +14,7 @@ import type { PageProps as ClientPageProps } from "~/auth/signin-view"; const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const session = await getServerSession({ req: context.req }); if (session) { redirect("/"); diff --git a/apps/web/app/(use-page-wrapper)/auth/sso/[provider]/page.tsx b/apps/web/app/(use-page-wrapper)/auth/sso/[provider]/page.tsx index cb3572e78f..d04832bcb6 100644 --- a/apps/web/app/(use-page-wrapper)/auth/sso/[provider]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/sso/[provider]/page.tsx @@ -11,7 +11,7 @@ import SSOProviderView from "~/auth/sso/provider-view"; const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/auth/sso/direct/page.tsx b/apps/web/app/(use-page-wrapper)/auth/sso/direct/page.tsx index a80dac7d74..a855dca4b0 100644 --- a/apps/web/app/(use-page-wrapper)/auth/sso/direct/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/sso/direct/page.tsx @@ -11,7 +11,7 @@ import SSODirectView from "~/auth/sso/direct-view"; const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/auth/verify-email-change/page.tsx b/apps/web/app/(use-page-wrapper)/auth/verify-email-change/page.tsx index f49468649f..761728d261 100644 --- a/apps/web/app/(use-page-wrapper)/auth/verify-email-change/page.tsx +++ b/apps/web/app/(use-page-wrapper)/auth/verify-email-change/page.tsx @@ -19,7 +19,9 @@ export const generateMetadata = async () => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; export default ServerPage; diff --git a/apps/web/app/(use-page-wrapper)/availability/[schedule]/page.tsx b/apps/web/app/(use-page-wrapper)/availability/[schedule]/page.tsx index d3d443ec18..f948002f65 100644 --- a/apps/web/app/(use-page-wrapper)/availability/[schedule]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/availability/[schedule]/page.tsx @@ -25,7 +25,7 @@ const querySchema = z.object({ const getSchedule = cache((id: number) => ScheduleRepository.findScheduleById({ id })); export const generateMetadata = async ({ params }: PageProps) => { - const parsed = querySchema.safeParse(params); + const parsed = querySchema.safeParse(await params); if (!parsed.success) { notFound(); } @@ -43,13 +43,13 @@ export const generateMetadata = async ({ params }: PageProps) => { }; const Page = async ({ params }: PageProps) => { - const parsed = querySchema.safeParse(params); + const parsed = querySchema.safeParse(await params); if (!parsed.success) { notFound(); } - // const scheduleId = Number(params.schedule); + // const scheduleId = Number(await params.schedule); - // const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + // const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); // const userId = session?.user?.id; // if (!userId) { // notFound(); diff --git a/apps/web/app/(use-page-wrapper)/booking/[uid]/embed/page.tsx b/apps/web/app/(use-page-wrapper)/booking/[uid]/embed/page.tsx index d0e4c69b5a..0520153bf9 100644 --- a/apps/web/app/(use-page-wrapper)/booking/[uid]/embed/page.tsx +++ b/apps/web/app/(use-page-wrapper)/booking/[uid]/embed/page.tsx @@ -13,7 +13,7 @@ import { const getEmbedData = withEmbedSsrAppDir(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getEmbedData(context); return ; }; diff --git a/apps/web/app/(use-page-wrapper)/booking/[uid]/page.tsx b/apps/web/app/(use-page-wrapper)/booking/[uid]/page.tsx index f110db9557..af0c90f719 100644 --- a/apps/web/app/(use-page-wrapper)/booking/[uid]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/booking/[uid]/page.tsx @@ -16,7 +16,7 @@ import { export const generateMetadata = async ({ params, searchParams }: _PageProps) => { const { bookingInfo, eventType, recurringBookings, orgSlug } = await getData( - buildLegacyCtx(headers(), cookies(), params, searchParams) + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) ); const needsConfirmation = bookingInfo.status === BookingStatus.PENDING && eventType.requiresConfirmation; @@ -33,7 +33,7 @@ export const generateMetadata = async ({ params, searchParams }: _PageProps) => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: _PageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; }; diff --git a/apps/web/app/(use-page-wrapper)/d/[link]/[slug]/page.tsx b/apps/web/app/(use-page-wrapper)/d/[link]/[slug]/page.tsx index 68fc6cd3fd..93786d48f9 100644 --- a/apps/web/app/(use-page-wrapper)/d/[link]/[slug]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/d/[link]/[slug]/page.tsx @@ -10,7 +10,7 @@ import { type PageProps } from "@lib/d/[link]/[slug]/getServerSideProps"; import Type from "~/d/[link]/d-type-view"; export const generateMetadata = async ({ params, searchParams }: _PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const pageProps = await getData(legacyCtx); const { booking, eventData, isBrandingHidden } = pageProps; @@ -27,7 +27,7 @@ export const generateMetadata = async ({ params, searchParams }: _PageProps) => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: _PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const pageProps = await getData(legacyCtx); return ; diff --git a/apps/web/app/(use-page-wrapper)/event-types/[type]/page.tsx b/apps/web/app/(use-page-wrapper)/event-types/[type]/page.tsx index 022fe291c3..2ef18d1964 100644 --- a/apps/web/app/(use-page-wrapper)/event-types/[type]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/event-types/[type]/page.tsx @@ -22,7 +22,7 @@ const querySchema = z.object({ }); export const generateMetadata = async ({ params }: _PageProps) => { - const parsed = querySchema.safeParse(params); + const parsed = querySchema.safeParse(await params); if (!parsed.success) { return await _generateMetadata( (t) => `${t("event_type")}`, @@ -43,7 +43,7 @@ export const generateMetadata = async ({ params }: _PageProps) => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: _PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(legacyCtx); return ; diff --git a/apps/web/app/(use-page-wrapper)/getting-started/[[...step]]/page.tsx b/apps/web/app/(use-page-wrapper)/getting-started/[[...step]]/page.tsx index 0a347eae7c..ba47708cfa 100644 --- a/apps/web/app/(use-page-wrapper)/getting-started/[[...step]]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/getting-started/[[...step]]/page.tsx @@ -22,7 +22,7 @@ export const generateMetadata = async () => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/layout.tsx b/apps/web/app/(use-page-wrapper)/layout.tsx index 2fc38abd52..b06a3a5fe6 100644 --- a/apps/web/app/(use-page-wrapper)/layout.tsx +++ b/apps/web/app/(use-page-wrapper)/layout.tsx @@ -3,7 +3,7 @@ import { headers } from "next/headers"; import PageWrapper from "@components/PageWrapperAppDir"; export default async function PageWrapperLayout({ children }: { children: React.ReactNode }) { - const h = headers(); + const h = await headers(); const nonce = h.get("x-nonce") ?? undefined; return ( diff --git a/apps/web/app/(use-page-wrapper)/payment/[uid]/page.tsx b/apps/web/app/(use-page-wrapper)/payment/[uid]/page.tsx index 008602773b..58712013e6 100644 --- a/apps/web/app/(use-page-wrapper)/payment/[uid]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/payment/[uid]/page.tsx @@ -10,7 +10,9 @@ import { APP_NAME } from "@calcom/lib/constants"; import { buildLegacyCtx } from "@lib/buildLegacyCtx"; export const generateMetadata = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); const eventName = props.booking.title; return await _generateMetadata( (t) => `${t("payment")} | ${eventName} | ${APP_NAME}`, @@ -21,7 +23,9 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + const props = await getData( + buildLegacyCtx(await headers(), await cookies(), await params, await searchParams) + ); return ; }; diff --git a/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/admin/organizations/[id]/edit/page.tsx b/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/admin/organizations/[id]/edit/page.tsx index 448902d771..0114306665 100644 --- a/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/admin/organizations/[id]/edit/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/admin/organizations/[id]/edit/page.tsx @@ -11,7 +11,7 @@ import { OrganizationRepository } from "@calcom/lib/server/repository/organizati const orgIdSchema = z.object({ id: z.coerce.number() }); export const generateMetadata = async ({ params }: { params: Params }) => { - const input = orgIdSchema.safeParse(params); + const input = orgIdSchema.safeParse(await params); if (!input.success) { return await _generateMetadata( (t) => t("editing_org"), @@ -28,7 +28,7 @@ export const generateMetadata = async ({ params }: { params: Params }) => { }; const Page = async ({ params }: { params: Params }) => { - const input = orgIdSchema.safeParse(params); + const input = orgIdSchema.safeParse(await params); if (!input.success) notFound(); diff --git a/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/admin/users/[id]/edit/page.tsx b/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/admin/users/[id]/edit/page.tsx index d9a9f5d025..6be685d31d 100644 --- a/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/admin/users/[id]/edit/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/admin/users/[id]/edit/page.tsx @@ -11,7 +11,7 @@ import { UserRepository } from "@calcom/lib/server/repository/user"; const userIdSchema = z.object({ id: z.coerce.number() }); export const generateMetadata = async ({ params }: { params: Params }) => { - const input = userIdSchema.safeParse(params); + const input = userIdSchema.safeParse(await params); if (!input.success) { return await _generateMetadata( (t) => t("editing_user"), @@ -28,7 +28,7 @@ export const generateMetadata = async ({ params }: { params: Params }) => { }; const Page = async ({ params }: { params: Params }) => { - const input = userIdSchema.safeParse(params); + const input = userIdSchema.safeParse(await params); if (!input.success) { notFound(); diff --git a/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/layout.tsx b/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/layout.tsx index 2f09486645..bf2bfed9fd 100644 --- a/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/layout.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/(admin-layout)/layout.tsx @@ -12,7 +12,7 @@ import AdminLayoutAppDirClient from "./AdminLayoutAppDirClient"; type AdminLayoutAppDirProps = Omit; export default async function AdminLayoutAppDir(props: AdminLayoutAppDirProps) { - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); const userRole = session?.user?.role; return await SettingsLayoutAppDir({ children: }); diff --git a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/webhooks/[id]/page.tsx b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/webhooks/[id]/page.tsx index 7263eb9279..6a8be3de09 100644 --- a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/webhooks/[id]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/webhooks/[id]/page.tsx @@ -12,8 +12,9 @@ export const generateMetadata = async () => (t) => t("add_webhook_description", { appName: APP_NAME }) ); -const Page = async ({ params }: PageProps) => { +const Page = async ({ params: _params }: PageProps) => { const t = await getTranslate(); + const params = await _params; const id = typeof params?.id === "string" ? params.id : undefined; const webhook = await WebhookRepository.findByWebhookId(id); diff --git a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/layout.tsx b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/layout.tsx index b6ec56f778..b19a991418 100644 --- a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/layout.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/layout.tsx @@ -12,7 +12,7 @@ import SettingsLayoutAppDirClient from "./SettingsLayoutAppDirClient"; type SettingsLayoutAppDirProps = Omit; export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDirProps) { - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); const userId = session?.user?.id ?? -1; const orgId = session?.user?.org?.id ?? -1; diff --git a/apps/web/app/(use-page-wrapper)/settings/license-key/new/page.tsx b/apps/web/app/(use-page-wrapper)/settings/license-key/new/page.tsx index 09d4940017..5a385244c6 100644 --- a/apps/web/app/(use-page-wrapper)/settings/license-key/new/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/license-key/new/page.tsx @@ -19,7 +19,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr>(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + await getData(buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)); return ( diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/new/about/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/new/about/page.tsx index ba189104c8..d7f855f431 100644 --- a/apps/web/app/(use-page-wrapper)/settings/organizations/new/about/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/organizations/new/about/page.tsx @@ -17,7 +17,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + await getData(buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)); return ( diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/new/add-teams/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/new/add-teams/page.tsx index 21c90a9430..b581f9864a 100644 --- a/apps/web/app/(use-page-wrapper)/settings/organizations/new/add-teams/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/organizations/new/add-teams/page.tsx @@ -17,7 +17,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + await getData(buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)); return ( diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/new/handover/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/new/handover/page.tsx index d5b06be456..eee663e5e7 100644 --- a/apps/web/app/(use-page-wrapper)/settings/organizations/new/handover/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/organizations/new/handover/page.tsx @@ -18,7 +18,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + await getData(buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)); return ( diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/new/onboard-members/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/new/onboard-members/page.tsx index d6aff7cb95..c99c48c497 100644 --- a/apps/web/app/(use-page-wrapper)/settings/organizations/new/onboard-members/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/organizations/new/onboard-members/page.tsx @@ -17,7 +17,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + await getData(buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)); return ( diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/new/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/new/page.tsx index 96da7ee472..d5b7ffd45f 100644 --- a/apps/web/app/(use-page-wrapper)/settings/organizations/new/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/organizations/new/page.tsx @@ -23,7 +23,7 @@ type Props = { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + await getData(buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)); return ( diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/new/status/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/new/status/page.tsx index 69967aecd2..07879c2e39 100644 --- a/apps/web/app/(use-page-wrapper)/settings/organizations/new/status/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/organizations/new/status/page.tsx @@ -17,7 +17,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + await getData(buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)); return ( diff --git a/apps/web/app/(use-page-wrapper)/settings/platform/new/page.tsx b/apps/web/app/(use-page-wrapper)/settings/platform/new/page.tsx index d338805430..c1086eab92 100644 --- a/apps/web/app/(use-page-wrapper)/settings/platform/new/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/platform/new/page.tsx @@ -23,7 +23,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - await getData(buildLegacyCtx(headers(), cookies(), params, searchParams)); + await getData(buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)); return ( diff --git a/apps/web/app/(use-page-wrapper)/signup/page.tsx b/apps/web/app/(use-page-wrapper)/signup/page.tsx index afbb38cc80..284f821bc6 100644 --- a/apps/web/app/(use-page-wrapper)/signup/page.tsx +++ b/apps/web/app/(use-page-wrapper)/signup/page.tsx @@ -18,7 +18,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: PageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/video/[uid]/page.tsx b/apps/web/app/(use-page-wrapper)/video/[uid]/page.tsx index 4e034265dc..3c525b0e5b 100644 --- a/apps/web/app/(use-page-wrapper)/video/[uid]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/video/[uid]/page.tsx @@ -39,7 +39,7 @@ export const generateMetadata = async () => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/video/meeting-ended/[uid]/page.tsx b/apps/web/app/(use-page-wrapper)/video/meeting-ended/[uid]/page.tsx index 89d44c95ff..ec528848d3 100644 --- a/apps/web/app/(use-page-wrapper)/video/meeting-ended/[uid]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/video/meeting-ended/[uid]/page.tsx @@ -18,7 +18,7 @@ export const generateMetadata = async () => const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/video/meeting-not-started/[uid]/page.tsx b/apps/web/app/(use-page-wrapper)/video/meeting-not-started/[uid]/page.tsx index c31aec6264..a2464ca46e 100644 --- a/apps/web/app/(use-page-wrapper)/video/meeting-not-started/[uid]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/video/meeting-not-started/[uid]/page.tsx @@ -18,7 +18,7 @@ const querySchema = z.object({ }); export const generateMetadata = async ({ params }: ServerPageProps) => { - const parsed = querySchema.safeParse(params); + const parsed = querySchema.safeParse(await params); if (!parsed.success) { notFound(); } @@ -35,7 +35,7 @@ export const generateMetadata = async ({ params }: ServerPageProps) => { const getData = withAppDirSsr(getServerSideProps); const ServerPage = async ({ params, searchParams }: ServerPageProps) => { - const context = buildLegacyCtx(headers(), cookies(), params, searchParams); + const context = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); const props = await getData(context); return ; diff --git a/apps/web/app/(use-page-wrapper)/workflows/[workflow]/page.tsx b/apps/web/app/(use-page-wrapper)/workflows/[workflow]/page.tsx index eafa40c528..5d1dcda480 100644 --- a/apps/web/app/(use-page-wrapper)/workflows/[workflow]/page.tsx +++ b/apps/web/app/(use-page-wrapper)/workflows/[workflow]/page.tsx @@ -23,7 +23,7 @@ const querySchema = z.object({ const getWorkflow = cache((id: number) => WorkflowRepository.getById({ id })); export const generateMetadata = async ({ params }: PageProps): Promise => { - const parsed = querySchema.safeParse(params); + const parsed = querySchema.safeParse(await params); if (!parsed.success) { notFound(); } @@ -38,9 +38,9 @@ export const generateMetadata = async ({ params }: PageProps): Promise { - // const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + // const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); // const user = session?.user; - const parsed = querySchema.safeParse(params); + const parsed = querySchema.safeParse(await params); if (!parsed.success) { notFound(); } diff --git a/apps/web/app/(use-page-wrapper)/workflows/page.tsx b/apps/web/app/(use-page-wrapper)/workflows/page.tsx index cdf5b195f7..cf89ad25b2 100644 --- a/apps/web/app/(use-page-wrapper)/workflows/page.tsx +++ b/apps/web/app/(use-page-wrapper)/workflows/page.tsx @@ -15,7 +15,7 @@ export const generateMetadata = async () => ); const Page = async ({ params, searchParams }: PageProps) => { - // const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + // const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); // const user = session?.user; // const filters = getTeamsFiltersFromQuery({ ...searchParams, ...params }); diff --git a/apps/web/app/_types.ts b/apps/web/app/_types.ts index 0e6ce75a13..a90eaae620 100644 --- a/apps/web/app/_types.ts +++ b/apps/web/app/_types.ts @@ -7,8 +7,8 @@ export type SearchParams = { }; export type PageProps = { - params: Params; - searchParams: SearchParams; + params: Promise; + searchParams: Promise; }; -export type LayoutProps = { params: Params; children: React.ReactElement }; +export type LayoutProps = { params: Promise; children: React.ReactElement }; diff --git a/apps/web/app/_utils.tsx b/apps/web/app/_utils.tsx index 3331e452bc..1884e95010 100644 --- a/apps/web/app/_utils.tsx +++ b/apps/web/app/_utils.tsx @@ -1,6 +1,4 @@ import { type TFunction } from "i18next"; -import i18next from "i18next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { cookies, headers } from "next/headers"; import { getLocale } from "@calcom/features/auth/lib/getLocale"; @@ -8,48 +6,19 @@ import type { AppImageProps, MeetingImageProps } from "@calcom/lib/OgImages"; import { constructAppImage, constructGenericImage, constructMeetingImage } from "@calcom/lib/OgImages"; import { IS_CALCOM, WEBAPP_URL, APP_NAME, SEO_IMG_OGIMG, CAL_URL } from "@calcom/lib/constants"; import { buildCanonical } from "@calcom/lib/next-seo.config"; +import { getTranslation } from "@calcom/lib/server/i18n"; import { truncateOnWord } from "@calcom/lib/text"; -//@ts-expect-error no type definitions -import config from "@calcom/web/next-i18next.config"; import { buildLegacyRequest } from "@lib/buildLegacyCtx"; -const i18nInstanceCache: Record = {}; - -const createI18nInstance = async (locale: string, ns: string) => { - const cacheKey = `${locale}-${ns}`; - // Check module-level cache first - if (i18nInstanceCache[cacheKey]) { - return i18nInstanceCache[cacheKey]; - } - - const { _nextI18Next } = await serverSideTranslations(locale, [ns], config); - - const _i18n = i18next.createInstance(); - await _i18n.init({ - lng: locale, - resources: _nextI18Next?.initialI18nStore, - fallbackLng: _nextI18Next?.userConfig?.i18n.defaultLocale, - }); - - // Cache the instance - i18nInstanceCache[cacheKey] = _i18n; - return _i18n; -}; - -const getTranslationWithCache = async (locale: string, ns = "common") => { - const localeWithFallback = locale ?? "en"; - const i18n = await createI18nInstance(localeWithFallback, ns); - return i18n.getFixedT(localeWithFallback, ns); -}; - export const getTranslate = async () => { const headersList = await headers(); // If "x-locale" does not exist in header, // ensure that config.matcher in middleware includes the page you are testing - const locale = headersList.get("x-locale") ?? (await getLocale(buildLegacyRequest(headersList, cookies()))); - const t = await getTranslationWithCache(locale ?? "en"); - return t; + const locale = + headersList.get("x-locale") ?? (await getLocale(buildLegacyRequest(headersList, await cookies()))); + + return await getTranslation(locale ?? "en", "common"); }; const _generateMetadataWithoutImage = async ( @@ -59,11 +28,10 @@ const _generateMetadataWithoutImage = async ( origin?: string, pathname?: string ) => { - const h = headers(); + const h = await headers(); const _pathname = h.get("x-pathname") ?? pathname ?? ""; const canonical = buildCanonical({ path: _pathname, origin: origin ?? CAL_URL }); - const locale = h.get("x-locale") ?? (await getLocale(buildLegacyRequest(h, cookies()))) ?? "en"; - const t = await getTranslationWithCache(locale); + const t = await getTranslate(); const title = getTitle(t); const description = getDescription(t); diff --git a/apps/web/app/api/auth/two-factor/totp/disable/route.ts b/apps/web/app/api/auth/two-factor/totp/disable/route.ts index 4fe6507d9c..ce0551be13 100644 --- a/apps/web/app/api/auth/two-factor/totp/disable/route.ts +++ b/apps/web/app/api/auth/two-factor/totp/disable/route.ts @@ -16,7 +16,7 @@ import { buildLegacyRequest } from "@lib/buildLegacyCtx"; async function handler(req: NextRequest) { const body = await parseRequestData(req); - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); if (!session) { return NextResponse.json({ message: "Not authenticated" }, { status: 401 }); diff --git a/apps/web/app/api/auth/two-factor/totp/enable/route.ts b/apps/web/app/api/auth/two-factor/totp/enable/route.ts index 07551665b4..79409e3ae4 100644 --- a/apps/web/app/api/auth/two-factor/totp/enable/route.ts +++ b/apps/web/app/api/auth/two-factor/totp/enable/route.ts @@ -14,7 +14,7 @@ import { buildLegacyRequest } from "@lib/buildLegacyCtx"; async function postHandler(req: NextRequest) { const body = await parseRequestData(req); - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); if (!session) { return NextResponse.json({ message: "Not authenticated" }, { status: 401 }); diff --git a/apps/web/app/api/auth/two-factor/totp/setup/route.ts b/apps/web/app/api/auth/two-factor/totp/setup/route.ts index cfd8fc4a5d..ea665ef1dd 100644 --- a/apps/web/app/api/auth/two-factor/totp/setup/route.ts +++ b/apps/web/app/api/auth/two-factor/totp/setup/route.ts @@ -18,7 +18,7 @@ import { buildLegacyRequest } from "@lib/buildLegacyCtx"; async function postHandler(req: NextRequest) { const body = await parseRequestData(req); - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); if (!session) { return NextResponse.json({ message: "Not authenticated" }, { status: 401 }); diff --git a/apps/web/app/api/availability/calendar/route.ts b/apps/web/app/api/availability/calendar/route.ts index 08cdae820a..23bd9840bd 100644 --- a/apps/web/app/api/availability/calendar/route.ts +++ b/apps/web/app/api/availability/calendar/route.ts @@ -23,7 +23,7 @@ const selectedCalendarSelectSchema = z.object({ }); async function authMiddleware() { - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); if (!session?.user?.id) { throw new HttpError({ statusCode: 401, message: "Not authenticated" }); diff --git a/apps/web/app/api/avatar/[uuid]/route.ts b/apps/web/app/api/avatar/[uuid]/route.ts index 1ec20964d0..ccd746d2d6 100644 --- a/apps/web/app/api/avatar/[uuid]/route.ts +++ b/apps/web/app/api/avatar/[uuid]/route.ts @@ -26,8 +26,8 @@ const handleValidationError = (error: z.ZodError): NextResponse => { ); }; -async function handler(req: NextRequest, { params }: { params: Params }) { - const result = querySchema.safeParse(params); +async function handler(req: NextRequest, { params }: { params: Promise }) { + const result = querySchema.safeParse(await params); if (!result.success) { return handleValidationError(result.error); } diff --git a/apps/web/app/api/cancel/route.ts b/apps/web/app/api/cancel/route.ts index be30753fee..32bd1e8096 100644 --- a/apps/web/app/api/cancel/route.ts +++ b/apps/web/app/api/cancel/route.ts @@ -15,7 +15,7 @@ async function handler(req: NextRequest) { } catch (error) { return NextResponse.json({ success: false, message: "Invalid JSON" }, { status: 400 }); } - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); const result = await handleCancelBooking({ appDirRequestBody, userId: session?.user?.id || -1, diff --git a/apps/web/app/api/customer-card/route.ts b/apps/web/app/api/customer-card/route.ts index b4a1de8266..4f50541985 100644 --- a/apps/web/app/api/customer-card/route.ts +++ b/apps/web/app/api/customer-card/route.ts @@ -457,7 +457,7 @@ const inputSchema = z.object({ }); async function handler(request: NextRequest) { - const headersList = headers(); + const headersList = await headers(); const requestBody = await request.json(); // HMAC verification diff --git a/apps/web/app/api/defaultResponderForAppDir.test.ts b/apps/web/app/api/defaultResponderForAppDir.test.ts index 704d5a4c14..b30afb0dae 100644 --- a/apps/web/app/api/defaultResponderForAppDir.test.ts +++ b/apps/web/app/api/defaultResponderForAppDir.test.ts @@ -1,3 +1,4 @@ +import type { Params } from "app/_types"; import { NextResponse, type NextRequest } from "next/server"; import { describe, expect, it, vi } from "vitest"; @@ -21,7 +22,7 @@ describe("defaultResponderForAppDir", () => { it("should return a JSON response when handler resolves with a result", async () => { const f = vi.fn().mockResolvedValue(NextResponse.json({ success: true })); const req = { method: "GET", url: "/api/test" } as unknown as NextRequest; - const params = {}; + const params = Promise.resolve({}) const response = await defaultResponderForAppDir(f)(req, { params }); const json = await response.json(); @@ -33,7 +34,7 @@ describe("defaultResponderForAppDir", () => { it("should return an empty JSON response when handler resolves with no result", async () => { const f = vi.fn().mockResolvedValue(null); const req = { method: "GET", url: "/api/test" } as unknown as NextRequest; - const params = {}; + const params = Promise.resolve({}) const response = await defaultResponderForAppDir(f)(req, { params }); const json = await response.json(); @@ -45,7 +46,7 @@ describe("defaultResponderForAppDir", () => { it("should respond with status code 409 for NoAvailableUsersFound", async () => { const f = vi.fn().mockRejectedValue(new Error(ErrorCode.NoAvailableUsersFound)); const req = { method: "GET", url: "/api/test" } as unknown as NextRequest; - const params = {}; + const params = Promise.resolve({}) const response = await defaultResponderForAppDir(f)(req, { params }); const json = await response.json(); @@ -61,7 +62,7 @@ describe("defaultResponderForAppDir", () => { it("should respond with a 429 status code for rate limit errors", async () => { const f = vi.fn().mockRejectedValue(new TRPCError({ code: "TOO_MANY_REQUESTS" })); const req = { method: "POST", url: "/api/test" } as unknown as NextRequest; - const params = {}; + const params = Promise.resolve({}) const response = await defaultResponderForAppDir(f)(req, { params }); const json = await response.json(); diff --git a/apps/web/app/api/defaultResponderForAppDir.ts b/apps/web/app/api/defaultResponderForAppDir.ts index 1531254b55..7b72874ec2 100644 --- a/apps/web/app/api/defaultResponderForAppDir.ts +++ b/apps/web/app/api/defaultResponderForAppDir.ts @@ -9,14 +9,14 @@ import { performance } from "@calcom/lib/server/perfObserver"; type Handler = ( req: NextRequest, - { params }: { params: Params } + { params }: { params: Promise } ) => Promise; export const defaultResponderForAppDir = ( handler: Handler, endpointRoute?: string ) => { - return async (req: NextRequest, { params }: { params: Params }) => { + return async (req: NextRequest, { params }: { params: Promise }) => { let ok = false; try { performance.mark("Start"); diff --git a/apps/web/app/api/future-opt-in/route.ts b/apps/web/app/api/future-opt-in/route.ts deleted file mode 100644 index 86ebab38b7..0000000000 --- a/apps/web/app/api/future-opt-in/route.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir"; -import { cookies, headers } from "next/headers"; -import { NextResponse } from "next/server"; - -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; -import { FUTURE_ROUTES_OVERRIDE_COOKIE_NAME as COOKIE_NAME } from "@calcom/lib/constants"; - -import { buildLegacyRequest } from "@lib/buildLegacyCtx"; - -async function getHandler() { - const headersList = headers(); - const cookiesList = cookies(); - const legacyReq = buildLegacyRequest(headersList, cookiesList); - - const session = await getServerSession({ req: legacyReq }); - - if (!session || !session.user || !session.user.email) { - return NextResponse.json({ message: "Not authenticated" }, { status: 401 }); - } - - let redirectUrl = "/"; - - // We take you back where you came from if possible - const referer = headersList.get("referer"); - if (referer) redirectUrl = referer; - - const response = NextResponse.redirect(redirectUrl); - - // If has the cookie, Opt-out of V2 - if (cookiesList.has(COOKIE_NAME) && cookiesList.get(COOKIE_NAME)?.value === "1") { - response.cookies.set(COOKIE_NAME, "0", { maxAge: 0, path: "/" }); - } else { - /* Opt-in to V2 */ - response.cookies.set(COOKIE_NAME, "1", { path: "/" }); - } - - return response; -} - -export const GET = defaultResponderForAppDir(getHandler); diff --git a/apps/web/app/api/generate-referral-link/route.ts b/apps/web/app/api/generate-referral-link/route.ts index 6649b2c614..1390060a39 100644 --- a/apps/web/app/api/generate-referral-link/route.ts +++ b/apps/web/app/api/generate-referral-link/route.ts @@ -9,8 +9,8 @@ import prisma from "@calcom/prisma"; import { buildLegacyRequest } from "@lib/buildLegacyCtx"; async function postHandler() { - const headersList = headers(); - const cookiesList = cookies(); + const headersList = await headers(); + const cookiesList = await cookies(); const legacyReq = buildLegacyRequest(headersList, cookiesList); const session = await getServerSession({ req: legacyReq }); diff --git a/apps/web/app/api/geolocation/route.ts b/apps/web/app/api/geolocation/route.ts index 46c2b38587..1aa8215360 100644 --- a/apps/web/app/api/geolocation/route.ts +++ b/apps/web/app/api/geolocation/route.ts @@ -3,7 +3,7 @@ import { headers } from "next/headers"; import { NextResponse } from "next/server"; async function getHandler() { - const headersList = headers(); + const headersList = await headers(); const country = headersList.get("x-vercel-ip-country") || "Unknown"; const response = NextResponse.json({ country }); diff --git a/apps/web/app/api/intercom-hash/route.ts b/apps/web/app/api/intercom-hash/route.ts index 35d01feab2..403e517429 100644 --- a/apps/web/app/api/intercom-hash/route.ts +++ b/apps/web/app/api/intercom-hash/route.ts @@ -8,8 +8,8 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { buildLegacyRequest } from "@lib/buildLegacyCtx"; async function getHandler() { - const headersList = headers(); - const cookiesList = cookies(); + const headersList = await headers(); + const cookiesList = await cookies(); const legacyReq = buildLegacyRequest(headersList, cookiesList); const session = await getServerSession({ req: legacyReq }); diff --git a/apps/web/app/api/link/route.ts b/apps/web/app/api/link/route.ts index 1efc9b1e40..eea61cebb1 100644 --- a/apps/web/app/api/link/route.ts +++ b/apps/web/app/api/link/route.ts @@ -79,7 +79,7 @@ async function handler(request: NextRequest) { try { /** @see https://trpc.io/docs/server-side-calls */ // Create a legacy request object for compatibility - const legacyReq = buildLegacyRequest(headers(), cookies()); + const legacyReq = buildLegacyRequest(await headers(), await cookies()); const res = {} as any; // Response is still mocked as it's not used in this context const ctx = await createContext({ req: legacyReq, res }, sessionGetter); diff --git a/apps/web/app/api/logo/route.ts b/apps/web/app/api/logo/route.ts index 3fccb28427..8dd9fbd86d 100644 --- a/apps/web/app/api/logo/route.ts +++ b/apps/web/app/api/logo/route.ts @@ -168,7 +168,7 @@ async function getHandler(request: NextRequest) { const parsedQuery = logoApiSchema.parse(Object.fromEntries(searchParams.entries())); // Create a legacy request object for compatibility - const legacyReq = buildLegacyRequest(headers(), cookies()); + const legacyReq = buildLegacyRequest(await headers(), await cookies()); const { isValidOrgDomain } = orgDomainConfig(legacyReq); const hostname = request.headers.get("host"); diff --git a/apps/web/app/api/me/route.ts b/apps/web/app/api/me/route.ts index 7e8d816d05..55761a3bed 100644 --- a/apps/web/app/api/me/route.ts +++ b/apps/web/app/api/me/route.ts @@ -15,7 +15,7 @@ async function getHandler() { const preSessionDate = performance.now(); // Create a legacy request object for compatibility - const legacyReq = buildLegacyRequest(headers(), cookies()); + const legacyReq = buildLegacyRequest(await headers(), await cookies()); const session = await getServerSession({ req: legacyReq }); if (!session) { diff --git a/apps/web/app/api/plain-hash/route.ts b/apps/web/app/api/plain-hash/route.ts index 2ff7bca488..6a239a7c5f 100644 --- a/apps/web/app/api/plain-hash/route.ts +++ b/apps/web/app/api/plain-hash/route.ts @@ -26,7 +26,7 @@ async function handler() { return NextResponse.json({ error: "Plain Chat is not enabled" }, { status: 404 }); } - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); if (!session?.user?.email) { return NextResponse.json({ error: "Unauthorized - No session email found" }, { status: 401 }); } diff --git a/apps/web/app/api/recorded-daily-video/route.ts b/apps/web/app/api/recorded-daily-video/route.ts index fd583fd185..72e8c92c90 100644 --- a/apps/web/app/api/recorded-daily-video/route.ts +++ b/apps/web/app/api/recorded-daily-video/route.ts @@ -62,7 +62,7 @@ export async function postHandler(request: NextRequest) { return NextResponse.json({ message: "Test request successful" }); } - const headersList = headers(); + const headersList = await headers(); const testMode = process.env.NEXT_PUBLIC_IS_E2E || process.env.INTEGRATION_TEST_MODE; if (!testMode) { diff --git a/apps/web/app/api/scim/v2.0/[...directory]/route.ts b/apps/web/app/api/scim/v2.0/[...directory]/route.ts index eb52d8433f..b4f27291c3 100644 --- a/apps/web/app/api/scim/v2.0/[...directory]/route.ts +++ b/apps/web/app/api/scim/v2.0/[...directory]/route.ts @@ -1,7 +1,9 @@ import type { DirectorySyncEvent, DirectorySyncRequest } from "@boxyhq/saml-jackson"; +import type { Params } from "app/_types"; import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir"; import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; +import { z } from "zod"; import handleGroupEvents from "@calcom/features/ee/dsync/lib/handleGroupEvents"; import handleUserEvents from "@calcom/features/ee/dsync/lib/handleUserEvents"; @@ -51,35 +53,40 @@ const handleEvents = async (event: DirectorySyncEvent) => { } }; +const querySchema = z.object({ + directory: z.string().array(), +}); + // This is the handler for the SCIM API requests -async function getHandler(request: NextRequest, { params }: { params: { directory?: string[] } }) { - return handleScimRequest(request, "GET", params.directory); +async function getHandler(request: NextRequest, { params }: { params: Promise }) { + return handleScimRequest(request, "GET", params); } -async function postHandler(request: NextRequest, { params }: { params: { directory?: string[] } }) { - return handleScimRequest(request, "POST", params.directory); +async function postHandler(request: NextRequest, { params }: { params: Promise }) { + return handleScimRequest(request, "POST", params); } -async function putHandler(request: NextRequest, { params }: { params: { directory?: string[] } }) { - return handleScimRequest(request, "PUT", params.directory); +async function putHandler(request: NextRequest, { params }: { params: Promise }) { + return handleScimRequest(request, "PUT", params); } -async function patchHandler(request: NextRequest, { params }: { params: { directory?: string[] } }) { - return handleScimRequest(request, "PATCH", params.directory); +async function patchHandler(request: NextRequest, { params }: { params: Promise }) { + return handleScimRequest(request, "PATCH", params); } -async function deleteHandler(request: NextRequest, { params }: { params: { directory?: string[] } }) { - return handleScimRequest(request, "DELETE", params.directory); +async function deleteHandler(request: NextRequest, { params }: { params: Promise }) { + return handleScimRequest(request, "DELETE", params); } -async function handleScimRequest(request: NextRequest, method: string, directoryParams?: string[]) { - const { dsyncController } = await jackson(); - - if (!directoryParams || directoryParams.length === 0) { +async function handleScimRequest(request: NextRequest, method: string, params: Promise) { + const parsed = querySchema.safeParse(await params); + if (!parsed.success || parsed.data.directory.length === 0) { return NextResponse.json({ error: "Missing directory parameters" }, { status: 400 }); } - const [directoryId, path, resourceId] = directoryParams; + const { dsyncController } = await jackson(); + + const [directoryId, path, resourceId] = parsed.data.directory; const shouldLog = DIRECTORY_IDS_TO_LOG.includes(directoryId); const searchParams = request.nextUrl.searchParams; @@ -90,7 +97,7 @@ async function handleScimRequest(request: NextRequest, method: string, directory safeStringify({ method, url: request.url, - params: directoryParams, + params: parsed.data.directory, searchParams: Object.fromEntries(searchParams.entries()), body: request.body ? await request diff --git a/apps/web/app/api/social/og/image/route.tsx b/apps/web/app/api/social/og/image/route.tsx index 0f171742f0..6e100d795b 100644 --- a/apps/web/app/api/social/og/image/route.tsx +++ b/apps/web/app/api/social/og/image/route.tsx @@ -1,19 +1,11 @@ +import { ImageResponse } from "next/og"; import type { NextRequest } from "next/server"; -import { ImageResponse } from "next/server"; import type { SatoriOptions } from "satori"; import { z } from "zod"; import { Meeting, App, Generic } from "@calcom/lib/OgImages"; import { WEBAPP_URL } from "@calcom/lib/constants"; -const calFont = fetch(new URL("/fonts/cal.ttf", WEBAPP_URL)).then((res) => res.arrayBuffer()); - -const interFont = fetch(new URL("/fonts/Inter-Regular.ttf", WEBAPP_URL)).then((res) => res.arrayBuffer()); - -const interFontMedium = fetch(new URL("/fonts/Inter-Medium.ttf", WEBAPP_URL)).then((res) => - res.arrayBuffer() -); - export const runtime = "edge"; const meetingSchema = z.object({ @@ -43,9 +35,9 @@ async function handler(req: NextRequest) { const imageType = searchParams.get("type"); const [calFontData, interFontData, interFontMediumData] = await Promise.all([ - calFont, - interFont, - interFontMedium, + fetch(new URL("/fonts/cal.ttf", WEBAPP_URL)).then((res) => res.arrayBuffer()), + fetch(new URL("/fonts/Inter-Regular.ttf", WEBAPP_URL)).then((res) => res.arrayBuffer()), + fetch(new URL("/fonts/Inter-Medium.ttf", WEBAPP_URL)).then((res) => res.arrayBuffer()), ]); const ogConfig = { width: 1200, diff --git a/apps/web/app/api/sync/helpscout/route.ts b/apps/web/app/api/sync/helpscout/route.ts index c8ad361de0..1b4f5f0a9b 100644 --- a/apps/web/app/api/sync/helpscout/route.ts +++ b/apps/web/app/api/sync/helpscout/route.ts @@ -29,7 +29,7 @@ async function postHandler(request: NextRequest) { if (!process.env.CALENDSO_ENCRYPTION_KEY) return NextResponse.json({ message: "Missing encryption key" }, { status: 500 }); - const legacyRequest = buildLegacyRequest(headers(), cookies()); + const legacyRequest = buildLegacyRequest(await headers(), await cookies()); // Get the raw request body const rawBody = await getRawBody(legacyRequest); diff --git a/apps/web/app/api/teams/[team]/upgrade/route.ts b/apps/web/app/api/teams/[team]/upgrade/route.ts index cd0ebcec36..1f8b2eef01 100644 --- a/apps/web/app/api/teams/[team]/upgrade/route.ts +++ b/apps/web/app/api/teams/[team]/upgrade/route.ts @@ -21,11 +21,11 @@ const querySchema = z.object({ session_id: z.string().min(1), }); -async function getHandler(req: NextRequest, { params }: { params: Params }) { +async function getHandler(req: NextRequest, { params }: { params: Promise }) { try { const searchParams = req.nextUrl.searchParams; const { team: id, session_id } = querySchema.parse({ - team: params.team, + team: (await params).team, session_id: searchParams.get("session_id"), }); @@ -86,7 +86,7 @@ async function getHandler(req: NextRequest, { params }: { params: Params }) { } } - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); if (!session) { return NextResponse.json({ message: "Team upgraded successfully" }); diff --git a/apps/web/app/api/teams/googleworkspace/callback/route.ts b/apps/web/app/api/teams/googleworkspace/callback/route.ts index b17b9adb22..89c72311a7 100644 --- a/apps/web/app/api/teams/googleworkspace/callback/route.ts +++ b/apps/web/app/api/teams/googleworkspace/callback/route.ts @@ -20,8 +20,8 @@ const stateSchema = z.object({ async function getHandler(request: NextRequest) { try { - const headersList = headers(); - const cookiesList = cookies(); + const headersList = await headers(); + const cookiesList = await cookies(); const legacyReq = buildLegacyRequest(headersList, cookiesList); const session = await getServerSession({ req: legacyReq }); diff --git a/apps/web/app/api/username/route.ts b/apps/web/app/api/username/route.ts index 10d123ecc5..26e399e692 100644 --- a/apps/web/app/api/username/route.ts +++ b/apps/web/app/api/username/route.ts @@ -19,7 +19,7 @@ async function postHandler(request: NextRequest) { const body = await request.json(); const { username, orgSlug } = bodySchema.parse(body); - const legacyReq = buildLegacyRequest(headers(), cookies()); + const legacyReq = buildLegacyRequest(await headers(), await cookies()); // Get current org domain from request headers const { currentOrgDomain } = orgDomainConfig(legacyReq); diff --git a/apps/web/app/api/verify-booking-token/route.ts b/apps/web/app/api/verify-booking-token/route.ts index 5fcba32d2f..3ecf29775d 100644 --- a/apps/web/app/api/verify-booking-token/route.ts +++ b/apps/web/app/api/verify-booking-token/route.ts @@ -118,7 +118,7 @@ async function handleBookingAction( const createCaller = createCallerFactory(bookingsRouter); // Use buildLegacyRequest to create a request object compatible with Pages Router - const legacyReq = request ? buildLegacyRequest(headers(), cookies()) : ({} as any); + const legacyReq = request ? buildLegacyRequest(await headers(), await cookies()) : ({} as any); const res = {} as any; const ctx = await createContext({ req: legacyReq, res }, sessionGetter); diff --git a/apps/web/app/icons/page.tsx b/apps/web/app/icons/page.tsx index e8203e3aa4..e23250edc1 100644 --- a/apps/web/app/icons/page.tsx +++ b/apps/web/app/icons/page.tsx @@ -44,4 +44,3 @@ export default async function IconsPage() { ); } -export const dynamic = "force-static"; diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index e903ed22c6..1744aeed95 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -9,7 +9,6 @@ import { IconSprites } from "@calcom/ui/components/icon"; import { NotificationSoundHandler } from "@calcom/web/components/notification-sound-handler"; import { buildLegacyCtx } from "@lib/buildLegacyCtx"; -import { prepareRootMetadata } from "@lib/metadata"; import { ssrInit } from "@server/lib/ssr"; @@ -26,7 +25,60 @@ const calFont = localFont({ weight: "600", }); -export const generateMetadata = () => prepareRootMetadata(); +export const viewport = { + width: "device-width", + initialScale: 1.0, + maximumScale: 1.0, + userScalable: false, + viewportFit: "cover", + themeColor: [ + { + media: "(prefers-color-scheme: light)", + color: "#f9fafb", + }, + { + media: "(prefers-color-scheme: dark)", + color: "#1C1C1C", + }, + ], +}; + +export const metadata = { + icons: { + icon: "/favicon.ico", + apple: "/api/logo?type=apple-touch-icon", + other: [ + { + rel: "icon-mask", + url: "/safari-pinned-tab.svg", + color: "#000000", + }, + { + url: "/api/logo?type=favicon-16", + sizes: "16x16", + type: "image/png", + }, + { + url: "/api/logo?type=favicon-32", + sizes: "32x32", + type: "image/png", + }, + ], + }, + manifest: "/site.webmanifest", + other: { + "application-TileColor": "#ff0000", + }, + twitter: { + site: "@calcom", + creator: "@calcom", + card: "summary_large_image", + }, + robots: { + index: true, + follow: true, + }, +}; const getInitialProps = async (url: string) => { const { pathname, searchParams } = new URL(url); @@ -34,7 +86,7 @@ const getInitialProps = async (url: string) => { const isEmbed = pathname.endsWith("/embed") || (searchParams?.get("embedType") ?? null) !== null; const embedColorScheme = searchParams?.get("ui.color-scheme"); - const req = { headers: headers(), cookies: cookies() }; + const req = { headers: await headers(), cookies: await cookies() }; const newLocale = await getLocale(req); const direction = dir(newLocale); @@ -49,7 +101,7 @@ const getFallbackProps = () => ({ }); export default async function RootLayout({ children }: { children: React.ReactNode }) { - const h = headers(); + const h = await headers(); const fullUrl = h.get("x-url") ?? ""; const nonce = h.get("x-csp") ?? ""; @@ -60,7 +112,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo ? getFallbackProps() : await getInitialProps(fullUrl); - const ssr = await ssrInit(buildLegacyCtx(h, cookies(), {}, {})); + const ssr = await ssrInit(buildLegacyCtx(h, await cookies(), {}, {})); return ( { - const headersList = headers(); + const headersList = await headers(); const pathname = headersList.get("x-pathname") ?? ""; const isInsights = pathname?.startsWith("/insights"); @@ -243,7 +243,7 @@ export const generateMetadata = async () => { const ServerPage = async () => { const t = await getTranslate(); - const h = headers(); + const h = await headers(); const nonce = h.get("x-nonce") ?? undefined; return ( diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 6af803e9b2..95d99df6d9 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -6,7 +6,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { buildLegacyRequest } from "@lib/buildLegacyCtx"; const RedirectPage = async () => { - const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) }); + const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) }); if (!session?.user?.id) { redirect("/auth/login"); diff --git a/apps/web/app/reschedule/[uid]/embed/page.tsx b/apps/web/app/reschedule/[uid]/embed/page.tsx index efc98cafb0..676f3ce290 100644 --- a/apps/web/app/reschedule/[uid]/embed/page.tsx +++ b/apps/web/app/reschedule/[uid]/embed/page.tsx @@ -8,7 +8,7 @@ import { getServerSideProps } from "@lib/reschedule/[uid]/getServerSideProps"; const getEmbedData = withEmbedSsrAppDir(getServerSideProps); const Page = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); await getEmbedData(legacyCtx); return null; diff --git a/apps/web/app/reschedule/[uid]/page.tsx b/apps/web/app/reschedule/[uid]/page.tsx index 4e03ebe7a4..3ae0f6ab53 100644 --- a/apps/web/app/reschedule/[uid]/page.tsx +++ b/apps/web/app/reschedule/[uid]/page.tsx @@ -8,7 +8,7 @@ import { getServerSideProps } from "@lib/reschedule/[uid]/getServerSideProps"; const getData = withAppDirSsr(getServerSideProps); const Page = async ({ params, searchParams }: PageProps) => { - const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams); + const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams); await getData(legacyCtx); diff --git a/apps/web/app/routing-forms/[...pages]/page.tsx b/apps/web/app/routing-forms/[...pages]/page.tsx index ead2d36f73..7e8a156724 100644 --- a/apps/web/app/routing-forms/[...pages]/page.tsx +++ b/apps/web/app/routing-forms/[...pages]/page.tsx @@ -10,7 +10,7 @@ const paramsSchema = z pages: [], }); -export default function RoutingForms({ params }: PageProps) { - const { pages } = paramsSchema.parse(params); +export default async function RoutingForms({ params }: PageProps) { + const { pages } = paramsSchema.parse(await params); redirect(`/apps/routing-forms/${pages.length ? pages.join("/") : ""}`); } diff --git a/apps/web/components/PageWrapperAppDir.tsx b/apps/web/components/PageWrapperAppDir.tsx index 5628bee5be..53c9850fc6 100644 --- a/apps/web/components/PageWrapperAppDir.tsx +++ b/apps/web/components/PageWrapperAppDir.tsx @@ -1,6 +1,6 @@ "use client"; -import type { SSRConfig } from "next-i18next"; +import type { SSRConfig } from "next-i18next/dist/types/types"; // import I18nLanguageHandler from "@components/I18nLanguageHandler"; import { usePathname } from "next/navigation"; import Script from "next/script"; diff --git a/apps/web/components/ServerTrans.tsx b/apps/web/components/ServerTrans.tsx new file mode 100644 index 0000000000..2cf5e08721 --- /dev/null +++ b/apps/web/components/ServerTrans.tsx @@ -0,0 +1,376 @@ +import type { TFunction } from "i18next"; +import type { ReactNode, ReactElement, FC } from "react"; +import React, { isValidElement, Fragment, createElement, cloneElement } from "react"; + +type ServerTransProps = { + i18nKey: string; // Translation key + components?: ReactElement[] | Record; // Components to inject + t: TFunction; + values?: Record; // Values for interpolation + children?: ReactNode; // Children as fallback content + parent?: React.ElementType; // Parent element to wrap content in +}; + +/** + * A custom Trans component that doesn't use React Context + * Handles HTML tags and component interpolation in translations + */ +const ServerTrans: FC = ({ + i18nKey, + components = [], + t, + values = {}, + children, + parent, +}) => { + const translationOptions = { ...values }; + // Get translated content + const content = t(i18nKey, translationOptions); + + // If no content at all, use children as fallback + if (!content && children) { + return <>{children}; + } + + // If no content, return empty fragment + if (!content) { + return <>; + } + + let result: ReactNode[]; + + // Process array-based components like <0>content + if (Array.isArray(components) && components.length > 0) { + result = parseArrayComponents(content, components); + } + // Process object-based components like content or {{tag}} + else if (isObject(components) && Object.keys(components).length > 0) { + result = parseObjectComponents(content, components as Record); + } + // Process just HTML tags + else { + result = parseHtmlTags(content); + } + + // Wrap in parent element if specified + if (parent) { + const Parent = parent; + return {result}; + } + + return <>{result}; +}; + +// Utility function to check if object +const isObject = (obj: any): obj is Record => + obj !== null && typeof obj === "object" && !Array.isArray(obj); + +// Parse array-based components like <0>content +const parseArrayComponents = (content: string, components: ReactElement[]): ReactNode[] => { + const parts: ReactNode[] = []; + let currentText = ""; + + // Simple state machine parser to handle nested tags + const parseContent = (text: string) => { + for (let i = 0; i < text.length; i++) { + // Look for opening tag + if (text[i] === "<" && /\d/.test(text[i + 1])) { + // Found potential component tag + let tagIndex = ""; + let j = i + 1; + + // Read the tag index + while (j < text.length && /\d/.test(text[j])) { + tagIndex += text[j]; + j++; + } + + // Check if it's a valid tag + if (j < text.length && text[j] === ">") { + // It's an opening tag, save text before it + if (currentText) { + // Process any HTML in the text + parts.push(...parseHtmlTags(currentText)); + currentText = ""; + } + + // Get the content inside the tag + const closingTag = ``; + const tagContent = getTextBetweenTags(text.substring(j + 1), tagIndex); + + if (tagContent !== null) { + // We found the content, now add the component + const componentIndex = parseInt(tagIndex, 10); + + if (componentIndex < components.length) { + const component = components[componentIndex]; + + if (isValidElement(component)) { + // Add the component with its content + parts.push( + cloneElement( + component, + { + ...(component.props || {}), + key: component.key || `comp-${componentIndex}`, + }, + // Process any HTML in the inner content + ...parseHtmlTags(tagContent) + ) + ); + } else { + // If not a valid element, just add the content + parts.push(...parseHtmlTags(tagContent)); + } + } else { + // Component index out of bounds, just add the content + parts.push(...parseHtmlTags(tagContent)); + } + + // Skip to after the closing tag + i = j + tagContent.length + closingTag.length; + continue; + } + } + } + + // Regular character, add to current text + currentText += text[i]; + } + + // Add any remaining text + if (currentText) { + parts.push(...parseHtmlTags(currentText)); + } + }; + + // Helper to find matching content between tags + const getTextBetweenTags = (text: string, tagIndex: string): string | null => { + let depth = 1; + let content = ""; + + for (let i = 0; i < text.length; i++) { + // Check for nested opening tag + if ( + text[i] === "<" && + text.substring(i + 1, i + 1 + tagIndex.length) === tagIndex && + text[i + 1 + tagIndex.length] === ">" + ) { + depth++; + content += text.substring(i, i + 2 + tagIndex.length); + i += 1 + tagIndex.length; + continue; + } + + // Check for closing tag + if ( + text[i] === "<" && + text.substring(i + 1, i + 2 + tagIndex.length) === `/${tagIndex}` && + text[i + 2 + tagIndex.length] === ">" + ) { + depth--; + + if (depth === 0) { + // Found the matching closing tag + return content; + } + + content += text.substring(i, i + 3 + tagIndex.length); + i += 2 + tagIndex.length; + continue; + } + + content += text[i]; + } + + return null; // No matching closing tag found + }; + + // Parse the content + parseContent(content); + + return parts.length > 0 ? parts : [content]; +}; + +// Parse object-based components like content or {{tag}} +const parseObjectComponents = (content: string, components: Record): ReactNode[] => { + let processedContent = content; + const placeholders: Record = {}; + + // First handle {{tag}} interpolation + Object.keys(components).forEach((tag) => { + const interpolationRegex = new RegExp(`{{\\s*${tag}\\s*}}`, "g"); + processedContent = processedContent.replace(interpolationRegex, (match) => { + const placeholder = `__INTERP_${tag}_${Math.random().toString(36).substring(2)}__`; + + if (isValidElement(components[tag])) { + placeholders[placeholder] = cloneElement(components[tag], { + ...(components[tag].props || {}), + key: components[tag].key || `interp-${tag}`, + }); + } + + return placeholder; + }); + }); + + // Then handle content + Object.keys(components).forEach((tag) => { + const tagRegex = new RegExp(`<${tag}>(.*?)<\\/${tag}>`, "gs"); + + processedContent = processedContent.replace(tagRegex, (match, content) => { + const placeholder = `__TAG_${tag}_${Math.random().toString(36).substring(2)}__`; + + if (isValidElement(components[tag])) { + // Process any HTML in the content + const parsedContent = parseHtmlTags(content); + + placeholders[placeholder] = cloneElement( + components[tag], + { + ...(components[tag].props || {}), + key: components[tag].key || `tag-${tag}`, + }, + ...(parsedContent.length > 1 ? parsedContent : [content]) + ); + } + + return placeholder; + }); + }); + + // Replace placeholders with components and split text parts + const parts: ReactNode[] = []; + let lastIndex = 0; + + // Find all placeholders in order + const placeholderRegex = /__(?:INTERP|TAG)_[^_]+_[a-z0-9]+__/g; + let match; + + while ((match = placeholderRegex.exec(processedContent)) !== null) { + const [placeholder] = match; + const index = match.index; + + // Add text before placeholder + if (index > lastIndex) { + const textBefore = processedContent.substring(lastIndex, index); + parts.push(...parseHtmlTags(textBefore)); + } + + // Add the component + if (placeholders[placeholder]) { + parts.push(placeholders[placeholder]); + } + + lastIndex = index + placeholder.length; + } + + // Add any remaining text + if (lastIndex < processedContent.length) { + const textAfter = processedContent.substring(lastIndex); + parts.push(...parseHtmlTags(textAfter)); + } + + return parts.length > 0 ? parts : [processedContent]; +}; + +// Parse HTML tags like content +const parseHtmlTags = (content: string): ReactNode[] => { + if (!content || typeof content !== "string") { + return [content].filter(Boolean); + } + + // Check if there are any HTML tags + if (!/<[a-z][\s\S]*>/i.test(content)) { + return [content]; + } + + // HTML tags to process + const htmlTags = [ + { tag: "strong", component: "strong" }, + { tag: "b", component: "b" }, + { tag: "i", component: "i" }, + { tag: "em", component: "em" }, + { tag: "p", component: "p" }, + { tag: "br", component: "br", selfClosing: true }, + { tag: "div", component: "div" }, + { tag: "span", component: "span" }, + { tag: "ul", component: "ul" }, + { tag: "ol", component: "ol" }, + { tag: "li", component: "li" }, + ]; + + let processedContent = content; + const placeholders: Record = {}; + + // Process each HTML tag + htmlTags.forEach(({ tag, component, selfClosing }) => { + if (selfClosing) { + // Handle self-closing tags like
+ const selfClosingRegex = new RegExp(`<${tag}\\s*\\/>`, "g"); + + processedContent = processedContent.replace(selfClosingRegex, (match) => { + const placeholder = `__HTML_${tag}_${Math.random().toString(36).substring(2)}__`; + placeholders[placeholder] = createElement(component, { key: placeholder }); + return placeholder; + }); + } else { + // Handle regular tags like content + const tagRegex = new RegExp(`<${tag}>(.*?)<\\/${tag}>`, "gs"); + + processedContent = processedContent.replace(tagRegex, (match, content) => { + const placeholder = `__HTML_${tag}_${Math.random().toString(36).substring(2)}__`; + + // Process nested tags recursively + const innerContent = parseHtmlTags(content); + + placeholders[placeholder] = createElement( + component, + { key: placeholder }, + ...(innerContent.length > 1 ? innerContent : [content]) + ); + + return placeholder; + }); + } + }); + + // If no tags were processed, return the original content + if (Object.keys(placeholders).length === 0) { + return [processedContent]; + } + + // Replace placeholders with components and split text parts + const parts: ReactNode[] = []; + let lastIndex = 0; + + // Find all placeholders in order + const placeholderRegex = /__HTML_[^_]+_[a-z0-9]+__/g; + let match; + + while ((match = placeholderRegex.exec(processedContent)) !== null) { + const [placeholder] = match; + const index = match.index; + + // Add text before placeholder + if (index > lastIndex) { + parts.push(processedContent.substring(lastIndex, index)); + } + + // Add the component + if (placeholders[placeholder]) { + parts.push(placeholders[placeholder]); + } + + lastIndex = index + placeholder.length; + } + + // Add any remaining text + if (lastIndex < processedContent.length) { + parts.push(processedContent.substring(lastIndex)); + } + + return parts.length > 0 ? parts : [processedContent]; +}; + +export default ServerTrans; diff --git a/apps/web/components/booking/CancelBooking.tsx b/apps/web/components/booking/CancelBooking.tsx index 50ab22eaaa..851a713f38 100644 --- a/apps/web/components/booking/CancelBooking.tsx +++ b/apps/web/components/booking/CancelBooking.tsx @@ -1,9 +1,12 @@ +"use client"; + import { useCallback, useState } from "react"; import { sdkActionManager } from "@calcom/embed-core/embed-iframe"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useRefreshData } from "@calcom/lib/hooks/useRefreshData"; -import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; +import { collectPageParameters, telemetryEventTypes } from "@calcom/lib/telemetry"; import type { RecurringEvent } from "@calcom/types/Calendar"; import { Button } from "@calcom/ui/components/button"; import { Label, Select, TextArea } from "@calcom/ui/components/form"; diff --git a/apps/web/components/getting-started/steps-views/UserProfile.tsx b/apps/web/components/getting-started/steps-views/UserProfile.tsx index edfa63946f..49033b8ae0 100644 --- a/apps/web/components/getting-started/steps-views/UserProfile.tsx +++ b/apps/web/components/getting-started/steps-views/UserProfile.tsx @@ -1,10 +1,13 @@ +"use client"; + import { useRouter } from "next/navigation"; import { useRef, useState } from "react"; import { useForm } from "react-hook-form"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; import { md } from "@calcom/lib/markdownIt"; -import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { telemetryEventTypes } from "@calcom/lib/telemetry"; import turndown from "@calcom/lib/turndownService"; import { trpc } from "@calcom/trpc/react"; import { UserAvatar } from "@calcom/ui/components/avatar"; diff --git a/apps/web/components/getting-started/steps-views/UserSettings.tsx b/apps/web/components/getting-started/steps-views/UserSettings.tsx index a016ab7dc7..a40a39e713 100644 --- a/apps/web/components/getting-started/steps-views/UserSettings.tsx +++ b/apps/web/components/getting-started/steps-views/UserSettings.tsx @@ -1,3 +1,5 @@ +"use client"; + import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; @@ -8,7 +10,8 @@ import { useTimePreferences } from "@calcom/features/bookings/lib"; import { TimezoneSelect } from "@calcom/features/components/timezone-select"; import { FULL_NAME_LENGTH_MAX_LIMIT } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; +import { telemetryEventTypes } from "@calcom/lib/telemetry"; import { trpc } from "@calcom/trpc/react"; import { Input } from "@calcom/ui/components/form"; import { Button } from "@calcom/ui/components/button"; diff --git a/apps/web/components/settings/SecondaryEmailConfirmModal.tsx b/apps/web/components/settings/SecondaryEmailConfirmModal.tsx index 38e40c9495..189bb6020e 100644 --- a/apps/web/components/settings/SecondaryEmailConfirmModal.tsx +++ b/apps/web/components/settings/SecondaryEmailConfirmModal.tsx @@ -1,7 +1,6 @@ -import { Trans } from "react-i18next"; - import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Dialog, DialogContent, DialogFooter, DialogClose } from "@calcom/ui/components/dialog"; +import ServerTrans from "@calcom/web/components/ServerTrans"; interface SecondaryEmailConfirmModalProps { email: string; @@ -15,7 +14,7 @@ const SecondaryEmailConfirmModal = ({ email, onCancel }: SecondaryEmailConfirmMo } + description={} type="creation" data-testid="secondary-email-confirm-dialog"> diff --git a/apps/web/lib/app-providers-app-dir.tsx b/apps/web/lib/app-providers-app-dir.tsx index f27474d761..c0110e50f5 100644 --- a/apps/web/lib/app-providers-app-dir.tsx +++ b/apps/web/lib/app-providers-app-dir.tsx @@ -3,8 +3,8 @@ import { dir } from "i18next"; import type { Session } from "next-auth"; import { useSession } from "next-auth/react"; import { EventCollectionProvider } from "next-collect/client"; -import type { SSRConfig } from "next-i18next"; import { appWithTranslation } from "next-i18next"; +import type { SSRConfig } from "next-i18next/dist/types/types"; import { ThemeProvider } from "next-themes"; import type { AppProps as NextAppProps, AppProps as NextJsAppProps } from "next/app"; import type { ReadonlyURLSearchParams } from "next/navigation"; diff --git a/apps/web/lib/app-providers.tsx b/apps/web/lib/app-providers.tsx index 2d926f54bd..0e5e085218 100644 --- a/apps/web/lib/app-providers.tsx +++ b/apps/web/lib/app-providers.tsx @@ -3,8 +3,8 @@ import { dir } from "i18next"; import type { Session } from "next-auth"; import { useSession } from "next-auth/react"; import { EventCollectionProvider } from "next-collect/client"; -import type { SSRConfig } from "next-i18next"; import { appWithTranslation } from "next-i18next"; +import type { SSRConfig } from "next-i18next/dist/types/types"; import { ThemeProvider } from "next-themes"; import type { AppProps as NextAppProps, AppProps as NextJsAppProps } from "next/app"; import dynamic from "next/dynamic"; diff --git a/apps/web/lib/apps/installation/[[...step]]/getServerSideProps.ts b/apps/web/lib/apps/installation/[[...step]]/getServerSideProps.ts index 55990675fc..13525879d0 100644 --- a/apps/web/lib/apps/installation/[[...step]]/getServerSideProps.ts +++ b/apps/web/lib/apps/installation/[[...step]]/getServerSideProps.ts @@ -1,6 +1,4 @@ -import { Prisma } from "@prisma/client"; import type { GetServerSidePropsContext } from "next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { z } from "zod"; import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData"; @@ -13,6 +11,7 @@ import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage"; import type { LocationObject } from "@calcom/lib/location"; import { UserRepository } from "@calcom/lib/server/repository/user"; import prisma from "@calcom/prisma"; +import { Prisma } from "@calcom/prisma/client"; import { eventTypeBookingFields } from "@calcom/prisma/zod-utils"; import { STEPS } from "~/apps/installation/[[...step]]/constants"; @@ -307,7 +306,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => return { props: { - ...(await serverSideTranslations(locale, ["common"])), app, appMetadata, showEventTypesStep, diff --git a/apps/web/lib/apps/routing-forms/[...pages]/getServerSideProps.ts b/apps/web/lib/apps/routing-forms/[...pages]/getServerSideProps.ts index 0afed87af6..a4c7392014 100644 --- a/apps/web/lib/apps/routing-forms/[...pages]/getServerSideProps.ts +++ b/apps/web/lib/apps/routing-forms/[...pages]/getServerSideProps.ts @@ -2,7 +2,7 @@ import type { GetServerSidePropsResult, GetServerSidePropsContext } from "next"; import { z } from "zod"; import { getAppWithMetadata } from "@calcom/app-store/_appRegistry"; -import { routingServerSidePropsConfig } from "@calcom/app-store/routing-forms/pages/app-routing.config"; +import { routingServerSidePropsConfig } from "@calcom/app-store/routing-forms/pages/app-routing.server-config"; import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import prisma from "@calcom/prisma"; import type { AppGetServerSidePropsContext } from "@calcom/types/AppGetServerSideProps"; diff --git a/apps/web/lib/daily-webhook/tests/recorded-daily-video.test.ts b/apps/web/lib/daily-webhook/tests/recorded-daily-video.test.ts index 672fda8317..f55cc06ebd 100644 --- a/apps/web/lib/daily-webhook/tests/recorded-daily-video.test.ts +++ b/apps/web/lib/daily-webhook/tests/recorded-daily-video.test.ts @@ -161,10 +161,7 @@ function createNextRequest(mockReq: ReturnType["req"]): Next }); // Create a NextRequest from the Request - const nextRequest = new NextRequest(request, { - ip: mockReq.socket?.remoteAddress || "127.0.0.1", - geo: { city: "", country: "", region: "" }, - }); + const nextRequest = new NextRequest(request); return nextRequest; } diff --git a/apps/web/lib/getting-started/[[...step]]/getServerSideProps.tsx b/apps/web/lib/getting-started/[[...step]]/getServerSideProps.tsx index b45b011c32..c64231bcea 100644 --- a/apps/web/lib/getting-started/[[...step]]/getServerSideProps.tsx +++ b/apps/web/lib/getting-started/[[...step]]/getServerSideProps.tsx @@ -1,5 +1,4 @@ import type { GetServerSidePropsContext } from "next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { getLocale } from "@calcom/features/auth/lib/getLocale"; import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; @@ -31,7 +30,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => const locale = await getLocale(context.req); return { props: { - ...(await serverSideTranslations(locale || "en", ["common"])), trpcState: ssr.dehydrate(), hasPendingInvites: user.teams.find((team) => team.accepted === false) ?? false, }, diff --git a/apps/web/lib/metadata.ts b/apps/web/lib/metadata.ts deleted file mode 100644 index 749d54e06c..0000000000 --- a/apps/web/lib/metadata.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { Metadata } from "next"; - -export type PageMetadataRecipe = Readonly<{ - title: string; - canonical: string; - image: string; - description: string; - siteName: string; - metadataBase: URL; -}>; - -export const prepareRootMetadata = (): Metadata => ({ - icons: { - icon: "/favicon.ico", - apple: "/api/logo?type=apple-touch-icon", - other: [ - { - rel: "icon-mask", - url: "/safari-pinned-tab.svg", - color: "#000000", - }, - { - url: "/api/logo?type=favicon-16", - sizes: "16x16", - type: "image/png", - }, - { - url: "/api/logo?type=favicon-32", - sizes: "32x32", - type: "image/png", - }, - ], - }, - manifest: "/site.webmanifest", - viewport: { - width: "device-width", - initialScale: 1.0, - maximumScale: 1.0, - userScalable: false, - viewportFit: "cover", - }, - other: { - "application-TileColor": "#ff0000", - }, - themeColor: [ - { - media: "(prefers-color-scheme: light)", - color: "#f9fafb", - }, - { - media: "(prefers-color-scheme: dark)", - color: "#1C1C1C", - }, - ], - twitter: { - site: "@calcom", - creator: "@calcom", - card: "summary_large_image", - }, - robots: { - index: true, - follow: true, - }, -}); diff --git a/apps/web/lib/reschedule/[uid]/getServerSideProps.ts b/apps/web/lib/reschedule/[uid]/getServerSideProps.ts index 4fe7c5a5b2..0e930f06dd 100644 --- a/apps/web/lib/reschedule/[uid]/getServerSideProps.ts +++ b/apps/web/lib/reschedule/[uid]/getServerSideProps.ts @@ -4,9 +4,9 @@ import { URLSearchParams } from "url"; import { z } from "zod"; import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; -import { getSafe } from "@calcom/lib/bookingSuccessRedirect"; import { buildEventUrlFromBooking } from "@calcom/lib/bookings/buildEventUrlFromBooking"; import { getDefaultEvent } from "@calcom/lib/defaultEvents"; +import { getSafe } from "@calcom/lib/getSafe"; import { maybeGetBookingUidFromSeat } from "@calcom/lib/server/maybeGetBookingUidFromSeat"; import { UserRepository } from "@calcom/lib/server/repository/user"; import prisma, { bookingMinimalSelect } from "@calcom/prisma"; diff --git a/apps/web/lib/settings/admin/orgMigrations/moveTeamToOrg/getServerSideProps.tsx b/apps/web/lib/settings/admin/orgMigrations/moveTeamToOrg/getServerSideProps.tsx index cb4ac548b5..ec46bdad79 100644 --- a/apps/web/lib/settings/admin/orgMigrations/moveTeamToOrg/getServerSideProps.tsx +++ b/apps/web/lib/settings/admin/orgMigrations/moveTeamToOrg/getServerSideProps.tsx @@ -1,6 +1,5 @@ import type { GetServerSidePropsContext } from "next"; import { getSession } from "next-auth/react"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { UserPermissionRole } from "@calcom/prisma/enums"; @@ -29,7 +28,6 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { error: null, migrated: null, userId: session.user.id, - ...(await serverSideTranslations(ctx.locale || "en", ["common"])), username: session.user.username, }, }; diff --git a/apps/web/lib/settings/admin/orgMigrations/moveUserToOrg/getServerSideProps.tsx b/apps/web/lib/settings/admin/orgMigrations/moveUserToOrg/getServerSideProps.tsx index be728f4d8c..7e23be070c 100644 --- a/apps/web/lib/settings/admin/orgMigrations/moveUserToOrg/getServerSideProps.tsx +++ b/apps/web/lib/settings/admin/orgMigrations/moveUserToOrg/getServerSideProps.tsx @@ -1,6 +1,5 @@ import type { GetServerSidePropsContext } from "next"; import { getSession } from "next-auth/react"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { UserPermissionRole } from "@calcom/prisma/enums"; @@ -25,8 +24,6 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { }; } return { - props: { - ...(await serverSideTranslations(ctx.locale || "en", ["common"])), - }, + props: {}, }; } diff --git a/apps/web/lib/settings/admin/orgMigrations/removeTeamFromOrg/getServerSideProps.tsx b/apps/web/lib/settings/admin/orgMigrations/removeTeamFromOrg/getServerSideProps.tsx index be728f4d8c..7e23be070c 100644 --- a/apps/web/lib/settings/admin/orgMigrations/removeTeamFromOrg/getServerSideProps.tsx +++ b/apps/web/lib/settings/admin/orgMigrations/removeTeamFromOrg/getServerSideProps.tsx @@ -1,6 +1,5 @@ import type { GetServerSidePropsContext } from "next"; import { getSession } from "next-auth/react"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { UserPermissionRole } from "@calcom/prisma/enums"; @@ -25,8 +24,6 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { }; } return { - props: { - ...(await serverSideTranslations(ctx.locale || "en", ["common"])), - }, + props: {}, }; } diff --git a/apps/web/lib/settings/admin/orgMigrations/removeUserFromOrg/getServerSideProps.tsx b/apps/web/lib/settings/admin/orgMigrations/removeUserFromOrg/getServerSideProps.tsx index be728f4d8c..7e23be070c 100644 --- a/apps/web/lib/settings/admin/orgMigrations/removeUserFromOrg/getServerSideProps.tsx +++ b/apps/web/lib/settings/admin/orgMigrations/removeUserFromOrg/getServerSideProps.tsx @@ -1,6 +1,5 @@ import type { GetServerSidePropsContext } from "next"; import { getSession } from "next-auth/react"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { UserPermissionRole } from "@calcom/prisma/enums"; @@ -25,8 +24,6 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { }; } return { - props: { - ...(await serverSideTranslations(ctx.locale || "en", ["common"])), - }, + props: {}, }; } diff --git a/apps/web/modules/auth/login-view.tsx b/apps/web/modules/auth/login-view.tsx index 22c754219d..7a83f9a7fa 100644 --- a/apps/web/modules/auth/login-view.tsx +++ b/apps/web/modules/auth/login-view.tsx @@ -17,7 +17,8 @@ import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLastUsed, LastUsed } from "@calcom/lib/hooks/useLastUsed"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; +import { collectPageParameters, telemetryEventTypes } from "@calcom/lib/telemetry"; import { trpc } from "@calcom/trpc/react"; import { EmailField } from "@calcom/ui/components/form"; import { Alert } from "@calcom/ui/components/alert"; diff --git a/apps/web/modules/connect-and-join/connect-and-join-view.tsx b/apps/web/modules/connect-and-join/connect-and-join-view.tsx index afaf9773af..2123d8ef15 100644 --- a/apps/web/modules/connect-and-join/connect-and-join-view.tsx +++ b/apps/web/modules/connect-and-join/connect-and-join-view.tsx @@ -1,7 +1,6 @@ "use client"; import { useSession } from "next-auth/react"; -import { Trans } from "next-i18next"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState } from "react"; @@ -13,6 +12,7 @@ import { trpc } from "@calcom/trpc"; import { Alert } from "@calcom/ui/components/alert"; import { Button } from "@calcom/ui/components/button"; import { EmptyScreen } from "@calcom/ui/components/empty-screen"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import { TRPCClientError } from "@trpc/client"; @@ -59,12 +59,18 @@ function ConnectAndJoin() {
{meetingUrl ? (
- - Some other host already accepted the meeting. Do you still want to join? - - Continue to Meeting - - + + Continue to Meeting + , + ]} + />
) : (
diff --git a/apps/web/modules/getting-started/[[...step]]/onboarding-view.tsx b/apps/web/modules/getting-started/[[...step]]/onboarding-view.tsx index 56c4874a90..849d04e7c9 100644 --- a/apps/web/modules/getting-started/[[...step]]/onboarding-view.tsx +++ b/apps/web/modules/getting-started/[[...step]]/onboarding-view.tsx @@ -1,7 +1,7 @@ "use client"; import { signOut } from "next-auth/react"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { usePathname, useRouter } from "next/navigation"; import { Suspense } from "react"; import { Toaster } from "sonner"; diff --git a/apps/web/modules/settings/teams/new/create-new-team-view.tsx b/apps/web/modules/settings/teams/new/create-new-team-view.tsx index 2650e67d45..903db49c98 100644 --- a/apps/web/modules/settings/teams/new/create-new-team-view.tsx +++ b/apps/web/modules/settings/teams/new/create-new-team-view.tsx @@ -8,7 +8,8 @@ import { CreateANewTeamForm } from "@calcom/features/ee/teams/components"; import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants"; import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl"; import { useParamsWithFallback } from "@calcom/lib/hooks/useParamsWithFallback"; -import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; +import { telemetryEventTypes } from "@calcom/lib/telemetry"; import type { RouterOutputs } from "@calcom/trpc/react"; import { WizardLayout } from "@calcom/ui/components/layout"; diff --git a/apps/web/modules/signup-view.tsx b/apps/web/modules/signup-view.tsx index bae04e8dbb..582b3644e4 100644 --- a/apps/web/modules/signup-view.tsx +++ b/apps/web/modules/signup-view.tsx @@ -3,7 +3,6 @@ import { Analytics as DubAnalytics } from "@dub/analytics/react"; import { zodResolver } from "@hookform/resolvers/zod"; import { signIn } from "next-auth/react"; -import { Trans } from "next-i18next"; import dynamic from "next/dynamic"; import Link from "next/link"; import { useRouter } from "next/navigation"; @@ -34,7 +33,8 @@ import { pushGTMEvent } from "@calcom/lib/gtm"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useDebounce } from "@calcom/lib/hooks/useDebounce"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; +import { collectPageParameters, telemetryEventTypes } from "@calcom/lib/telemetry"; import { IS_EUROPE } from "@calcom/lib/timezoneConstants"; import { signupSchema as apiSignupSchema } from "@calcom/prisma/zod-utils"; import type { inferSSRProps } from "@calcom/types/inferSSRProps"; @@ -44,6 +44,7 @@ import { Button } from "@calcom/ui/components/button"; import { PasswordField, CheckboxField, TextField, Form } from "@calcom/ui/components/form"; import { Icon } from "@calcom/ui/components/icon"; import { showToast } from "@calcom/ui/components/toast"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import type { getServerSideProps } from "@lib/signup/getServerSideProps"; @@ -597,7 +598,8 @@ export default function Signup({
- 1mb, to improve dev mode performance/RAM usage - serverComponentsExternalPackages: ["next-i18next"], optimizePackageImports: ["@calcom/ui"], - instrumentationHook: true, - serverActions: true, - }, - i18n: { - ...i18n, - defaultLocale: "en", - locales: ["en"], - localeDetection: false, + turbo: {}, }, productionBrowserSourceMaps: process.env.SENTRY_DISABLE_CLIENT_SOURCE_MAPS === "0", /* We already do type check on GH actions */ @@ -275,7 +272,6 @@ const nextConfig = { fs: false, // ignore module resolve errors caused by the server component bundler "pg-native": false, - "superagent-proxy": false, }; /** diff --git a/apps/web/package.json b/apps/web/package.json index 7e0c09dd92..ef1837570d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -7,7 +7,7 @@ "analyze:server": "BUNDLE_ANALYZE=server next build", "analyze:browser": "BUNDLE_ANALYZE=browser next build", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next", - "dev": "next dev", + "dev": "next dev --turbopack", "dev:cron": "ts-node cron-tester.ts", "dev-https": "NODE_TLS_REJECT_UNAUTHORIZED=0 next dev --experimental-https", "dx": "yarn dev", @@ -71,7 +71,7 @@ "@stripe/react-stripe-js": "^1.10.0", "@stripe/stripe-js": "^1.35.0", "@tanstack/react-query": "^5.17.15", - "@tremor/react": "^2.0.0", + "@tremor/react": "^2.11.0", "@types/turndown": "^5.0.1", "@unkey/ratelimit": "^0.1.1", "@upstash/redis": "^1.21.0", @@ -101,11 +101,11 @@ "memory-cache": "^0.2.0", "micro": "^10.0.1", "mime-types": "^2.1.35", - "next": "^13.5.6", + "next": "^15.1.6", "next-auth": "^4.22.1", "next-axiom": "^0.17.0", "next-collect": "^0.2.1", - "next-i18next": "^13.2.2", + "next-i18next": "^15.4.2", "next-seo": "^6.0.0", "next-themes": "^0.2.0", "nodemailer": "^6.7.8", @@ -178,7 +178,6 @@ "autoprefixer": "^10.4.12", "copy-webpack-plugin": "^11.0.0", "cron": "^3.1.7", - "deasync": "^0.1.30", "detect-port": "^1.3.0", "env-cmd": "^10.1.0", "google-auth-library": "^9.15.0", diff --git a/apps/web/pages/404.tsx b/apps/web/pages/404.tsx deleted file mode 100644 index 5bfa86fb5e..0000000000 --- a/apps/web/pages/404.tsx +++ /dev/null @@ -1,259 +0,0 @@ -"use client"; - -import type { GetStaticPropsContext } from "next"; -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import { useEffect, useState } from "react"; - -import { - getOrgDomainConfigFromHostname, - subdomainSuffix, -} from "@calcom/features/ee/organizations/lib/orgDomains"; -import { DOCS_URL, IS_CALCOM, WEBSITE_URL } from "@calcom/lib/constants"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { HeadSeo } from "@calcom/ui/components/head-seo"; -import { Icon } from "@calcom/ui/components/icon"; - -import PageWrapper from "@components/PageWrapper"; - -import { getTranslations } from "@server/lib/getTranslations"; - -enum pageType { - ORG = "org", - TEAM = "team", - USER = "user", - OTHER = "other", -} - -export default function Custom404() { - const pathname = usePathname(); - const { t } = useLocale(); - const [username, setUsername] = useState(""); - const [currentPageType, setCurrentPageType] = useState(pageType.USER); - - const links = [ - { - title: t("enterprise"), - description: "Learn more about organizations and subdomains in our enterprise plan.", - icon: "shield" as const, - href: `${WEBSITE_URL}/enterprise`, - }, - { - title: t("documentation"), - description: t("documentation_description"), - icon: "file-text" as const, - href: DOCS_URL, - }, - { - title: t("blog"), - description: t("blog_description"), - icon: "book-open" as const, - href: `${WEBSITE_URL}/blog`, - }, - ]; - - const [url, setUrl] = useState(`${WEBSITE_URL}/signup`); - useEffect(() => { - const { isValidOrgDomain, currentOrgDomain } = getOrgDomainConfigFromHostname({ - hostname: window.location.host, - }); - - 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 - setUsername(splitPath[2]); - setCurrentPageType(pageType.TEAM); - setUrl( - `${WEBSITE_URL}/signup?callbackUrl=settings/teams/new%3Fslug%3D${splitPath[2].replace("/", "")}` - ); - } else { - setUsername(routerUsername); - setUrl(`${WEBSITE_URL}/signup?username=${routerUsername.replace("/", "")}`); - } - } else { - setUsername(currentOrgDomain ?? ""); - setCurrentPageType(pageType.ORG); - setUrl( - `${WEBSITE_URL}/signup?callbackUrl=settings/organizations/new%3Fslug%3D${ - currentOrgDomain?.replace("/", "") ?? "" - }` - ); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const isSuccessPage = pathname?.startsWith("/booking"); - const isSubpage = pathname?.includes("/", 2) || isSuccessPage; - - /** - * If we're on 404 and the route is insights it means it is disabled - * TODO: Abstract this for all disabled features - **/ - const isInsights = pathname?.startsWith("/insights"); - if (isInsights) { - return ( - <> - -
-
-
-

{t("error_404")}

-

- Feature is currently disabled -

-
-
-
- - {t("or_go_back_home")} - - -
-
-
-
- - ); - } - - if (!username) return null; - - return ( - <> - -
-
-
-

{t("error_404")}

-

- {isSuccessPage ? "Booking not found" : t("page_doesnt_exist")} -

- {isSubpage && currentPageType !== pageType.TEAM ? ( - {t("check_spelling_mistakes_or_go_back")} - ) : IS_CALCOM ? ( - - {t(`404_the_${currentPageType.toLowerCase()}`)}{" "} - {username} {t("is_still_available")}{" "} - {t("register_now")}. - - ) : ( - - {t(`404_the_${currentPageType.toLowerCase()}`)}{" "} - {username}{" "} - {t("is_still_available")} - - )} -
-
- {((!isSubpage && IS_CALCOM) || - currentPageType === pageType.ORG || - currentPageType === pageType.TEAM) && ( - - )} -

- {t("popular_pages")} -

- -
- - {t("or_go_back_home")} - - -
-
-
-
- - ); -} - -Custom404.PageWrapper = PageWrapper; - -export const getStaticProps = async (context: GetStaticPropsContext) => { - const i18n = await getTranslations(context); - - return { - props: { - i18n, - }, - }; -}; diff --git a/apps/web/playwright/booking-seats.e2e.ts b/apps/web/playwright/booking-seats.e2e.ts index 3c5b87a61f..97fe26ef07 100644 --- a/apps/web/playwright/booking-seats.e2e.ts +++ b/apps/web/playwright/booking-seats.e2e.ts @@ -227,6 +227,7 @@ test.describe("Reschedule for booking with seats", () => { await page.goto( `/booking/${booking.uid}?cancel=true&allRemainingBookings=false&seatReferenceUid=${bookingSeats[0].referenceUid}` ); + await page.waitForSelector("text=Reason for cancellation"); await expect(page.locator('text="Cancel event"')).toBeVisible(); diff --git a/apps/web/playwright/managed-event-types.e2e.ts b/apps/web/playwright/managed-event-types.e2e.ts index 1085fcfa35..93276ce49c 100644 --- a/apps/web/playwright/managed-event-types.e2e.ts +++ b/apps/web/playwright/managed-event-types.e2e.ts @@ -34,10 +34,11 @@ test.describe("Managed Event Types", () => { await page.getByTestId("new-event-type").click(); await page.getByTestId("option-team-1").click(); // Expecting we can add a managed event type as team owner - await expect(page.locator('button[value="MANAGED"]')).toBeVisible(); + const locator = page.locator('div:has(input[value="MANAGED"]) > button'); + await expect(locator).toBeVisible(); // Actually creating a managed event type to test things further - await page.click('button[value="MANAGED"]'); + await locator.click(); await page.fill("[name=title]", "managed"); await page.click("[type=submit]"); diff --git a/apps/web/playwright/organization/team-management.e2e.ts b/apps/web/playwright/organization/team-management.e2e.ts index 7985da5a4b..c6fc65b76f 100644 --- a/apps/web/playwright/organization/team-management.e2e.ts +++ b/apps/web/playwright/organization/team-management.e2e.ts @@ -69,8 +69,9 @@ test.describe("Teams", () => { }); await test.step("Can finish team creation", async () => { - await expect(page.locator('button[value="ROUND_ROBIN"]')).toBeVisible(); - await page.click('button[value="ROUND_ROBIN"]'); + const locator = page.locator('div:has(input[value="ROUND_ROBIN"]) > button'); + await expect(locator).toBeVisible(); + await locator.click(); await page.fill("[name=title]", "roundRobin"); await page.getByTestId("finish-button").click(); await page.waitForURL(/\/settings\/teams\/(\d+)\/profile$/i); diff --git a/apps/web/public/favicon.ico b/apps/web/public/favicon.ico deleted file mode 100644 index 0760f8a241f733fe4e01f7716362d6299b144d8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 zcmeI3XKWQm5XX-|6e%H)kVK#)AN;}eX2A5`5xp1DY(%l>Unt+OKtN1KL_ny5Pz9nR zfk3hoL?VJH0wJSNWCRK&Kuk9Xn9OhDbMg8RPA!?0Jnm&x?u4zW&1Vu4~;FT5>XSJE~=C~hkv#dBVC?eH0J8h#n{x}xGpG3VQ_yHw@%dt}h^BgNb(;@!!CEiqRcDsDz0|96yU=JdiS zNm;z#YbE1TGCpCqfoj#N2?*tbU7L5c3)M$q z-m6-*s(`w6>q?U*O$>2yaaKpYqXoZQ*RNk+nm2DQ@$vCFvev9wQ-Et*qecw@?z*T- z`03cOqby#$SWcWcA(t;-Hk>?pQkE}YE*&~_FrMMPQKLpOckWy{b?TH{yLL^^ojWJ< z=FO8SQ>Ms~BS&QC&YjYtMGNWLwX5viyH^ezI3WG{^|R-TivLNICdt*SS0%3lc?Jy{ zBn=xjG=AQ^d6TQ@ix)3)p1*hRp6O!v@Zpk`l_jrVzn1ai$4lkPl?#0w(0fu+lH9+4 z-}r$KbiQugI@z#cgPcBnT3)?+CGa$M>{wZ_V1c}S`_{lc^ge(7d^vOGjMdRexcJ8w zTDEK{7cN{d-XA@BB(rACl6v*(<=8y>rf$@zQPQ+&Q@M2MlC?d1_N=sN)5dg)UfZ^9 zE7Wm>i~lNBs>qBPGi-dJyLRnbn}>dX;^rzm_U_$VGBY!2YUALy2hLMcQtV#1_-8IL z*ErC9|Ni|2nS#wR>bd{;@ndVBoSdA?p5dQ5j&Si`yLN3!O-(hLH*VaJ)~#FT_`yIK z7zgYnBO}Aw<7e=*$OSm3jw4+B*Q!-ZjvYH@G;iIyCGFa^3+dzV<6F0Gwf6Xx&6_uy zPZ~00h-}%iMP9yqY4^g#KfVVa!}0w2b4g50%w-dSV?g^ZUAoA{ix=$~{Ls^gICy?%n0!!Gq>=83*R{{{8!9 z#flYj_wHTuQH*6#`+xXp(4c`FKYrZ!$IoxyzFoR?>t^+=3kD1rVDBs5%d8ii40Y<% z5#$&#Vubl6))}<#)TxuSZ{Ob54BQLH`>R*4UXq@kZZcpK=n!9i{``4yHo+K8n>H=i z{J@?VA4=qMvbp+^BS#iF|JXS6diLxoM~@ygTQ)&_KTn=Kv2kHd1CN38BG@%@g^PbD z1MgjEE?c(D-V3}NI3G4_m|!pO%RBwS|GVnBySat9RUBJ2jIzKd! znK5IH!uugVeMI^hr-w-MQ9{31#~z~6wo7a(q)okva{WAtV*ay~_cKw0*u%#P{;$%abbCr^M{=EuokzllI{8b=@Xxys(z)A1 zb9=1pt#QtrarY>x18(ole@@%{fPUF`8#88%#nyK0*da@oE*18R>5skdnKNhFUL||) z#0ZI@_2|*V_PvQ~67!*-52epD#HqJ!+h%*n#3&v-cwlh~Voiew50*`vHd$keHQ=11FzEN~+t>7q?)~``*b#alpW(`tD>mjUSFV&*t5(UKJ9i3&KKggDZtMzs zN5{yBE?nG_cpEViVraw<4<9}(H*ek)Y@?v|hm6GCi77&Z*bDP(_3G6|hZqs#M4n2Y zK7B0Tf%%ADh$SsqvZO%vj}DM?(V|7BW9*9f7A1KL#1Y|Ccj!c*^L7Fvd7SgA{193(CmE-e6{g1!BlL@(;fA!xlInUqwrI_d~((A9x z2CwG{h4C8 zB27`)dppcA_H2Gt@V#krBfIX;luy$gnPlB209sX~M{+iuG^Gh`_9@twh*9M1Q|N!q z0uSZ6f`a{~e-!V#o@H(?ReYu3{~-MD>wTYf?RbVh?&srK*T=&GJnQ<%Rl0W~rCS5I zb%3kOize;KRb`#zaymzk9&PzcQwti zAb*YgpMCrG<@r2)k{?9dUAuN!J{fC$*7)R5a*iy>7>qtLK$n~daz*Hi^)YP$>m~9& z8aHkna*gE1EEo;yxF4Xqg1#sJ4(Kni|4`T1Z;FEd#e`}X>>l%ndHbazMe#rptX;4= O+A?n|Bp1Ll@$A2(WVaXq diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 1ee1408196..bab3543d5c 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -85,7 +85,7 @@ "payment_not_created_error": "Payment could not be created", "couldnt_charge_card_error": "Could not charge card for Payment", "no_available_users_found_error": "No available users found. Could you try another time slot?", - "timeslot_unavailable_book_a_new_time": "The selected time slot is no longer available. <2>Please select a new time", + "timeslot_unavailable_book_a_new_time": "The selected time slot is no longer available. <0>Please select a new time", "timeslot_unavailable_short": "Taken", "unavailable_timeslot_title": "Unavailable timeslot", "booking_time_out_of_bounds_error": "The event type cannot be booked at this time. Could you try another time slot?", @@ -172,7 +172,7 @@ "meeting_url": "Meeting URL", "meeting_url_not_found": "Meeting URL not found", "token_not_found": "Token not found", - "some_other_host_already_accepted_the_meeting": "Some other host already accepted the meeting. Do you still want to join? <1>Continue to Meeting", + "some_other_host_already_accepted_the_meeting": "Some other host already accepted the meeting. Do you still want to join? <0>Continue to Meeting", "meeting_request_rejected": "Your meeting request has been rejected", "rejected_event_type_with_organizer": "Rejected: {{eventType}} with {{organizer}} on {{date}}", "hi": "Hi", @@ -319,8 +319,8 @@ "yours": "Your account", "available_apps": "Available Apps", "available_apps_lower_case": "Available apps", - "available_apps_desc": "View popular apps below and explore more in our <1>App Store", - "fixed_host_helper": "Add anyone who needs to attend the event. <1>Learn more", + "available_apps_desc": "View popular apps below and explore more in our <0>App Store", + "fixed_host_helper": "Add anyone who needs to attend the event. <0>Learn more", "round_robin_helper": "People in the group take turns and only one person will show up for the event.", "check_email_reset_password": "Check your email. We sent you a link to reset your password.", "finish": "Finish", @@ -406,7 +406,7 @@ "bookerlayout_error_min_one_enabled": "At least one layout has to be enabled.", "bookerlayout_error_default_not_enabled": "The layout you selected as the default view is not part of the enabled layouts.", "bookerlayout_error_unknown_layout": "The layout you selected is not a valid layout.", - "bookerlayout_override_global_settings": "You can manage this for all your event types in Settings -> <2>Appearance or <6>Override for this event only.", + "bookerlayout_override_global_settings": "You can manage this for all your event types in Settings -> <0>Appearance or <1>Override for this event only.", "unexpected_error_try_again": "An unexpected error occurred. Try again.", "sunday_time_error": "Invalid time on Sunday", "monday_time_error": "Invalid time on Monday", @@ -657,6 +657,7 @@ "edit_team": "Edit team", "editing_user": "Editing user", "editing_org": "Editing organization", + "edit_or_manage_webhooks": "If you wish to edit or manage your web hooks, please head over to <0>webhooks settings", "reject": "Reject", "reject_all": "Reject all", "accept": "Accept", @@ -692,7 +693,7 @@ "add_team_members_description": "Invite others to join your team", "add_team_member": "Add team member", "invite_new_member": "Invite a new team member", - "invite_new_member_description": "Note: This will <1>cost an extra seat ($15/m) on your subscription.", + "invite_new_member_description": "Note: This will <0>cost an extra seat ($15/m) on your subscription.", "invite_new_team_member": "Invite someone to your team.", "upload_csv_file": "Upload a .csv file", "invite_via_email": "Invite via email", @@ -945,7 +946,7 @@ "hide_event_type": "Hide event type", "edit_location": "Edit location", "into_the_future": "into the future", - "when_booked_with_less_than_notice": "When booked with less than notice", + "when_booked_with_less_than_notice": "When booked with less than <0> notice", "within_date_range": "Within a date range", "indefinitely_into_future": "Indefinitely into the future", "add_new_custom_input_field": "Add new custom input field", @@ -964,7 +965,8 @@ "delete_event_type": "Delete event type?", "delete_managed_event_type": "Delete managed event type?", "delete_event_type_description": "Anyone who you've shared this link with will no longer be able to book using it.", - "delete_managed_event_type_description": "
  • Members assigned to this event type will also have their event types deleted.
  • Anyone who they've shared their link with will no longer be able to book using it.
", + "delete_managed_event_type_description_1": "Members assigned to this event type will also have their event types deleted.", + "delete_managed_event_type_description_2": "Anyone who they've shared their link with will no longer be able to book using it.", "confirm_delete_event_type": "Yes, delete", "delete_account": "Delete account", "confirm_delete_account": "Yes, delete account", @@ -1220,7 +1222,12 @@ "your_unique_api_key": "Your unique API key", "copy_safe_api_key": "Copy this API key and save it somewhere safe. If you lose this key you have to generate a new one.", "zapier_setup_instructions": "<0>Log into your Zapier account and create a new Zap.<1>Select Cal.com as your Trigger app. Also choose a Trigger event.<2>Choose your account and then enter your Unique API Key.<3>Test your Trigger.<4>You're set!", - "make_setup_instructions": "<0>Go to <1><0>Make Invite Link and install the Cal.com app.<1>Log into your Make account and create a new Scenario.<2>Select Cal.com as your Trigger app. Also choose a Trigger event.<3>Choose your account and then enter your Unique API Key.<4>Test your Trigger.<5>You're set!", + "make_setup_instructions_1": "Go to <0>Make Invite Link and install the Cal.com app.", + "make_setup_instructions_2": "Log into your Make account and create a new Scenario.", + "make_setup_instructions_3": "Select Cal.com as your Trigger app. Also choose a Trigger event.", + "make_setup_instructions_4": "Choose your account and then enter your Unique API Key.", + "make_setup_instructions_5": "Test your Trigger.", + "make_setup_instructions_6": "You're set!", "install_zapier_app": "Please first install the Zapier App in the app store.", "install_make_app": "Please first install the Make App in the app store.", "app_not_installed": "App not installed", @@ -1361,7 +1368,7 @@ "hour_one_short": "{{count}}h", "hour_other": "{{count}} hours", "invalid_input": "Invalid input", - "broken_video_action": "We could not add the <1>{{location}} meeting link to your scheduled event. Contact your invitees or update your calendar event to add the details. You can either <3> change your location on the event type or try <5>removing and adding the app again.", + "broken_video_action": "We could not add the {{location}} meeting link to your scheduled event. Contact your invitees or update your calendar event to add the details. You can either <0> change your location on the event type or try <1>removing and adding the app again.", "broken_calendar_action": "We could not update your <1>{{calendar}}. <2> Please check your calendar settings or remove and add your calendar again ", "attendee_name": "Attendee's name", "scheduler_full_name": "The full name of the person booking", @@ -1699,7 +1706,7 @@ "how_long_after_user_no_show_minutes": "How long after the users don't show up on cal video meeting?", "no_available_slots": "No Available slots", "time_available": "Time available", - "cant_find_the_right_conferencing_app_visit_our_app_store": "Can't find the right conferencing app? Visit our <1>App Store.", + "cant_find_the_right_conferencing_app_visit_our_app_store": "Can't find the right conferencing app? Visit our <0>App Store.", "install_new_calendar_app": "Install new calendar app", "make_phone_number_required": "Make phone number required for booking event", "new_event_type_availability": "{{eventTypeTitle}} Availability", @@ -1773,6 +1780,7 @@ "booking_limit_reached": "Booking Limit for this event type has been reached", "duration_limit_reached": "Duration Limit for this event type has been reached", "admin_has_disabled": "An admin has disabled {{appName}}", + "disable_attendees_emails_description": "This will disable all emails to {{recipient}}. This includes booking confirmations, requests, reschedules and reschedule requests, cancellation emails, and any other emails related to booking updates.

It is your responsibility to ensure that your {{recipient}} are aware of any bookings and changes to their bookings.", "disabled_app_affects_event_type": "An admin has disabled {{appName}} which affects your event type {{eventType}}", "event_replaced_notice": "An admin has replaced one of your event types", "email_subject_slug_replacement": "A team administrator has replaced your event /{{slug}}", @@ -1871,7 +1879,7 @@ "new_attendee": "New Attendee", "awaiting_approval": "Awaiting Approval", "requires_google_calendar": "This app requires a Google Calendar connection", - "event_type_requires_google_calendar": "The “Add to calendar” for this event type needs to be a Google Calendar for Meet to work. Connect it <1>here.", + "event_type_requires_google_calendar": "The “Add to calendar” for this event type needs to be a Google Calendar for Meet to work. Connect it <0>here.", "connected_google_calendar": "You have connected a Google Calendar account.", "using_meet_requires_calendar": "Using Google Meet requires a connected Google Calendar", "continue_to_install_google_calendar": "Continue to install Google Calendar", @@ -2436,7 +2444,10 @@ "create_your_org_description": "Upgrade to Organizations and receive a subdomain, unified billing, Insights, extensive whitelabeling and more", "create_your_enterprise_description": "Upgrade to Enterprise and get access to Active Directory Sync, SCIM Automatic User provisioning, Cal.ai Voice Agents, Admin APIs and more!", "other_payment_app_enabled": "You can only enable one payment app per event type", - "admin_delete_organization_description": "
  • Teams that are member of this organization will also be deleted along with their event-types
  • Users that were part of the organization will not be deleted but their usernames would be changed to allow them to exist outside the organization
  • User event-types created after the user was in the organization will be deleted
  • Migrated user event-types will not be deleted
", + "admin_delete_organization_description_1": "Teams that are member of this organization will also be deleted along with their event-types", + "admin_delete_organization_description_2": "Users that were part of the organization will not be deleted but their usernames would be changed to allow them to exist outside the organization", + "admin_delete_organization_description_3": "User event-types created after the user was in the organization will be deleted", + "admin_delete_organization_description_4": "Migrated user event-types will not be deleted", "admin_delete_organization_title": "Delete {{organizationName}}?", "published": "Published", "unpublished": "Unpublished", @@ -2516,7 +2527,7 @@ "set_weight": "Set Weight", "enable_weights": "Enable Weights", "priority_for_user": "Priority for {{userName}}", - "weights_description": "Weights determine how meetings are distributed among hosts. <1>Learn more", + "weights_description": "Weights determine how meetings are distributed among hosts. <0>Learn more", "weight_for_user": "Weight for {{userName}}", "change_priority": "change priority", "field_identifiers_as_variables": "Use field identifiers as variables for your custom event redirect", @@ -2552,8 +2563,8 @@ "email_team_invite|content|added_to_subteam": "{{invitedBy}} has added you to the team {{teamName}} in their organization {{parentTeamName}}. {{appName}} is the event-juggling scheduler that enables you and your team to schedule meetings without the email tennis.", "email_team_invite|content|invited_to_subteam": "{{invitedBy}} has invited you to join the team {{teamName}} in their organization {{parentTeamName}}. {{appName}} is the event-juggling scheduler that enables you and your team to schedule meetings without the email tennis.", "email_team_invite|content|invited_to_regular_team": "{{invitedBy}} has invited you to join their team {{teamName}} on {{appName}}. {{appName}} is the event-juggling scheduler that enables you and your team to schedule meetings without the email tennis.", - "email|existing_user_added_link_will_change": "On accepting the invite, your link will change to your organization domain but don't worry, all previous links will still work and redirect appropriately.

Please note: All of your personal event types will be moved into the {teamName} organization, which may also include potential personal link.

For personal events we recommend creating a new account with a personal email address.", - "email|existing_user_added_link_changed": "Your link has been changed from {prevLinkWithoutProtocol} to {newLinkWithoutProtocol} but don't worry, all previous links still work and redirect appropriately.

Please note: All of your personal event types have been moved into the {teamName} organisation, which may also include potential personal link.

Please log in and make sure you have no private events on your new organisational account.

For personal events we recommend creating a new account with a personal email address.

Enjoy your new clean link: {newLinkWithoutProtocol}", + "email|existing_user_added_link_will_change": "On accepting the invite, your link will change to your organization domain but don't worry, all previous links will still work and redirect appropriately.

Please note: All of your personal event types will be moved into the {{teamName}} organization, which may also include potential personal link.

For personal events we recommend creating a new account with a personal email address.", + "email|existing_user_added_link_changed": "Your link has been changed from {{a0}} to {{a1}} but don't worry, all previous links still work and redirect appropriately.

Please note: All of your personal event types have been moved into the {{teamName}} organisation, which may also include potential personal link.

Please log in and make sure you have no private events on your new organisational account.

For personal events we recommend creating a new account with a personal email address.

Enjoy your new clean link: {{a2}}", "email_organization_created|subject": "Your organization has been created", "your_current_plan": "Your current plan", "organization_price_per_user_month": "$37 per user per month (30 seats minimum)", @@ -2610,7 +2621,7 @@ "ooo_reasons_travel": "Travel", "ooo_reasons_sick_leave": "Sick leave", "ooo_reasons_public_holiday": "Public holiday", - "ooo_forwarding_to": "Forwarding to {{username}}", + "ooo_forwarding_to": "Forwarding to <0>{{username}}", "ooo_not_forwarding": "No forwarding", "ooo_empty_title": "Create an OOO", "ooo_empty_description": "Communicate to your bookers when you're not available to take bookings. They can still book you upon your return or you can forward them to a team member.", @@ -2940,7 +2951,7 @@ "dry_run_mode_active": "You are doing a test booking.", "icon_showcase": "Icon showcase", "icons_showcase": "Icons showcase", - "migrating_from_team":"Migrating from team", + "migrating_from_team": "Migrating from team", "feature_currently_disabled": "Feature is currently disabled", "choose_an_option": "Choose an option", "enter_option_value": "Enter option value", @@ -3013,7 +3024,7 @@ "ooo_team_redirect_infinite_not_allowed": "There is already a reverse forwarding between these users.", "previous_ooo_empty_title": "No previous OOO found", "previous": "Previous", - "rr_interval_successfully_updated":"Round Robin interval successfully updated", + "rr_interval_successfully_updated": "Round Robin interval successfully updated", "trial_mode": "Trial mode", "inactive_team_plan": "Inactive team plan", "inactive_team_plan_description": "Your team plan is inactive. Check your subcription or reach out to customer support", @@ -3026,4 +3037,4 @@ "user_has_no_team_yet": "You don't have a team yet", "no_team_members": "You don't have team members yet", "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" -} +} \ No newline at end of file diff --git a/apps/web/scripts/vercel-app-router-deploy.sh b/apps/web/scripts/vercel-app-router-deploy.sh deleted file mode 100755 index b9f36a543d..0000000000 --- a/apps/web/scripts/vercel-app-router-deploy.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -checkRoute () { - if [ "$1" != '1' ]; then rm -rf $2; fi -} - -# These conditionals are used to remove directories from the build that are not needed in production -# This is to reduce the size of the build and prevent OOM errors -checkRoute "$APP_ROUTER_APPS_SLUG_SETUP_ENABLED" app/future/apps/\[slug\]/setup -checkRoute "$APP_ROUTER_TEAM_ENABLED" app/future/team - -# These are routes that don't have and environment variable to enable or disable them -# Will stop removing gradually as we test and confirm that they are working -rm -rf \ - app/future/d\ - app/future/enterprise\ - app/future/org\ - app/future/payment\ - app/future/reschedule\ - app/future/routing-forms\ - app/future/signup\ - -exit 1 diff --git a/apps/web/server/lib/auth/forgot-password/[id]/getServerSideProps.tsx b/apps/web/server/lib/auth/forgot-password/[id]/getServerSideProps.tsx index 0ae3cf1906..c511604ad9 100644 --- a/apps/web/server/lib/auth/forgot-password/[id]/getServerSideProps.tsx +++ b/apps/web/server/lib/auth/forgot-password/[id]/getServerSideProps.tsx @@ -1,8 +1,6 @@ import type { GetServerSidePropsContext } from "next"; import { getCsrfToken } from "next-auth/react"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -import { getLocale } from "@calcom/features/auth/lib/getLocale"; import prisma from "@calcom/prisma"; export async function getServerSideProps(context: GetServerSidePropsContext) { @@ -25,13 +23,12 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { } catch (e) { resetPasswordRequest = null; } - const locale = await getLocale(context.req); + return { props: { isRequestExpired: !resetPasswordRequest, requestId: id, csrfToken: await getCsrfToken({ req: context.req }), - ...(await serverSideTranslations(locale, ["common"])), }, }; } diff --git a/apps/web/server/lib/getTranslations.ts b/apps/web/server/lib/getTranslations.ts deleted file mode 100644 index e8aaba052f..0000000000 --- a/apps/web/server/lib/getTranslations.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { GetStaticPropsContext } from "next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { i18n } = require("@calcom/config/next-i18next.config"); - -export async function getTranslations( - opts: GetStaticPropsContext -) { - const requestedLocale = opts.params?.locale || opts.locale || i18n.defaultLocale; - const isSupportedLocale = i18n.locales.includes(requestedLocale); - if (!isSupportedLocale) { - console.warn(`Requested unsupported locale "${requestedLocale}"`); - } - const locale = isSupportedLocale ? requestedLocale : i18n.defaultLocale; - - const _i18n = await serverSideTranslations(locale, ["common"]); - - return { - i18n: _i18n, - }; -} diff --git a/apps/web/server/lib/ssr.ts b/apps/web/server/lib/ssr.ts index d99fb56983..42bc111b70 100644 --- a/apps/web/server/lib/ssr.ts +++ b/apps/web/server/lib/ssr.ts @@ -1,11 +1,9 @@ import type { GetServerSidePropsContext } from "next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import superjson from "superjson"; import { forms } from "@calcom/app-store/routing-forms/trpc/procedures/forms"; import { getLocale } from "@calcom/features/auth/lib/getLocale"; import { map } from "@calcom/features/flags/server/procedures/map"; -import { CALCOM_VERSION } from "@calcom/lib/constants"; import { createContext } from "@calcom/trpc/server/createContext"; import { teamsAndUserProfilesQuery } from "@calcom/trpc/server/routers/loggedInViewer/procedures/teamsAndUserProfilesQuery"; import { event } from "@calcom/trpc/server/routers/publicViewer/procedures/event"; @@ -54,24 +52,13 @@ const routerSlice = router({ export async function ssrInit(context: GetServerSidePropsContext, options?: { noI18nPreload: boolean }) { const ctx = await createContext(context); const locale = await getLocale(context.req); - const i18n = await serverSideTranslations(locale, ["common", "vital"]); const ssr = createServerSideHelpers({ router: routerSlice, transformer: superjson, - ctx: { ...ctx, locale, i18n }, + ctx: { ...ctx, locale }, }); - // i18n translations are already retrieved from serverSideTranslations call, there is no need to run a i18n.fetch - // we can set query data directly to the queryClient - const queryKey = [ - ["viewer", "public", "i18n"], - { input: { locale, CalComVersion: CALCOM_VERSION }, type: "query" }, - ]; - if (!options?.noI18nPreload) { - ssr.queryClient.setQueryData(queryKey, { i18n }); - } - await Promise.allSettled([ // So feature flags are available on first render ssr.viewer.features.map.prefetch(), diff --git a/apps/web/styles/globals.css b/apps/web/styles/globals.css index 163fda356c..5446ff5955 100644 --- a/apps/web/styles/globals.css +++ b/apps/web/styles/globals.css @@ -1,3 +1,6 @@ +/* @import rules must precede all rules aside from @charset and @layer statements. */ +@import "./raqb.css"; + @tailwind base; @tailwind components; @tailwind utilities; @@ -9,48 +12,48 @@ --cal-spacing-0: 0px; --cal-spacing-px: 1px; --cal-spacing-0_5: 0.125rem; /* 2px */ - --cal-spacing-1: 0.25rem; /* 4px */ + --cal-spacing-1: 0.25rem; /* 4px */ --cal-spacing-1_5: 0.375rem; /* 6px */ - --cal-spacing-2: 0.5rem; /* 8px */ + --cal-spacing-2: 0.5rem; /* 8px */ --cal-spacing-2_5: 0.625rem; /* 10px */ - --cal-spacing-3: 0.75rem; /* 12px */ + --cal-spacing-3: 0.75rem; /* 12px */ --cal-spacing-3_5: 0.875rem; /* 14px */ - --cal-spacing-4: 1rem; /* 16px */ - --cal-spacing-5: 1.25rem; /* 20px */ - --cal-spacing-6: 1.5rem; /* 24px */ - --cal-spacing-7: 1.75rem; /* 28px */ - --cal-spacing-8: 2rem; /* 32px */ - --cal-spacing-9: 2.25rem; /* 36px */ - --cal-spacing-10: 2.5rem; /* 40px */ - --cal-spacing-11: 2.75rem; /* 44px */ - --cal-spacing-12: 3rem; /* 48px */ - --cal-spacing-14: 3.5rem; /* 56px */ - --cal-spacing-16: 4rem; /* 64px */ - --cal-spacing-20: 5rem; /* 80px */ - --cal-spacing-24: 6rem; /* 96px */ - --cal-spacing-28: 7rem; /* 112px */ - --cal-spacing-32: 8rem; /* 128px */ - --cal-spacing-36: 9rem; /* 144px */ - --cal-spacing-40: 10rem; /* 160px */ - --cal-spacing-44: 11rem; /* 176px */ - --cal-spacing-48: 12rem; /* 192px */ - --cal-spacing-52: 13rem; /* 208px */ - --cal-spacing-56: 14rem; /* 224px */ - --cal-spacing-60: 15rem; /* 240px */ - --cal-spacing-64: 16rem; /* 256px */ - --cal-spacing-72: 18rem; /* 288px */ - --cal-spacing-80: 20rem; /* 320px */ - --cal-spacing-96: 24rem; /* 384px */ + --cal-spacing-4: 1rem; /* 16px */ + --cal-spacing-5: 1.25rem; /* 20px */ + --cal-spacing-6: 1.5rem; /* 24px */ + --cal-spacing-7: 1.75rem; /* 28px */ + --cal-spacing-8: 2rem; /* 32px */ + --cal-spacing-9: 2.25rem; /* 36px */ + --cal-spacing-10: 2.5rem; /* 40px */ + --cal-spacing-11: 2.75rem; /* 44px */ + --cal-spacing-12: 3rem; /* 48px */ + --cal-spacing-14: 3.5rem; /* 56px */ + --cal-spacing-16: 4rem; /* 64px */ + --cal-spacing-20: 5rem; /* 80px */ + --cal-spacing-24: 6rem; /* 96px */ + --cal-spacing-28: 7rem; /* 112px */ + --cal-spacing-32: 8rem; /* 128px */ + --cal-spacing-36: 9rem; /* 144px */ + --cal-spacing-40: 10rem; /* 160px */ + --cal-spacing-44: 11rem; /* 176px */ + --cal-spacing-48: 12rem; /* 192px */ + --cal-spacing-52: 13rem; /* 208px */ + --cal-spacing-56: 14rem; /* 224px */ + --cal-spacing-60: 15rem; /* 240px */ + --cal-spacing-64: 16rem; /* 256px */ + --cal-spacing-72: 18rem; /* 288px */ + --cal-spacing-80: 20rem; /* 320px */ + --cal-spacing-96: 24rem; /* 384px */ /* Border Radius */ --cal-radius-none: 0px; - --cal-radius-sm: 0.125rem; /* 2px */ - --cal-radius: 0.25rem; /* 4px */ - --cal-radius-md: 0.375rem; /* 6px */ - --cal-radius-lg: 0.5rem; /* 8px */ - --cal-radius-xl: 0.75rem; /* 12px */ - --cal-radius-2xl: 1rem; /* 16px */ - --cal-radius-3xl: 1.5rem; /* 24px */ + --cal-radius-sm: 0.125rem; /* 2px */ + --cal-radius: 0.25rem; /* 4px */ + --cal-radius-md: 0.375rem; /* 6px */ + --cal-radius-lg: 0.5rem; /* 8px */ + --cal-radius-xl: 0.75rem; /* 12px */ + --cal-radius-2xl: 1rem; /* 16px */ + --cal-radius-3xl: 1.5rem; /* 24px */ --cal-radius-full: 9999px; /* Background Standard */ @@ -69,7 +72,7 @@ --cal-bg-brand: hsla(214, 30%, 16%, 1); /* gray-50 */ --cal-bg-brand-emphasis: hsla(220, 6%, 25%, 1); /* stone-100 */ --cal-bg-brand-muted: hsla(220, 14%, 94%, 1); /* stone-100 */ - + /* Background Semantic */ --cal-bg-semantic-info-subtle: hsla(212, 88%, 97%, 1); /* blue-100 */ --cal-bg-semantic-info-emphasis: hsla(236, 80%, 25%, 1); /* blue-500 */ @@ -135,8 +138,8 @@ --cal-text-visualization-7: hsla(0, 84%, 25%, 1); /* red-800 */ /* Border/Semantic Subtle */ - --cal-border-semantic-attention-subtle: hsla(32, 98%, 83%, 1); - --cal-border-semantic-error-subtle: hsla(0, 96%, 89%, 1); + --cal-border-semantic-attention-subtle: hsla(32, 98%, 83%, 1); + --cal-border-semantic-error-subtle: hsla(0, 96%, 89%, 1); /* Legacy Content/Text Components - Consider deprecating */ --cal-text-info: hsla(225, 57%, 33%, 1); /* #253985 - interactive text/icons */ @@ -209,11 +212,9 @@ /* Border Semantic */ --cal-border-semantic-error: hsla(0, 63%, 24%, 1); /* red-800 */ - /* Border/Semantic Subtle */ - --cal-border-semantic-attention-subtle: hsla(15, 75%, 23%, 1); - --cal-border-semantic-error-subtle: hsla(0, 63%, 24%, 1); - + --cal-border-semantic-attention-subtle: hsla(15, 75%, 23%, 1); + --cal-border-semantic-error-subtle: hsla(0, 63%, 24%, 1); /* Legacy Border - Consider deprecating */ --cal-border-error: hsla(0, 63%, 24%, 1); /* Keeping existing error border */ @@ -251,7 +252,7 @@ @layer base { * { - @apply border-default + @apply border-default; } } @@ -275,7 +276,7 @@ body  { https://docs.todesktop.com/ */ -html.todesktop-platform-win32 .todesktop\:\!bg-transparent{ +html.todesktop-platform-win32 .todesktop\:\!bg-transparent { background: inherit !important; } @@ -308,7 +309,8 @@ html.todesktop header a { -webkit-app-region: no-drag; } -html.todesktop-platform-darwin body, html.todesktop-platform-darwin aside { +html.todesktop-platform-darwin body, +html.todesktop-platform-darwin aside { background: transparent !important; } @@ -634,12 +636,10 @@ select:focus { @apply !border-r-default left-0.5 !border-y-0 !border-l-0; } -.intercom-lightweight-app { +.intercom-lightweight-app { @apply z-40 !important; } [data-radix-popper-content-wrapper] { border: none; } - -@import "./raqb.css"; diff --git a/apps/web/test/lib/plainTiers.test.ts b/apps/web/test/lib/plainTiers.test.ts index 70addf52c4..6d67fec3f7 100644 --- a/apps/web/test/lib/plainTiers.test.ts +++ b/apps/web/test/lib/plainTiers.test.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import prismaMock from "../../../../tests/libs/__mocks__/prismaMock"; +import type { Params } from "app/_types"; import type { NextRequest } from "next/server"; import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest"; @@ -76,13 +77,16 @@ describe("Plain Integration API", () => { const userData = { id: 1, email: `${tier}@example.com`, name: `${tier} User` }; (getServerSession as any).mockResolvedValue({ user: userData }); prismaMock.user.findUnique.mockResolvedValue({ ...userData, teams }); + const params = Promise.resolve({}) - const data = await (await POST({} as NextRequest, { params: {} })).json(); + const data = await (await POST({} as NextRequest, { params })).json(); expect(data).toMatchObject({ userTier: tier, email: userData.email, fullName: userData.name }); }); it("should return 401 when no session exists", async () => { (getServerSession as any).mockResolvedValue(null); - expect((await POST({} as NextRequest, { params: {} })).status).toBe(401); + const params = Promise.resolve({}) + + expect((await POST({} as NextRequest, { params })).status).toBe(401); }); }); diff --git a/apps/web/test/utils/bookingScenario/bookingScenario.ts b/apps/web/test/utils/bookingScenario/bookingScenario.ts index 230849914c..190edfbaa2 100644 --- a/apps/web/test/utils/bookingScenario/bookingScenario.ts +++ b/apps/web/test/utils/bookingScenario/bookingScenario.ts @@ -1575,7 +1575,6 @@ export function mockNoTranslations() { i18nMock.getTranslation.mockImplementation(() => { return new Promise((resolve) => { const identityFn = (key: string) => key; - // @ts-expect-error FIXME resolve(identityFn); }); }); diff --git a/packages/app-store/alby/components/AlbyPaymentComponent.tsx b/packages/app-store/alby/components/AlbyPaymentComponent.tsx index dd90b44567..e65d71e657 100644 --- a/packages/app-store/alby/components/AlbyPaymentComponent.tsx +++ b/packages/app-store/alby/components/AlbyPaymentComponent.tsx @@ -1,3 +1,5 @@ +"use client"; + import Link from "next/link"; import { useEffect, useState } from "react"; import QRCode from "react-qr-code"; diff --git a/packages/app-store/exchangecalendar/lib/CalendarService.ts b/packages/app-store/exchangecalendar/lib/CalendarService.ts index e0dd65b07e..b781761e2e 100644 --- a/packages/app-store/exchangecalendar/lib/CalendarService.ts +++ b/packages/app-store/exchangecalendar/lib/CalendarService.ts @@ -1,4 +1,3 @@ -import { XhrApi } from "@ewsjs/xhr"; import type { FindFoldersResults, FindItemsResults } from "ews-javascript-api"; import { Appointment, @@ -55,7 +54,7 @@ export default class ExchangeCalendarService implements Calendar { } async createEvent(event: CalendarEvent): Promise { - const appointment: Appointment = new Appointment(this.getExchangeService()); + const appointment: Appointment = new Appointment(await this.getExchangeService()); appointment.Subject = event.title; appointment.Start = DateTime.Parse(event.startTime); appointment.End = DateTime.Parse(event.endTime); @@ -91,7 +90,7 @@ export default class ExchangeCalendarService implements Calendar { uid: string, event: CalendarEvent ): Promise { - const appointment: Appointment = await Appointment.Bind(this.getExchangeService(), new ItemId(uid)); + const appointment: Appointment = await Appointment.Bind(await this.getExchangeService(), new ItemId(uid)); appointment.Subject = event.title; appointment.Start = DateTime.Parse(event.startTime); appointment.End = DateTime.Parse(event.endTime); @@ -127,7 +126,7 @@ export default class ExchangeCalendarService implements Calendar { } async deleteEvent(uid: string): Promise { - const appointment: Appointment = await Appointment.Bind(this.getExchangeService(), new ItemId(uid)); + const appointment: Appointment = await Appointment.Bind(await this.getExchangeService(), new ItemId(uid)); return appointment.Delete(DeleteMode.MoveToDeletedItems).catch((reason) => { this.log.error(reason); throw reason; @@ -143,7 +142,7 @@ export default class ExchangeCalendarService implements Calendar { const promises: Promise[] = calendars .filter((lcal) => selectedCalendars.some((rcal) => lcal.externalId == rcal.externalId)) .map(async (calendar) => { - return this.getExchangeService() + return (await this.getExchangeService()) .FindAppointments( new FolderId(calendar.externalId), new CalendarView(DateTime.Parse(dateFrom), DateTime.Parse(dateTo)) @@ -167,7 +166,7 @@ export default class ExchangeCalendarService implements Calendar { } async listCalendars(): Promise { - const service: ExchangeService = this.getExchangeService(); + const service: ExchangeService = await this.getExchangeService(); const view: FolderView = new FolderView(1000); view.PropertySet = new PropertySet(BasePropertySet.IdOnly); view.PropertySet.Add(FolderSchema.ParentFolderId); @@ -197,12 +196,13 @@ export default class ExchangeCalendarService implements Calendar { }); } - private getExchangeService(): ExchangeService { + private async getExchangeService(): Promise { const service: ExchangeService = new ExchangeService(this.payload.exchangeVersion); service.Credentials = new WebCredentials(this.payload.username, this.payload.password); service.Url = new Uri(this.payload.url); if (this.payload.authenticationMethod === ExchangeAuthentication.NTLM) { - const xhr: XhrApi = new XhrApi({ + const { XhrApi } = await import("@ewsjs/xhr"); + const xhr = new XhrApi({ rejectUnauthorized: false, }).useNtlmAuthentication(this.payload.username, this.payload.password); service.XHRApi = xhr; diff --git a/packages/app-store/locations.ts b/packages/app-store/locations.ts index 52255bb273..bb5deeb94e 100644 --- a/packages/app-store/locations.ts +++ b/packages/app-store/locations.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { z } from "zod"; import { appStoreMetadata } from "@calcom/app-store/bookerAppsMetaData"; diff --git a/packages/app-store/make/pages/setup/index.tsx b/packages/app-store/make/pages/setup/index.tsx index e3589bd5fa..4eb737475d 100644 --- a/packages/app-store/make/pages/setup/index.tsx +++ b/packages/app-store/make/pages/setup/index.tsx @@ -1,5 +1,4 @@ import type { InferGetServerSidePropsType } from "next"; -import { Trans } from "next-i18next"; import Link from "next/link"; import { useState } from "react"; import { Toaster } from "sonner"; @@ -11,6 +10,7 @@ import { Button } from "@calcom/ui/components/button"; import { Icon } from "@calcom/ui/components/icon"; import { showToast } from "@calcom/ui/components/toast"; import { Tooltip } from "@calcom/ui/components/tooltip"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import type { getServerSideProps } from "./_getServerSideProps"; @@ -115,20 +115,25 @@ export default function MakeSetup({ inviteLink }: InferGetServerSidePropsType
    - -
  1. - Go to - - Make Invite Link - - and install the Cal.com app. -
  2. -
  3. Log into your Make account and create a new Scenario.
  4. -
  5. Select Cal.com as your Trigger app. Also choose a Trigger event.
  6. -
  7. Choose your account and then enter your Unique API Key.
  8. -
  9. Test your Trigger.
  10. -
  11. You're set!
  12. -
    +
  13. + + Make Invite Link + , + ]} + /> +
  14. +
  15. {t("make_setup_instructions_2")}
  16. +
  17. {t("make_setup_instructions_3")}
  18. +
  19. {t("make_setup_instructions_4")}
  20. +
  21. {t("make_setup_instructions_5")}
  22. +
  23. {t("make_setup_instructions_6")}
diff --git a/packages/app-store/routing-forms/components/getServerSidePropsSingleForm.ts b/packages/app-store/routing-forms/components/getServerSidePropsSingleForm.ts index 582670de8f..b65bc23ca1 100644 --- a/packages/app-store/routing-forms/components/getServerSidePropsSingleForm.ts +++ b/packages/app-store/routing-forms/components/getServerSidePropsSingleForm.ts @@ -114,7 +114,6 @@ export const getServerSidePropsForSingleFormView = async function getServerSideP return { props: { - trpcState: await ssr.dehydrate(), form: await getSerializableForm({ form: formWithoutProfileInfo }), enrichedWithUserProfileForm: await getSerializableForm({ form: enrichFormWithMigrationData(formWithUserInfoProfile), diff --git a/packages/app-store/routing-forms/pages/app-routing.client-config.tsx b/packages/app-store/routing-forms/pages/app-routing.client-config.tsx new file mode 100644 index 0000000000..d1e9da2043 --- /dev/null +++ b/packages/app-store/routing-forms/pages/app-routing.client-config.tsx @@ -0,0 +1,8 @@ +export const routingFormsComponents = { + "form-edit": () => import("./form-edit/[...appPages]").then((mod) => mod.default), + "route-builder": () => import("./route-builder/[...appPages]").then((mod) => mod.default), + "forms": () => import("./forms/[...appPages]").then((mod) => mod.default), + "routing-link": () => import("./routing-link/[...appPages]").then((mod) => mod.default), + "reporting": () => import("./reporting/[...appPages]").then((mod) => mod.default), + "incomplete-booking": () => import("./incomplete-booking/[...appPages]").then((mod) => mod.default), +}; \ No newline at end of file diff --git a/packages/app-store/routing-forms/pages/app-routing.config.tsx b/packages/app-store/routing-forms/pages/app-routing.server-config.tsx similarity index 50% rename from packages/app-store/routing-forms/pages/app-routing.config.tsx rename to packages/app-store/routing-forms/pages/app-routing.server-config.tsx index 2c7ba5f788..7945db3f6a 100644 --- a/packages/app-store/routing-forms/pages/app-routing.config.tsx +++ b/packages/app-store/routing-forms/pages/app-routing.server-config.tsx @@ -1,26 +1,11 @@ -//TODO: Generate this file automatically so that like in Next.js file based routing can work automatically +import "server-only"; + import type { AppGetServerSideProps } from "@calcom/types/AppGetServerSideProps"; import { getServerSidePropsForSingleFormView as getServerSidePropsSingleForm } from "../components/getServerSidePropsSingleForm"; -import * as formEdit from "./form-edit/[...appPages]"; -import * as forms from "./forms/[...appPages]"; -// extracts getServerSideProps function from the client component import { getServerSideProps as getServerSidePropsForms } from "./forms/getServerSideProps"; -import * as IncompleteBooking from "./incomplete-booking/[...appPages]"; -import * as Reporting from "./reporting/[...appPages]"; -import * as RouteBuilder from "./route-builder/[...appPages]"; -import * as RoutingLink from "./routing-link/[...appPages]"; import { getServerSideProps as getServerSidePropsRoutingLink } from "./routing-link/getServerSideProps"; -const routingConfig = { - "form-edit": formEdit, - "route-builder": RouteBuilder, - forms: forms, - "routing-link": RoutingLink, - reporting: Reporting, - "incomplete-booking": IncompleteBooking, -}; - export const routingServerSidePropsConfig: Record = { forms: getServerSidePropsForms, "form-edit": getServerSidePropsSingleForm, @@ -29,5 +14,3 @@ export const routingServerSidePropsConfig: Record reporting: getServerSidePropsSingleForm, "incomplete-booking": getServerSidePropsSingleForm, }; - -export default routingConfig; diff --git a/packages/app-store/routing-forms/pages/forms/getServerSideProps.ts b/packages/app-store/routing-forms/pages/forms/getServerSideProps.ts index 345c0b3e5f..725b220a3b 100644 --- a/packages/app-store/routing-forms/pages/forms/getServerSideProps.ts +++ b/packages/app-store/routing-forms/pages/forms/getServerSideProps.ts @@ -30,8 +30,6 @@ export const getServerSideProps = async function getServerSideProps( // Prefetch this so that New Button is immediately available await ssr.viewer.teamsAndUserProfilesQuery.prefetch(); return { - props: { - trpcState: await ssr.dehydrate(), - }, + props: {}, }; }; diff --git a/packages/app-store/routing-forms/pages/layout-handler/[...appPages].tsx b/packages/app-store/routing-forms/pages/layout-handler/[...appPages].tsx deleted file mode 100644 index 48ec8d4ed4..0000000000 --- a/packages/app-store/routing-forms/pages/layout-handler/[...appPages].tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client"; - -import type { GetServerSidePropsContext, GetServerSideProps } from "next"; -import type { ReactElement, ReactNode, ComponentType } from "react"; -import { FormProvider, useForm } from "react-hook-form"; - -import { useParamsWithFallback } from "@calcom/lib/hooks/useParamsWithFallback"; - -import RoutingFormsRoutingConfig from "../app-routing.config"; - -const DEFAULT_ROUTE = "forms"; - -type ComponentWithLayout = ComponentType & { - getLayout?: (page: ReactElement) => ReactNode; -}; - -type Component = { - default: ComponentWithLayout; - getServerSideProps?: ( - context: GetServerSidePropsContext, - ...rest: Parameters - ) => ReturnType; -}; - -const getComponent = (route: string): Component => { - return (RoutingFormsRoutingConfig as unknown as Record)[route]; -}; - -export default function LayoutHandler(props: { [key: string]: unknown }) { - const params = useParamsWithFallback(); - const methods = useForm(); - const pageKey = Array.isArray(params.pages) - ? params.pages[0] - : params.pages?.split("/")[0] ?? DEFAULT_ROUTE; - const PageComponent = getComponent(pageKey).default; - return ( - - - - ); -} diff --git a/packages/app-store/server.ts b/packages/app-store/server.ts index e948427c8e..75261d1af3 100644 --- a/packages/app-store/server.ts +++ b/packages/app-store/server.ts @@ -1,5 +1,5 @@ import type { Prisma } from "@prisma/client"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { defaultVideoAppCategories } from "@calcom/app-store/utils"; import getEnabledAppsFromCredentials from "@calcom/lib/apps/getEnabledAppsFromCredentials"; diff --git a/packages/app-store/vital/lib/client.ts b/packages/app-store/vital/lib/client.ts index 0196a8ec5d..5ae7384218 100644 --- a/packages/app-store/vital/lib/client.ts +++ b/packages/app-store/vital/lib/client.ts @@ -1,4 +1,3 @@ -import { VitalClient } from "@tryvital/vital-node"; import type { ClientConfig } from "@tryvital/vital-node/dist/lib/models"; import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug"; @@ -8,10 +7,10 @@ type VitalEnv = ClientConfig & { webhook_secret: string; }; -export let vitalClient: VitalClient | null = null; +export let vitalClient: any = null; export let vitalEnv: VitalEnv | null = null; -export async function initVitalClient(): Promise { +export async function initVitalClient() { if (vitalClient) return vitalClient; const appKeys = (await getAppKeysFromSlug("vital-automation")) as unknown as VitalEnv; if ( @@ -23,6 +22,7 @@ export async function initVitalClient(): Promise { ) throw Error("Missing properties in vital-automation DB keys"); vitalEnv = appKeys; + const { VitalClient } = await import("@tryvital/vital-node"); vitalClient = new VitalClient({ region: appKeys.region, api_key: appKeys.api_key || "", diff --git a/packages/app-store/vital/lib/reschedule.ts b/packages/app-store/vital/lib/reschedule.ts index 655e105102..285ff44afa 100644 --- a/packages/app-store/vital/lib/reschedule.ts +++ b/packages/app-store/vital/lib/reschedule.ts @@ -1,5 +1,5 @@ import type { Booking, BookingReference, User } from "@prisma/client"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import dayjs from "@calcom/dayjs"; import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails"; diff --git a/packages/app-store/wipemycalother/lib/reschedule.ts b/packages/app-store/wipemycalother/lib/reschedule.ts index 1473b3b66a..8974608ee7 100644 --- a/packages/app-store/wipemycalother/lib/reschedule.ts +++ b/packages/app-store/wipemycalother/lib/reschedule.ts @@ -1,5 +1,5 @@ import type { Booking, BookingReference, User } from "@prisma/client"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import dayjs from "@calcom/dayjs"; import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails"; diff --git a/packages/app-store/zapier/pages/setup/index.tsx b/packages/app-store/zapier/pages/setup/index.tsx index c900b3c07e..12798cf44d 100644 --- a/packages/app-store/zapier/pages/setup/index.tsx +++ b/packages/app-store/zapier/pages/setup/index.tsx @@ -1,4 +1,3 @@ -import { Trans } from "next-i18next"; import Link from "next/link"; import { useState } from "react"; import { Toaster } from "sonner"; @@ -6,10 +5,11 @@ import { Toaster } from "sonner"; import AppNotInstalledMessage from "@calcom/app-store/_components/AppNotInstalledMessage"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import { Icon } from "@calcom/ui/components/icon"; -import { Tooltip } from "@calcom/ui/components/tooltip"; import { Button } from "@calcom/ui/components/button"; +import { Icon } from "@calcom/ui/components/icon"; import { showToast } from "@calcom/ui/components/toast"; +import { Tooltip } from "@calcom/ui/components/tooltip"; +import ServerTrans from "@calcom/web/components/ServerTrans"; export interface IZapierSetupProps { inviteLink?: string; @@ -124,13 +124,19 @@ export default function ZapierSetup(props: IZapierSetupProps) { )} - -
  • Log into your Zapier account and create a new Zap.
  • -
  • Select Cal.com as your Trigger app. Also choose a Trigger event.
  • -
  • Choose your account and then enter your Unique API Key.
  • -
  • Test your Trigger.
  • -
  • You're set!
  • -
    + Log into your Zapier account and create a new Zap., +
  • + Select Cal.com as your Trigger app. Also choose a Trigger event. +
  • , +
  • Choose your account and then enter your Unique API Key.
  • , +
  • Test your Trigger.
  • , +
  • You're set!
  • , + ]} + /> diff --git a/packages/emails/email-manager.ts b/packages/emails/email-manager.ts index d45cfc3ac0..2870182071 100644 --- a/packages/emails/email-manager.ts +++ b/packages/emails/email-manager.ts @@ -1,6 +1,6 @@ // eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import type { z } from "zod"; import type BaseEmail from "@calcom/emails/templates/_base-email"; diff --git a/packages/emails/lib/generateIcsFile.ts b/packages/emails/lib/generateIcsFile.ts index 53f2e32f09..022e20ff27 100644 --- a/packages/emails/lib/generateIcsFile.ts +++ b/packages/emails/lib/generateIcsFile.ts @@ -1,5 +1,5 @@ import type { EventStatus } from "ics"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/emails/lib/generateIcsString.ts b/packages/emails/lib/generateIcsString.ts index d3e327f544..f4563f66f1 100644 --- a/packages/emails/lib/generateIcsString.ts +++ b/packages/emails/lib/generateIcsString.ts @@ -1,6 +1,6 @@ import type { DateArray, ParticipationRole, EventStatus, ParticipationStatus } from "ics"; import { createEvent } from "ics"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { RRule } from "rrule"; import { getRichDescription } from "@calcom/lib/CalEventParser"; diff --git a/packages/emails/package.json b/packages/emails/package.json index 8327255745..1031261fe1 100644 --- a/packages/emails/package.json +++ b/packages/emails/package.json @@ -9,7 +9,7 @@ "dependencies": { "@calcom/dayjs": "*", "@calcom/lib": "*", - "next-i18next": "^13.2.2", + "next-i18next": "^15.4.2", "react": "^18.2.0", "react-dom": "^18.2.0", "rrule": "^2.7.1" diff --git a/packages/emails/src/components/AppsStatus.tsx b/packages/emails/src/components/AppsStatus.tsx index a42d8aefa9..e7f4e0d1fb 100644 --- a/packages/emails/src/components/AppsStatus.tsx +++ b/packages/emails/src/components/AppsStatus.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/emails/src/components/LocationInfo.tsx b/packages/emails/src/components/LocationInfo.tsx index 0766f905ca..999d523deb 100644 --- a/packages/emails/src/components/LocationInfo.tsx +++ b/packages/emails/src/components/LocationInfo.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { guessEventLocationType } from "@calcom/app-store/locations"; import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser"; diff --git a/packages/emails/src/components/UserFieldsResponses.tsx b/packages/emails/src/components/UserFieldsResponses.tsx index 0df70b467b..6d3fd92281 100644 --- a/packages/emails/src/components/UserFieldsResponses.tsx +++ b/packages/emails/src/components/UserFieldsResponses.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import getLabelValueMapFromResponses from "@calcom/lib/getLabelValueMapFromResponses"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/emails/src/components/WhenInfo.tsx b/packages/emails/src/components/WhenInfo.tsx index 5f27015d47..801df21731 100644 --- a/packages/emails/src/components/WhenInfo.tsx +++ b/packages/emails/src/components/WhenInfo.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { RRule } from "rrule"; import dayjs from "@calcom/dayjs"; diff --git a/packages/emails/src/components/WhoInfo.tsx b/packages/emails/src/components/WhoInfo.tsx index 0b3f199221..27341a1933 100644 --- a/packages/emails/src/components/WhoInfo.tsx +++ b/packages/emails/src/components/WhoInfo.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import isSmsCalEmail from "@calcom/lib/isSmsCalEmail"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/emails/src/templates/AdminOrganizationNotificationEmail.tsx b/packages/emails/src/templates/AdminOrganizationNotificationEmail.tsx index b6e9198e56..bbafb9e8cc 100644 --- a/packages/emails/src/templates/AdminOrganizationNotificationEmail.tsx +++ b/packages/emails/src/templates/AdminOrganizationNotificationEmail.tsx @@ -1,8 +1,7 @@ -"use client"; - -import { Trans, type TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import { BaseEmailHtml, CallToAction } from "../components"; @@ -92,20 +91,7 @@ export const AdminOrganizationNotificationEmail = ({ <>{language("hi_admin")}!

    - - An organization with slug {`"${orgSlug}"`} was created. -
    -
    - Please be sure to configure your DNS registry to point the subdomain corresponding to the new - organization to where the main app is running. Otherwise the organization will not work. -
    -
    - Here are just the very basic options to configure a subdomain to point to their app so it loads the - organization profile page. -
    -
    - You can do it either with the A Record: -
    +

    {dnsTable("A", orgSlug, webappIPAddress, language)}

    diff --git a/packages/emails/src/templates/BaseScheduledEmail.tsx b/packages/emails/src/templates/BaseScheduledEmail.tsx index 492317757e..14be1911c5 100644 --- a/packages/emails/src/templates/BaseScheduledEmail.tsx +++ b/packages/emails/src/templates/BaseScheduledEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import dayjs from "@calcom/dayjs"; import { formatPrice } from "@calcom/lib/price"; diff --git a/packages/emails/src/templates/BrokenIntegrationEmail.tsx b/packages/emails/src/templates/BrokenIntegrationEmail.tsx index d7ebe70026..cfdbcca8c8 100644 --- a/packages/emails/src/templates/BrokenIntegrationEmail.tsx +++ b/packages/emails/src/templates/BrokenIntegrationEmail.tsx @@ -1,11 +1,9 @@ -"use client"; - -import type { TFunction } from "next-i18next"; -import { Trans } from "react-i18next"; +import type { TFunction } from "i18next"; import { AppStoreLocationType } from "@calcom/app-store/locations"; import { WEBAPP_URL } from "@calcom/lib/constants"; import type { CalendarEvent, Person } from "@calcom/types/Calendar"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import { BaseScheduledEmail } from "./BaseScheduledEmail"; @@ -17,18 +15,27 @@ export function getEnumKeyByEnumValue(myEnum: any, enumValue: number | string): const BrokenVideoIntegration = (props: { location: string; eventTypeId?: number | null; t: TFunction }) => { return ( - - We could not add the {props.location} meeting link to your scheduled event. Contact your - invitees or update your calendar event to add the details. You can either  - - change your location on the event type - -  or try  - removing and adding the app again. - + + change your location on the event type + , + + removing and adding the app again. + , + ]} + /> ); }; @@ -40,12 +47,13 @@ const BrokenCalendarIntegration = (props: { const { t } = props; return ( - - We could not update your {props.calendar}.{" "} - - Please check your calendar settings or remove and add your calendar again - - +

    + {t("broken_calendar_action", { + calendar: props.calendar, + calendarSettingsLink: `${WEBAPP_URL}/apps/installed`, + interpolation: { escapeValue: false }, + })} +
    ); }; diff --git a/packages/emails/src/templates/DailyVideoDownloadRecordingEmail.tsx b/packages/emails/src/templates/DailyVideoDownloadRecordingEmail.tsx index d84c8a1f50..7d8bf81415 100644 --- a/packages/emails/src/templates/DailyVideoDownloadRecordingEmail.tsx +++ b/packages/emails/src/templates/DailyVideoDownloadRecordingEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { WEBAPP_URL, APP_NAME, COMPANY_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/DailyVideoDownloadTranscriptEmail.tsx b/packages/emails/src/templates/DailyVideoDownloadTranscriptEmail.tsx index 3c9fa5ae9f..fe583a14d3 100644 --- a/packages/emails/src/templates/DailyVideoDownloadTranscriptEmail.tsx +++ b/packages/emails/src/templates/DailyVideoDownloadTranscriptEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { WEBAPP_URL, COMPANY_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/DisabledAppEmail.tsx b/packages/emails/src/templates/DisabledAppEmail.tsx index 345ea0a76c..f24d7f8fc4 100644 --- a/packages/emails/src/templates/DisabledAppEmail.tsx +++ b/packages/emails/src/templates/DisabledAppEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { WEBAPP_URL } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/ForgotPasswordEmail.tsx b/packages/emails/src/templates/ForgotPasswordEmail.tsx index e04c336dd1..575ad42d05 100644 --- a/packages/emails/src/templates/ForgotPasswordEmail.tsx +++ b/packages/emails/src/templates/ForgotPasswordEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/MonthlyDigestEmail.tsx b/packages/emails/src/templates/MonthlyDigestEmail.tsx index 86e7c21a2e..78978a9e81 100644 --- a/packages/emails/src/templates/MonthlyDigestEmail.tsx +++ b/packages/emails/src/templates/MonthlyDigestEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, SENDER_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/OrgAutoInviteEmail.tsx b/packages/emails/src/templates/OrgAutoInviteEmail.tsx index 7bed163473..913e357dd5 100644 --- a/packages/emails/src/templates/OrgAutoInviteEmail.tsx +++ b/packages/emails/src/templates/OrgAutoInviteEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, WEBAPP_URL, IS_PRODUCTION } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/OrganizationAccountVerifyEmail.tsx b/packages/emails/src/templates/OrganizationAccountVerifyEmail.tsx index aa7ef5d989..8b0eb91c25 100644 --- a/packages/emails/src/templates/OrganizationAccountVerifyEmail.tsx +++ b/packages/emails/src/templates/OrganizationAccountVerifyEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, SUPPORT_MAIL_ADDRESS, COMPANY_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/OrganizationAdminNoSlots.tsx b/packages/emails/src/templates/OrganizationAdminNoSlots.tsx index d0da37e2aa..9770f1f746 100644 --- a/packages/emails/src/templates/OrganizationAdminNoSlots.tsx +++ b/packages/emails/src/templates/OrganizationAdminNoSlots.tsx @@ -1,5 +1,6 @@ -import type { TFunction } from "next-i18next"; -import { Trans } from "next-i18next"; +import type { TFunction } from "i18next"; + +import ServerTrans from "@calcom/web/components/ServerTrans"; import { BaseEmailHtml, CallToAction } from "../components"; @@ -30,25 +31,11 @@ export const OrganizationAdminNoSlotsEmail = ( <>{props.language("org_admin_no_slots|heading", { name: props.user })}

    - - Hello Organization Admins, -
    -
    - Please note: It has been brought to our attention that {props.user} has not had any availability - when a user has visited {props.teamSlug}/{props.slug}. -
    - Start time: {props.startTime} -
    - End time: {props.endTime} -
    -
    - There’s a few reasons why this could be happening: -
    -

      -
    • The user does not have any calendars connected
    • -
    • Their schedules attached to this event are not enabled
    • -
    -
    +

    {isNewUser ? ( - + <> Enjoy your new organization link: {newLinkWithoutProtocol} - + ) : ( - - Your link has been changed from {prevLinkWithoutProtocol} to{" "} - {newLinkWithoutProtocol} but don't worry, all previous links - still work and redirect appropriately. -
    -
    - Please note: All of your personal event types have been moved into the - {teamName} - {" "} - organisation, which may also include potential personal link. -
    -
    - Please log in and make sure you have no private events on your new organisational account. -
    -
    - For personal events we recommend creating a new account with a personal email address. -
    -
    - Enjoy your new clean link: {newLinkWithoutProtocol} -
    + + {prevLinkWithoutProtocol} + + ), + a1: ( + + {newLinkWithoutProtocol} + + ), + a2: ( + + {newLinkWithoutProtocol} + + ), + }} + values={{ teamName }} + /> )}

    diff --git a/packages/emails/src/templates/SlugReplacementEmail.tsx b/packages/emails/src/templates/SlugReplacementEmail.tsx index b8707a3b26..f1c65011eb 100644 --- a/packages/emails/src/templates/SlugReplacementEmail.tsx +++ b/packages/emails/src/templates/SlugReplacementEmail.tsx @@ -1,9 +1,7 @@ -"use client"; - -import type { TFunction } from "next-i18next"; -import { Trans } from "next-i18next"; +import type { TFunction } from "i18next"; import { WEBAPP_URL } from "@calcom/lib/constants"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import { BaseEmailHtml, CallToAction } from "../components"; @@ -23,22 +21,14 @@ export const SlugReplacementEmail = ( headerType="teamCircle" title={t("event_replaced_notice")}> <> - -

    Hi {name}

    -

    ,

    -
    - -

    - An administrator on the {teamName} team has replaced your event type{" "} - /{slug} with a managed event type that they control. -

    -
    - -

    - Your link will continue to work but some settings for it may have changed. You can review it in - event types. -

    -
    +

    + +

    +

    ,

    +

    + +

    +

    {t("email_body_slug_replacement_info")}

    - -

    - If you have any questions about the event type, please reach out to your administrator. -
    -
    - Happy scheduling,
    - The Cal.com team -

    -
    +

    + +

    {/*

    <>{t("email_body_slug_replacement_suggestion")}

    */} diff --git a/packages/emails/src/templates/TeamInviteEmail.tsx b/packages/emails/src/templates/TeamInviteEmail.tsx index 77ee69c4b0..2e403a3e0d 100644 --- a/packages/emails/src/templates/TeamInviteEmail.tsx +++ b/packages/emails/src/templates/TeamInviteEmail.tsx @@ -1,7 +1,7 @@ -import type { TFunction } from "next-i18next"; -import { Trans } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, WEBAPP_URL, IS_PRODUCTION } from "@calcom/lib/constants"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import { getSubject, getTypeOfInvite } from "../../templates/team-invite-email"; import { V2BaseEmailHtml, CallToAction } from "../components"; @@ -157,49 +157,48 @@ export const TeamInviteEmail = ( <> {autoJoinType == "added" ? ( <> - - {invitedBy} has added you to the {teamName} organization. - {" "} - - Your link has been changed from {prevLinkWithoutProtocol} to{" "} - {newLinkWithoutProtocol} but don't worry, all previous - links still work and redirect appropriately. -
    -
    - Please note: All of your personal event types have been moved into the{" "} - {teamName} organisation, which may also include potential personal link. -
    -
    - Please log in and make sure you have no private events on your new organisational account. -
    -
    - For personal events we recommend creating a new account with a personal email address. -
    -
    - Enjoy your new clean link:{" "} - {newLinkWithoutProtocol} -
    + {" "} + + {prevLinkWithoutProtocol} + + ), + a1: ( + + {newLinkWithoutProtocol} + + ), + a2: ( + + {newLinkWithoutProtocol} + + ), + }} + values={{ teamName, appName: APP_NAME }} + /> ) : ( <> - - {invitedBy} has invited you to join the {teamName} organization. - {" "} - {" "} + - On accepting the invite, your link will change to your organization domain but don't - worry, all previous links will still work and redirect appropriately. -
    -
    - Please note: All of your personal event types will be moved into the{" "} - {teamName} organisation, which may also include potential personal link. -
    -
    - For personal events we recommend creating a new account with a personal email address. -
    + values={{ teamName, appName: APP_NAME }} + /> )} @@ -208,18 +207,20 @@ export const TeamInviteEmail = ( return ( <> {autoJoinType === "added" ? ( - - {invitedBy} has added you to the {teamName} organization. - + ) : ( - - {invitedBy} has invited you to join the {teamName} organization. - + )}{" "} - - {appName} is the event-juggling scheduler that enables you and your team to schedule meetings - without the email tennis. - + {appName} is the event-juggling scheduler that enables you and your team to schedule meetings + without the email tennis. ); } @@ -228,20 +229,20 @@ export const TeamInviteEmail = ( return ( <> {autoJoinType === "added" ? ( - - {invitedBy} has added you to the team {teamName} in their organization{" "} - {parentTeamName}. - + ) : ( - - {invitedBy} has invited you to the team {teamName} in their organization{" "} - {parentTeamName}. - + )}{" "} - - {appName} is the event-juggling scheduler that enables you and your team to schedule meetings - without the email tennis. - + {appName} is the event-juggling scheduler that enables you and your team to schedule meetings + without the email tennis. ); } diff --git a/packages/emails/src/templates/VerifyAccountEmail.tsx b/packages/emails/src/templates/VerifyAccountEmail.tsx index fa82f353a0..b145f75106 100644 --- a/packages/emails/src/templates/VerifyAccountEmail.tsx +++ b/packages/emails/src/templates/VerifyAccountEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, SENDER_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants"; diff --git a/packages/emails/src/templates/VerifyEmailChangeEmail.tsx b/packages/emails/src/templates/VerifyEmailChangeEmail.tsx index d0c62c710e..bc5fe0d023 100644 --- a/packages/emails/src/templates/VerifyEmailChangeEmail.tsx +++ b/packages/emails/src/templates/VerifyEmailChangeEmail.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, SENDER_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/_base-email.ts b/packages/emails/templates/_base-email.ts index 74c3a6e6f7..d2150c0856 100644 --- a/packages/emails/templates/_base-email.ts +++ b/packages/emails/templates/_base-email.ts @@ -1,5 +1,4 @@ import { decodeHTML } from "entities"; -import { createTransport } from "nodemailer"; import { z } from "zod"; import dayjs from "@calcom/dayjs"; @@ -71,6 +70,7 @@ export default class BaseEmail { }, ...(parseSubject.success && { subject: decodeHTML(parseSubject.data) }), }; + const { createTransport } = await import("nodemailer"); await new Promise((resolve, reject) => createTransport(this.getMailerOptions().transport).sendMail( payloadWithUnEscapedSubject, diff --git a/packages/emails/templates/account-verify-email.ts b/packages/emails/templates/account-verify-email.ts index cbad2a6b1b..57909dc90d 100644 --- a/packages/emails/templates/account-verify-email.ts +++ b/packages/emails/templates/account-verify-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, COMPANY_NAME, EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/admin-organization-notification.ts b/packages/emails/templates/admin-organization-notification.ts index 7c277a04f8..11f916d406 100644 --- a/packages/emails/templates/admin-organization-notification.ts +++ b/packages/emails/templates/admin-organization-notification.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/attendee-daily-video-download-recording-email.ts b/packages/emails/templates/attendee-daily-video-download-recording-email.ts index f89819dde6..ddfc108d8b 100644 --- a/packages/emails/templates/attendee-daily-video-download-recording-email.ts +++ b/packages/emails/templates/attendee-daily-video-download-recording-email.ts @@ -1,5 +1,5 @@ // TODO: We should find a way to keep App specific email templates within the App itself -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { TimeFormat } from "@calcom/lib/timeFormat"; import type { CalendarEvent, Person } from "@calcom/types/Calendar"; diff --git a/packages/emails/templates/attendee-daily-video-download-transcript-email.ts b/packages/emails/templates/attendee-daily-video-download-transcript-email.ts index 4fc2404934..4fb52a1b25 100644 --- a/packages/emails/templates/attendee-daily-video-download-transcript-email.ts +++ b/packages/emails/templates/attendee-daily-video-download-transcript-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { TimeFormat } from "@calcom/lib/timeFormat"; import type { CalendarEvent, Person } from "@calcom/types/Calendar"; diff --git a/packages/emails/templates/attendee-scheduled-email.ts b/packages/emails/templates/attendee-scheduled-email.ts index 907cb1242c..a1a3b715cc 100644 --- a/packages/emails/templates/attendee-scheduled-email.ts +++ b/packages/emails/templates/attendee-scheduled-email.ts @@ -1,6 +1,6 @@ // eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { getRichDescription } from "@calcom/lib/CalEventParser"; import { TimeFormat } from "@calcom/lib/timeFormat"; diff --git a/packages/emails/templates/attendee-verify-email.ts b/packages/emails/templates/attendee-verify-email.ts index 5024fe0089..f362db3724 100644 --- a/packages/emails/templates/attendee-verify-email.ts +++ b/packages/emails/templates/attendee-verify-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, COMPANY_NAME, EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/booking-redirect-notification.ts b/packages/emails/templates/booking-redirect-notification.ts index 4369d06391..25375da3bb 100644 --- a/packages/emails/templates/booking-redirect-notification.ts +++ b/packages/emails/templates/booking-redirect-notification.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/broken-integration-email.ts b/packages/emails/templates/broken-integration-email.ts index 14555256ce..801844cbf5 100644 --- a/packages/emails/templates/broken-integration-email.ts +++ b/packages/emails/templates/broken-integration-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { getRichDescription } from "@calcom/lib/CalEventParser"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/change-account-email-verify.ts b/packages/emails/templates/change-account-email-verify.ts index e5c75230f8..ae792fc273 100644 --- a/packages/emails/templates/change-account-email-verify.ts +++ b/packages/emails/templates/change-account-email-verify.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, COMPANY_NAME, EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/disabled-app-email.ts b/packages/emails/templates/disabled-app-email.ts index 85c75bbd61..a6510db62b 100644 --- a/packages/emails/templates/disabled-app-email.ts +++ b/packages/emails/templates/disabled-app-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/forgot-password-email.ts b/packages/emails/templates/forgot-password-email.ts index 2fde8e3baf..909b8c50f2 100644 --- a/packages/emails/templates/forgot-password-email.ts +++ b/packages/emails/templates/forgot-password-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/org-auto-join-invite.ts b/packages/emails/templates/org-auto-join-invite.ts index c295eca9d8..9615dff07e 100644 --- a/packages/emails/templates/org-auto-join-invite.ts +++ b/packages/emails/templates/org-auto-join-invite.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/organization-admin-no-slots-email.ts b/packages/emails/templates/organization-admin-no-slots-email.ts index 5170724da6..e9494013ca 100644 --- a/packages/emails/templates/organization-admin-no-slots-email.ts +++ b/packages/emails/templates/organization-admin-no-slots-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/organization-creation-email.ts b/packages/emails/templates/organization-creation-email.ts index c6adc77430..bcc7a5d859 100644 --- a/packages/emails/templates/organization-creation-email.ts +++ b/packages/emails/templates/organization-creation-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/organization-email-verification.ts b/packages/emails/templates/organization-email-verification.ts index 0722662477..70a32c10a2 100644 --- a/packages/emails/templates/organization-email-verification.ts +++ b/packages/emails/templates/organization-email-verification.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/organizer-daily-video-download-recording-email.ts b/packages/emails/templates/organizer-daily-video-download-recording-email.ts index ff80acf5c1..28a25f6a69 100644 --- a/packages/emails/templates/organizer-daily-video-download-recording-email.ts +++ b/packages/emails/templates/organizer-daily-video-download-recording-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; import { TimeFormat } from "@calcom/lib/timeFormat"; diff --git a/packages/emails/templates/organizer-daily-video-download-transcript-email.ts b/packages/emails/templates/organizer-daily-video-download-transcript-email.ts index 763387306e..f1320a73e9 100644 --- a/packages/emails/templates/organizer-daily-video-download-transcript-email.ts +++ b/packages/emails/templates/organizer-daily-video-download-transcript-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; import { TimeFormat } from "@calcom/lib/timeFormat"; diff --git a/packages/emails/templates/organizer-scheduled-email.ts b/packages/emails/templates/organizer-scheduled-email.ts index 4c62a4219f..24d6effde7 100644 --- a/packages/emails/templates/organizer-scheduled-email.ts +++ b/packages/emails/templates/organizer-scheduled-email.ts @@ -1,6 +1,6 @@ // eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { getRichDescription } from "@calcom/lib/CalEventParser"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/slug-replacement-email.ts b/packages/emails/templates/slug-replacement-email.ts index 90133beee2..053aacd144 100644 --- a/packages/emails/templates/slug-replacement-email.ts +++ b/packages/emails/templates/slug-replacement-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/emails/templates/team-invite-email.ts b/packages/emails/templates/team-invite-email.ts index 145a4b44e2..52f0130eb6 100644 --- a/packages/emails/templates/team-invite-email.ts +++ b/packages/emails/templates/team-invite-email.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { APP_NAME, EMAIL_FROM_NAME } from "@calcom/lib/constants"; diff --git a/packages/embeds/embed-core/src/useCompatSearchParams.tsx b/packages/embeds/embed-core/src/useCompatSearchParams.tsx index ef6c6587ef..c1076f6df8 100644 --- a/packages/embeds/embed-core/src/useCompatSearchParams.tsx +++ b/packages/embeds/embed-core/src/useCompatSearchParams.tsx @@ -1,4 +1,5 @@ -// this file is copied from '@calcom/lib/hooks/useCompatSearchParams.tsx' +"use client"; + import { ReadonlyURLSearchParams, useParams, useSearchParams } from "next/navigation"; export const useCompatSearchParams = () => { diff --git a/packages/features/apps/components/appCard.test.tsx b/packages/features/apps/components/appCard.test.tsx index fc3760651a..3f1661ef85 100644 --- a/packages/features/apps/components/appCard.test.tsx +++ b/packages/features/apps/components/appCard.test.tsx @@ -1,11 +1,19 @@ /* eslint-disable playwright/missing-playwright-await */ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { render, screen } from "@testing-library/react"; +import { vi, describe, expect } from "vitest"; import type { AppFrontendPayload } from "@calcom/types/App"; import { AppCard } from "./AppCard"; +vi.mock("next/navigation", () => ({ + useRouter: vi.fn().mockReturnValue({ + push: vi.fn(), + }), + usePathname: vi.fn(), +})); + describe("Tests for AppCard component", () => { const mockApp: AppFrontendPayload = { logo: "/path/to/logo.png", @@ -34,7 +42,7 @@ describe("Tests for AppCard component", () => { }; describe("Tests for app description", () => { - test("Should render the app name correctly and display app logo with correct alt text", () => { + it("Should render the app name correctly and display app logo with correct alt text", () => { renderAppCard(); const appLogo = screen.getByAltText("Test App Logo"); const appName = screen.getByText("Test App"); @@ -43,14 +51,14 @@ describe("Tests for AppCard component", () => { expect(appName).toBeInTheDocument(); }); - test("Should render details button with correct href", () => { + it("Should render details button with correct href", () => { renderAppCard(); const detailsButton = screen.getByText("details"); expect(detailsButton).toBeInTheDocument(); expect(detailsButton.closest("a")).toHaveAttribute("href", "/apps/test-app"); }); - test("Should highlight the app name based on searchText", () => { + it("Should highlight the app name based on searchText", () => { renderAppCard({}, { searchText: "test" }); const highlightedText = screen.getByTestId("highlighted-text"); expect(highlightedText).toBeInTheDocument(); @@ -58,13 +66,13 @@ describe("Tests for AppCard component", () => { }); describe("Tests for app categories", () => { - test("Should show 'Template' badge if app is a template", () => { + it("Should show 'Template' badge if app is a template", () => { renderAppCard({ isTemplate: true }); const templateBadge = screen.getByText("Template"); expect(templateBadge).toBeInTheDocument(); }); - test("Should show 'default' badge if app is default or global", () => { + it("Should show 'default' badge if app is default or global", () => { renderAppCard({ isDefault: true }); const defaultBadge = screen.getByText("default"); expect(defaultBadge).toBeInTheDocument(); diff --git a/packages/features/auth/lib/passwordResetRequest.ts b/packages/features/auth/lib/passwordResetRequest.ts index 3c4f3509a7..e1e5b1d259 100644 --- a/packages/features/auth/lib/passwordResetRequest.ts +++ b/packages/features/auth/lib/passwordResetRequest.ts @@ -1,7 +1,6 @@ import type { User } from "@prisma/client"; import dayjs from "@calcom/dayjs"; -import { sendPasswordResetEmail } from "@calcom/emails"; import { getTranslation } from "@calcom/lib/server/i18n"; import prisma from "@calcom/prisma"; @@ -40,6 +39,8 @@ const passwordResetRequest = async (user: Pick - The selected time slot is no longer available.{" "} - - + + Please select a new time + , + ]} + /> } /> @@ -154,7 +161,8 @@ export const BookEventForm = ({ {!isPlatform && (
    - { {fromUser?.displayName && toUser?.displayName && (

    - username]} />

    diff --git a/packages/features/bookings/Booker/components/hooks/useBookings.ts b/packages/features/bookings/Booker/components/hooks/useBookings.ts index a8bc894570..47b7444979 100644 --- a/packages/features/bookings/Booker/components/hooks/useBookings.ts +++ b/packages/features/bookings/Booker/components/hooks/useBookings.ts @@ -1,3 +1,5 @@ +"use client"; + import { useMutation } from "@tanstack/react-query"; import { useRouter } from "next/navigation"; import { useRef, useState, useEffect } from "react"; diff --git a/packages/features/bookings/components/event-meta/Duration.tsx b/packages/features/bookings/components/event-meta/Duration.tsx index 853364c6b4..7e8bf9be14 100644 --- a/packages/features/bookings/components/event-meta/Duration.tsx +++ b/packages/features/bookings/components/event-meta/Duration.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { useEffect, useRef } from "react"; import { useIsPlatform } from "@calcom/atoms/hooks/useIsPlatform"; diff --git a/packages/features/bookings/lib/handleNewBooking/types.ts b/packages/features/bookings/lib/handleNewBooking/types.ts index ace8788910..83f40475bc 100644 --- a/packages/features/bookings/lib/handleNewBooking/types.ts +++ b/packages/features/bookings/lib/handleNewBooking/types.ts @@ -1,6 +1,6 @@ import type { App } from "@prisma/client"; import type { Prisma } from "@prisma/client"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import type { EventTypeAppsList } from "@calcom/app-store/utils"; import type { PaymentAppData } from "@calcom/lib/getPaymentAppData"; diff --git a/packages/features/ee/dsync/lib/inviteExistingUserToOrg.ts b/packages/features/ee/dsync/lib/inviteExistingUserToOrg.ts index 3ccb8a1b5f..c2b8733e55 100644 --- a/packages/features/ee/dsync/lib/inviteExistingUserToOrg.ts +++ b/packages/features/ee/dsync/lib/inviteExistingUserToOrg.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { createAProfileForAnExistingUser } from "@calcom/lib/createAProfileForAnExistingUser"; import prisma from "@calcom/prisma"; diff --git a/packages/features/ee/dsync/lib/users/inviteExistingUserToOrg.ts b/packages/features/ee/dsync/lib/users/inviteExistingUserToOrg.ts index 452441ecd8..a382b7f1c9 100644 --- a/packages/features/ee/dsync/lib/users/inviteExistingUserToOrg.ts +++ b/packages/features/ee/dsync/lib/users/inviteExistingUserToOrg.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { createAProfileForAnExistingUser } from "@calcom/lib/createAProfileForAnExistingUser"; import prisma from "@calcom/prisma"; diff --git a/packages/features/ee/managed-event-types/hooks/useLockedFieldsManager.tsx b/packages/features/ee/managed-event-types/hooks/useLockedFieldsManager.tsx index ba4eb344f3..a26044d99b 100644 --- a/packages/features/ee/managed-event-types/hooks/useLockedFieldsManager.tsx +++ b/packages/features/ee/managed-event-types/hooks/useLockedFieldsManager.tsx @@ -1,6 +1,6 @@ // eslint-disable-next-line no-restricted-imports import { get } from "lodash"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import type { Dispatch, SetStateAction } from "react"; import { useState } from "react"; import type { UseFormReturn } from "react-hook-form"; diff --git a/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.test.ts b/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.test.ts index 94724870ea..2923a02561 100644 --- a/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.test.ts +++ b/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.test.ts @@ -30,32 +30,6 @@ vi.mock("@calcom/trpc/server/routers/viewer/organizations/createTeams.handler", createTeamsHandler: vi.fn(), })); -vi.mock("next-i18next", () => ({ - serverSideTranslations: vi.fn().mockImplementation(async () => { - return { - _nextI18Next: { - initialI18nStore: { - en: { - common: {}, - }, - }, - userConfig: { - i18n: { - defaultLocale: "en", - locales: ["en"], - }, - }, - }, - }; - }), - i18n: { - language: "en", - languages: ["en"], - defaultLocale: "en", - getFixedT: () => (key: string) => key, - }, -})); - vi.mock("@calcom/lib/domainManager/organization", () => ({ createDomain: vi.fn(), })); diff --git a/packages/features/ee/organizations/pages/settings/admin/AdminOrgPage.tsx b/packages/features/ee/organizations/pages/settings/admin/AdminOrgPage.tsx index df14aa3e8a..5743ef36fe 100644 --- a/packages/features/ee/organizations/pages/settings/admin/AdminOrgPage.tsx +++ b/packages/features/ee/organizations/pages/settings/admin/AdminOrgPage.tsx @@ -1,6 +1,5 @@ "use client"; -import { Trans } from "next-i18next"; import { useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; @@ -9,6 +8,7 @@ import { Badge } from "@calcom/ui/components/badge"; import { Dialog, ConfirmationDialogContent } from "@calcom/ui/components/dialog"; import { DropdownActions, Table } from "@calcom/ui/components/table"; import { showToast } from "@calcom/ui/components/toast"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import { subdomainSuffix } from "../../../../organizations/lib/orgDomains"; @@ -251,20 +251,12 @@ const DeleteOrgDialog = ({ cancelBtnText={t("cancel")} variety="danger" onConfirm={onConfirm}> - , ul:
      }}> -
        -
      • - Teams that are member of this organization will also be deleted along with their event-types -
      • -
      • - Users that were part of the organization will not be deleted and their event-types will also - remain intact. -
      • -
      • Usernames would be changed to allow them to exist outside the organization
      • -
      - +
        +
      • {t("admin_delete_organization_description_1")}
      • +
      • {t("admin_delete_organization_description_2")}
      • +
      • {t("admin_delete_organization_description_3")}
      • +
      • {t("admin_delete_organization_description_4")}
      • +
      ); diff --git a/packages/features/ee/payments/components/Payment.tsx b/packages/features/ee/payments/components/Payment.tsx index 92c4b30694..7f6f561bf6 100644 --- a/packages/features/ee/payments/components/Payment.tsx +++ b/packages/features/ee/payments/components/Payment.tsx @@ -1,3 +1,5 @@ +"use client"; + import type { EventType, Payment } from "@prisma/client"; import { Elements, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js"; import type { StripeElementLocale, StripeElements, StripePaymentElementOptions } from "@stripe/stripe-js"; diff --git a/packages/features/ee/platform/components/CreateANewPlatformForm.tsx b/packages/features/ee/platform/components/CreateANewPlatformForm.tsx index b25b868c04..344bf5d973 100644 --- a/packages/features/ee/platform/components/CreateANewPlatformForm.tsx +++ b/packages/features/ee/platform/components/CreateANewPlatformForm.tsx @@ -10,8 +10,9 @@ import { uuid } from "short-uuid"; import { deriveOrgNameFromEmail } from "@calcom/ee/organizations/components/CreateANewOrganizationForm"; import { deriveSlugFromEmail } from "@calcom/ee/organizations/components/CreateANewOrganizationForm"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; import slugify from "@calcom/lib/slugify"; -import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { telemetryEventTypes } from "@calcom/lib/telemetry"; import { UserPermissionRole } from "@calcom/prisma/enums"; import { CreationSource } from "@calcom/prisma/enums"; import { trpc } from "@calcom/trpc/react"; diff --git a/packages/features/ee/teams/components/AddNewTeamMembers.tsx b/packages/features/ee/teams/components/AddNewTeamMembers.tsx index 07103e0c02..554d93e26c 100644 --- a/packages/features/ee/teams/components/AddNewTeamMembers.tsx +++ b/packages/features/ee/teams/components/AddNewTeamMembers.tsx @@ -1,3 +1,5 @@ +"use client"; + import { keepPreviousData } from "@tanstack/react-query"; import { useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; @@ -9,7 +11,8 @@ import { MemberInvitationModalWithoutMembers } from "@calcom/features/ee/teams/c import { APP_NAME } from "@calcom/lib/constants"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; +import { telemetryEventTypes } from "@calcom/lib/telemetry"; import { MembershipRole } from "@calcom/prisma/enums"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; diff --git a/packages/features/ee/teams/components/MemberInvitationModal.tsx b/packages/features/ee/teams/components/MemberInvitationModal.tsx index dcdf77562a..92bdbde216 100644 --- a/packages/features/ee/teams/components/MemberInvitationModal.tsx +++ b/packages/features/ee/teams/components/MemberInvitationModal.tsx @@ -1,5 +1,4 @@ import { useSession } from "next-auth/react"; -import { Trans } from "next-i18next"; import type { FormEvent } from "react"; import { useMemo, useRef, useState } from "react"; import { Controller, useForm } from "react-hook-form"; @@ -13,10 +12,10 @@ import { CreationSource } from "@calcom/prisma/enums"; import type { RouterOutputs } from "@calcom/trpc"; import { trpc } from "@calcom/trpc"; import { isEmail } from "@calcom/trpc/server/routers/viewer/teams/util"; -import { TextAreaField } from "@calcom/ui/components/form"; -import { Button } from "@calcom/ui/components/button"; import classNames from "@calcom/ui/classNames"; +import { Button } from "@calcom/ui/components/button"; import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/components/dialog"; +import { TextAreaField } from "@calcom/ui/components/form"; import { Form } from "@calcom/ui/components/form"; import { Label } from "@calcom/ui/components/form"; import { TextField } from "@calcom/ui/components/form"; @@ -24,6 +23,7 @@ import { Select } from "@calcom/ui/components/form"; import { ToggleGroup } from "@calcom/ui/components/form"; import { Icon } from "@calcom/ui/components/icon"; import { showToast } from "@calcom/ui/components/toast"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import type { PendingMember } from "../lib/types"; import { GoogleWorkspaceInviteButton } from "./GoogleWorkspaceInviteButton"; @@ -205,10 +205,15 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps) description={ IS_TEAM_BILLING_ENABLED_CLIENT && !currentOrg ? ( - - Note: This will cost an extra seat ($15/m){" "} - on your subscription. - + + cost an extra seat ($15/m) + , + ]} + /> ) : null }> diff --git a/packages/features/ee/teams/components/createButton/create-button-with-teams-list.test.tsx b/packages/features/ee/teams/components/createButton/create-button-with-teams-list.test.tsx index d2eb778bc8..2db6c2062e 100644 --- a/packages/features/ee/teams/components/createButton/create-button-with-teams-list.test.tsx +++ b/packages/features/ee/teams/components/createButton/create-button-with-teams-list.test.tsx @@ -5,6 +5,20 @@ import { vi } from "vitest"; import type { CreateBtnProps } from "./CreateButton"; import { CreateButtonWithTeamsList } from "./CreateButtonWithTeamsList"; +const mockRouter = { + push: vi.fn((path: string) => { + return; + }), +}; + +vi.mock("next/navigation", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + useRouter: vi.fn(() => mockRouter), + }; +}); + const runtimeMock = async (data: Array) => { const updatedTrpc = { viewer: { diff --git a/packages/features/ee/workflows/lib/getOptions.ts b/packages/features/ee/workflows/lib/getOptions.ts index c1a58dc01b..cda37286a0 100644 --- a/packages/features/ee/workflows/lib/getOptions.ts +++ b/packages/features/ee/workflows/lib/getOptions.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import type { WorkflowActions } from "@calcom/prisma/enums"; import { WorkflowTemplates, WorkflowTriggerEvents } from "@calcom/prisma/enums"; diff --git a/packages/features/ee/workflows/lib/getWorkflowReminders.ts b/packages/features/ee/workflows/lib/getWorkflowReminders.ts index 0dbaab08c6..e41ca972bc 100644 --- a/packages/features/ee/workflows/lib/getWorkflowReminders.ts +++ b/packages/features/ee/workflows/lib/getWorkflowReminders.ts @@ -89,9 +89,9 @@ export async function getAllRemindersToDelete(): Promise()({ referenceId: true, - }; + }); const remindersToDelete = await getWorkflowReminders(whereFilter, select); @@ -109,10 +109,10 @@ export async function getAllRemindersToCancel(): Promise()({ referenceId: true, id: true, - }; + }); const remindersToCancel = await getWorkflowReminders(whereFilter, select); diff --git a/packages/features/ee/workflows/lib/variableTranslations.ts b/packages/features/ee/workflows/lib/variableTranslations.ts index 29810cd615..7e030bc36a 100644 --- a/packages/features/ee/workflows/lib/variableTranslations.ts +++ b/packages/features/ee/workflows/lib/variableTranslations.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { DYNAMIC_TEXT_VARIABLES, FORMATTED_DYNAMIC_TEXT_VARIABLES } from "./constants"; diff --git a/packages/features/eventtypes/components/EditWeightsForAllTeamMembers.tsx b/packages/features/eventtypes/components/EditWeightsForAllTeamMembers.tsx index 96fd1aaf5a..24ff64b7cf 100644 --- a/packages/features/eventtypes/components/EditWeightsForAllTeamMembers.tsx +++ b/packages/features/eventtypes/components/EditWeightsForAllTeamMembers.tsx @@ -1,6 +1,5 @@ "use client"; -import { Trans } from "next-i18next"; import Link from "next/link"; import { useState, useEffect, useRef, useMemo } from "react"; @@ -24,6 +23,7 @@ import { SheetTitle, } from "@calcom/ui/components/sheet"; import { showToast } from "@calcom/ui/components/toast"; +import ServerTrans from "@calcom/web/components/ServerTrans"; type TeamMemberItemProps = { member: Omit & { weight?: number }; @@ -302,15 +302,19 @@ export const EditWeightsForAllTeamMembers = ({ {t("edit_team_member_weights")}
      - - Weights determine how meetings are distributed among hosts. - - Learn more - - + + Learn more + , + ]} + />
      diff --git a/packages/features/eventtypes/components/HostEditDialogs.tsx b/packages/features/eventtypes/components/HostEditDialogs.tsx index db068d08da..daff7c02eb 100644 --- a/packages/features/eventtypes/components/HostEditDialogs.tsx +++ b/packages/features/eventtypes/components/HostEditDialogs.tsx @@ -1,5 +1,3 @@ -import { Trans } from "next-i18next"; -import Link from "next/link"; import type { Dispatch, SetStateAction } from "react"; import { useState } from "react"; import { useFormContext } from "react-hook-form"; @@ -19,6 +17,7 @@ import classNames from "@calcom/ui/classNames"; import { Dialog, DialogContent, DialogFooter, DialogClose } from "@calcom/ui/components/dialog"; import type { CheckedSelectOption } from "./CheckedTeamSelect"; +import WeightDescription from "./WeightDescription"; interface IDialog { isOpenDialog: boolean; @@ -99,18 +98,6 @@ export const PriorityDialog = ( ); }; -export const weightDescription = ( - - Weights determine how meetings are distributed among hosts. - - Learn more - - -); - export function sortHosts( hostA: { priority: number | null; weight: number | null }, hostB: { priority: number | null; weight: number | null }, @@ -167,7 +154,7 @@ export const WeightDialog = (props: IDialog & { customClassNames?: WeightDialogC return ( - + }>

      - - The “Add to calendar” for this event type needs to be a Google Calendar for Meet to work. - Connect it - - here - - . - + + here + , + ]} + />

    )} @@ -480,13 +484,18 @@ const Locations: React.FC = ({ {props.showAppStoreLink && !isPlatorm && (

    - - Can't find the right conferencing app? Visit our - - App Store - - . - + + App Store + , + ]} + />

    )} diff --git a/packages/features/eventtypes/components/WeightDescription.tsx b/packages/features/eventtypes/components/WeightDescription.tsx new file mode 100644 index 0000000000..2b1aec5b84 --- /dev/null +++ b/packages/features/eventtypes/components/WeightDescription.tsx @@ -0,0 +1,22 @@ +import type { TFunction } from "i18next"; +import Link from "next/link"; + +import ServerTrans from "@calcom/web/components/ServerTrans"; + +export default function WeightDescription({ t }: { t: TFunction }) { + return ( + + Learn more + , + ]} + /> + ); +} diff --git a/packages/features/eventtypes/components/dialogs/DeleteDialog.tsx b/packages/features/eventtypes/components/dialogs/DeleteDialog.tsx index dc7f2eef9e..cf58700c45 100644 --- a/packages/features/eventtypes/components/dialogs/DeleteDialog.tsx +++ b/packages/features/eventtypes/components/dialogs/DeleteDialog.tsx @@ -1,8 +1,8 @@ -import { Trans } from "next-i18next"; - import { useLocale } from "@calcom/lib/hooks/useLocale"; +import classNames from "@calcom/ui/classNames"; import type { DialogProps } from "@calcom/ui/components/dialog"; import { ConfirmationDialogContent, Dialog } from "@calcom/ui/components/dialog"; +import ServerTrans from "@calcom/web/components/ServerTrans"; export function DeleteDialog({ isManagedEvent, @@ -32,14 +32,14 @@ export function DeleteDialog({ onDelete(eventTypeId); }}>

    - , ul:

      }}> -
        -
      • Members assigned to this event type will also have their event types deleted.
      • -
      • Anyone who they've shared their link with will no longer be able to book using it.
      • + {isManagedEvent ? ( +
          +
        • {t("delete_managed_event_type_description_1")}
        • +
        • {t("delete_managed_event_type_description_2")}
        - + ) : ( + t("delete_event_type_description") + )}

        diff --git a/packages/features/eventtypes/components/dialogs/ManagedEventDialog.tsx b/packages/features/eventtypes/components/dialogs/ManagedEventDialog.tsx index 81d19e1564..e337507f89 100644 --- a/packages/features/eventtypes/components/dialogs/ManagedEventDialog.tsx +++ b/packages/features/eventtypes/components/dialogs/ManagedEventDialog.tsx @@ -1,8 +1,7 @@ -import { Trans } from "next-i18next"; - import type { ChildrenEventType } from "@calcom/features/eventtypes/components/ChildrenEventTypeSelect"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { ConfirmationDialogContent, Dialog } from "@calcom/ui/components/dialog"; +import ServerTrans from "@calcom/web/components/ServerTrans"; interface ManagedEventDialogProps { slugExistsChildrenDialogOpen: ChildrenEventType[]; @@ -31,8 +30,13 @@ export default function ManagedEventDialog(props: ManagedEventDialogProps) { cancelBtnText={t("go_back")} onConfirm={onConfirm}>

        - 1 + ? "managed_event_dialog_information_other" + : "managed_event_dialog_information_one" + } values={{ names: `${slugExistsChildrenDialogOpen .map((ch) => ch.owner.name) @@ -42,7 +46,6 @@ export default function ManagedEventDialog(props: ManagedEventDialogProps) { } ${slugExistsChildrenDialogOpen.map((ch) => ch.owner.name).slice(-1)}`, slug, }} - count={slugExistsChildrenDialogOpen.length} />

        {" "}

        {t("managed_event_dialog_clarification")}

        diff --git a/packages/features/eventtypes/components/tabs/advanced/DisableAllEmailsSetting.tsx b/packages/features/eventtypes/components/tabs/advanced/DisableAllEmailsSetting.tsx index e2265481f5..785250d8e8 100644 --- a/packages/features/eventtypes/components/tabs/advanced/DisableAllEmailsSetting.tsx +++ b/packages/features/eventtypes/components/tabs/advanced/DisableAllEmailsSetting.tsx @@ -1,13 +1,13 @@ -import type { TFunction } from "next-i18next"; -import { Trans } from "next-i18next"; +import type { TFunction } from "i18next"; import { useState } from "react"; import type { InputClassNames, SettingsToggleClassNames } from "@calcom/features/eventtypes/lib/types"; -import { InputField } from "@calcom/ui/components/form"; -import { Button } from "@calcom/ui/components/button"; import classNames from "@calcom/ui/classNames"; +import { Button } from "@calcom/ui/components/button"; import { Dialog, DialogContent, DialogFooter, DialogClose } from "@calcom/ui/components/dialog"; +import { InputField } from "@calcom/ui/components/form"; import { SettingsToggle } from "@calcom/ui/components/form"; +import ServerTrans from "@calcom/web/components/ServerTrans"; export type EmailNotificationToggleCustomClassNames = SettingsToggleClassNames & { confirmationDialog?: { @@ -53,15 +53,7 @@ export const DisableAllEmailsSetting = ({ className={customClassNames?.confirmationDialog?.container}>

        - - This will disable all emails to {recipient}. This includes booking confirmations, requests, - reschedules and reschedule requests, cancellation emails, and any other emails related to - booking updates. -
        -
        - It is your responsibility to ensure that your {recipient} are aware of any bookings and changes - to their bookings. -
        +

        - - { - const val = Number(evt.target?.value); + components={[ +

        + { + const val = Number(evt.target?.value); + setRequiresConfirmationSetup({ + unit: + requiresConfirmationSetup?.unit ?? + defaultRequiresConfirmationSetup.unit, + time: val, + }); + formMethods.setValue( + "metadata.requiresConfirmationThreshold.time", + val, + { shouldDirty: true } + ); + }} + className={classNames( + "border-default h-9! !m-0 block w-16 rounded-r-none border-r-0 text-sm [appearance:textfield] focus:z-10 focus:border-r", + customClassNames?.conditionalConfirmationRadio?.timeInput + )} + defaultValue={metadata?.requiresConfirmationThreshold?.time || 30} + /> + -
        - ), - }} + + , + ]} /> } diff --git a/packages/features/eventtypes/components/tabs/apps/EventAppsTab.tsx b/packages/features/eventtypes/components/tabs/apps/EventAppsTab.tsx index 6999d840ac..e4074ad581 100644 --- a/packages/features/eventtypes/components/tabs/apps/EventAppsTab.tsx +++ b/packages/features/eventtypes/components/tabs/apps/EventAppsTab.tsx @@ -1,4 +1,3 @@ -import { Trans } from "next-i18next"; import Link from "next/link"; import { useFormContext } from "react-hook-form"; @@ -10,9 +9,10 @@ import type { FormValues, EventTypeSetupProps } from "@calcom/features/eventtype import useAppsData from "@calcom/lib/hooks/useAppsData"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import { EmptyScreen } from "@calcom/ui/components/empty-screen"; import { Alert } from "@calcom/ui/components/alert"; import { Button } from "@calcom/ui/components/button"; +import { EmptyScreen } from "@calcom/ui/components/empty-screen"; +import ServerTrans from "@calcom/web/components/ServerTrans"; export type EventType = Pick["eventType"] & EventTypeAppCardComponentProps["eventType"]; @@ -97,22 +97,19 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => { severity={appsDisableProps.isLocked ? "neutral" : "info"} className="mb-2" title={ - - {lockedText[0].toUpperCase()} - {lockedText.slice(1)} {isManagedEventType ? "for members" : "by team admins"} - + } actions={
        {appsDisableProps.LockedIcon}
        } message={ - - {isManagedEventType ? "Members" : "You"}{" "} - {appsDisableProps.isLocked - ? "will be able to see the active apps but will not be able to edit any app settings" - : "will be able to see the active apps and will be able to edit any app settings"} - + }_description`} + /> } /> )} @@ -162,12 +159,15 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => { {t("available_apps_lower_case")}

        - - View popular apps below and explore more in our   - - App Store - - + + App Store + , + ]} + />

        ) : null} diff --git a/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx b/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx index c128ac31bf..2ce396de5f 100644 --- a/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx +++ b/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx @@ -1,4 +1,4 @@ -import { Trans } from "next-i18next"; +import type { TFunction } from "i18next"; import Link from "next/link"; import { useEffect, useRef, useState } from "react"; import type { ComponentProps, Dispatch, SetStateAction } from "react"; @@ -12,7 +12,7 @@ import AddMembersWithSwitch, { import AssignAllTeamMembers from "@calcom/features/eventtypes/components/AssignAllTeamMembers"; import type { ChildrenEventTypeSelectCustomClassNames } from "@calcom/features/eventtypes/components/ChildrenEventTypeSelect"; import ChildrenEventTypeSelect from "@calcom/features/eventtypes/components/ChildrenEventTypeSelect"; -import { sortHosts, weightDescription } from "@calcom/features/eventtypes/components/HostEditDialogs"; +import { sortHosts } from "@calcom/features/eventtypes/components/HostEditDialogs"; import type { FormValues, TeamMember, @@ -28,8 +28,10 @@ import { Label } from "@calcom/ui/components/form"; import { Select } from "@calcom/ui/components/form"; import { SettingsToggle } from "@calcom/ui/components/form"; import { RadioAreaGroup as RadioArea } from "@calcom/ui/components/radio"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import { EditWeightsForAllTeamMembers } from "../../EditWeightsForAllTeamMembers"; +import WeightDescription from "../../WeightDescription"; export type EventTeamAssignmentTabCustomClassNames = { assignmentType?: { @@ -114,16 +116,20 @@ const ChildrenEventTypesList = ({ ); }; -const FixedHostHelper = ( - - Add anyone who needs to attend the event. - - Learn more - - +const FixedHostHelper = ({ t }: { t: TFunction }) => ( + + Learn more + , + ]} + /> ); type FixedHostsCustomClassNames = SettingsToggleClassNames & { @@ -172,7 +178,7 @@ const FixedHosts = ({ "text-subtle max-w-full break-words text-sm leading-tight", customClassNames?.description )}> - {FixedHostHelper} +

        @@ -212,7 +218,7 @@ const FixedHosts = ({ data-testid="fixed-hosts-switch" toggleSwitchAtTheEnd={true} title={t("fixed_hosts")} - description={FixedHostHelper} + description={} checked={isDisabled && !assignAllTeamMembers} hideSwitch={assignAllTeamMembers} labelClassName={classNames("text-sm", customClassNames?.label)} @@ -334,7 +340,7 @@ const RoundRobinHosts = ({ render={({ field: { value: isRRWeightsEnabled, onChange } }) => ( } checked={isRRWeightsEnabled} switchContainerClassName={customClassNames?.enableWeights?.container} labelClassName={customClassNames?.enableWeights?.label} diff --git a/packages/features/eventtypes/components/tabs/webhooks/EventWebhooksTab.tsx b/packages/features/eventtypes/components/tabs/webhooks/EventWebhooksTab.tsx index 70d73e9a5b..4641521097 100644 --- a/packages/features/eventtypes/components/tabs/webhooks/EventWebhooksTab.tsx +++ b/packages/features/eventtypes/components/tabs/webhooks/EventWebhooksTab.tsx @@ -1,5 +1,4 @@ import type { Webhook } from "@prisma/client"; -import { Trans } from "next-i18next"; import Link from "next/link"; import { useState } from "react"; import { useFormContext } from "react-hook-form"; @@ -13,11 +12,12 @@ import { subscriberUrlReserved } from "@calcom/features/webhooks/lib/subscriberU import { APP_NAME } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import { showToast } from "@calcom/ui/components/toast"; import { Alert } from "@calcom/ui/components/alert"; import { Button } from "@calcom/ui/components/button"; import { Dialog, DialogContent } from "@calcom/ui/components/dialog"; import { EmptyScreen } from "@calcom/ui/components/empty-screen"; +import { showToast } from "@calcom/ui/components/toast"; +import ServerTrans from "@calcom/web/components/ServerTrans"; export const EventWebhooksTab = ({ eventType }: Pick) => { const { t } = useLocale(); @@ -122,25 +122,21 @@ export const EventWebhooksTab = ({ eventType }: Pick - {lockedText[0].toUpperCase()} - {lockedText.slice(1)} {isManagedEventType ? "for members" : "by team admins"} - + } actions={
        {webhooksDisableProps.LockedIcon}
        } message={ - - {isManagedEventType ? "Members" : "You"}{" "} - {webhooksDisableProps.isLocked - ? "will be able to see the active webhooks but will not be able to edit any webhook settings" - : "will be able to see the active webhooks and will be able to edit any webhook settings"} - + }_description`} + /> } /> )} @@ -181,14 +177,18 @@ export const EventWebhooksTab = ({ eventType }: Pick

        - - If you wish to edit or manage your web hooks, please head over to   - - webhooks settings - - + + webhooks settings + , + ]} + />

        diff --git a/packages/features/eventtypes/components/tabs/workflows/EventWorkfowsTab.tsx b/packages/features/eventtypes/components/tabs/workflows/EventWorkfowsTab.tsx index 3780f72223..da9a4af164 100644 --- a/packages/features/eventtypes/components/tabs/workflows/EventWorkfowsTab.tsx +++ b/packages/features/eventtypes/components/tabs/workflows/EventWorkfowsTab.tsx @@ -2,7 +2,6 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { useFormContext } from "react-hook-form"; -import { Trans } from "react-i18next"; import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired"; import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager"; @@ -15,14 +14,15 @@ import { HttpError } from "@calcom/lib/http-error"; import { WorkflowActions } from "@calcom/prisma/enums"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; -import { Icon } from "@calcom/ui/components/icon"; -import { Tooltip } from "@calcom/ui/components/tooltip"; +import classNames from "@calcom/ui/classNames"; import { Alert } from "@calcom/ui/components/alert"; import { Button } from "@calcom/ui/components/button"; -import classNames from "@calcom/ui/classNames"; import { EmptyScreen } from "@calcom/ui/components/empty-screen"; import { Switch } from "@calcom/ui/components/form"; +import { Icon } from "@calcom/ui/components/icon"; import { showToast } from "@calcom/ui/components/toast"; +import { Tooltip } from "@calcom/ui/components/tooltip"; +import ServerTrans from "@calcom/web/components/ServerTrans"; type PartialWorkflowType = Pick; @@ -252,22 +252,19 @@ function EventWorkflowsTab(props: Props) { severity={workflowsDisableProps.isLocked ? "neutral" : "info"} className="mb-2" title={ - - {lockedText[0].toUpperCase()} - {lockedText.slice(1)} {isManagedEventType ? "for members" : "by team admins"} - + } actions={
        {workflowsDisableProps.LockedIcon}
        } message={ - - {isManagedEventType ? "Members" : "You"}{" "} - {workflowsDisableProps.isLocked - ? "will be able to see the active workflows but will not be able to edit any workflow settings" - : "will be able to see the active workflow and will be able to edit any workflow settings"} - + }_description`} + /> } /> )} diff --git a/packages/features/form-builder/FormBuilderField.tsx b/packages/features/form-builder/FormBuilderField.tsx index da5ab3779a..65413d5cbd 100644 --- a/packages/features/form-builder/FormBuilderField.tsx +++ b/packages/features/form-builder/FormBuilderField.tsx @@ -1,5 +1,5 @@ import { ErrorMessage } from "@hookform/error-message"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { Controller, useFormContext } from "react-hook-form"; import type { z } from "zod"; diff --git a/packages/features/insights/components/RoutedToPerPeriod.tsx b/packages/features/insights/components/RoutedToPerPeriod.tsx index 7ccadb47b5..002506d7ef 100644 --- a/packages/features/insights/components/RoutedToPerPeriod.tsx +++ b/packages/features/insights/components/RoutedToPerPeriod.tsx @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { useQueryState } from "nuqs"; import { type ReactNode, useMemo, useRef, useState } from "react"; diff --git a/packages/features/settings/BookerLayoutSelector.tsx b/packages/features/settings/BookerLayoutSelector.tsx index 802e3329d6..9562fcc1a4 100644 --- a/packages/features/settings/BookerLayoutSelector.tsx +++ b/packages/features/settings/BookerLayoutSelector.tsx @@ -1,5 +1,4 @@ import * as RadioGroup from "@radix-ui/react-radio-group"; -import { Trans } from "next-i18next"; import Link from "next/link"; import { useCallback, useState } from "react"; import { Controller, useFormContext } from "react-hook-form"; @@ -8,10 +7,11 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import { BookerLayouts, defaultBookerLayoutSettings } from "@calcom/prisma/zod-utils"; import { bookerLayoutOptions, type BookerLayoutSettings } from "@calcom/prisma/zod-utils"; import type { RouterOutputs } from "@calcom/trpc/react"; -import { Label } from "@calcom/ui/components/form"; -import { Button } from "@calcom/ui/components/button"; import classNames from "@calcom/ui/classNames"; +import { Button } from "@calcom/ui/components/button"; +import { Label } from "@calcom/ui/components/form"; import { CheckboxField } from "@calcom/ui/components/form"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import SectionBottomActions from "./SectionBottomActions"; @@ -229,20 +229,26 @@ const BookerLayoutFields = ({ {disableFields && (

        - - You can manage this for all your event types in Settings {"-> "} - - Appearance - {" "} - or{" "} - {" "} - for this event only. - + + Appearance + , + , + ]} + />

        )} diff --git a/packages/features/settings/outOfOffice/OutOfOfficeEntriesList.tsx b/packages/features/settings/outOfOffice/OutOfOfficeEntriesList.tsx index 69003e0531..9f51ba3781 100644 --- a/packages/features/settings/outOfOffice/OutOfOfficeEntriesList.tsx +++ b/packages/features/settings/outOfOffice/OutOfOfficeEntriesList.tsx @@ -7,7 +7,6 @@ import { getFilteredRowModel, useReactTable, } from "@tanstack/react-table"; -import { Trans } from "next-i18next"; import { useEffect, useMemo, useRef, useState } from "react"; import { useFormState } from "react-hook-form"; @@ -25,13 +24,14 @@ import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import { Icon } from "@calcom/ui/components/icon"; -import { SkeletonText } from "@calcom/ui/components/skeleton"; -import { Tooltip } from "@calcom/ui/components/tooltip"; import { Avatar } from "@calcom/ui/components/avatar"; import { Button } from "@calcom/ui/components/button"; import { EmptyScreen } from "@calcom/ui/components/empty-screen"; +import { Icon } from "@calcom/ui/components/icon"; +import { SkeletonText } from "@calcom/ui/components/skeleton"; import { showToast } from "@calcom/ui/components/toast"; +import { Tooltip } from "@calcom/ui/components/tooltip"; +import ServerTrans from "@calcom/web/components/ServerTrans"; import CreateNewOutOfOfficeEntryButton from "./CreateNewOutOfOfficeEntryButton"; import { CreateOrEditOutOfOfficeEntryModal } from "./CreateOrEditOutOfOfficeModal"; @@ -197,14 +197,13 @@ function OutOfOfficeEntriesListContent() {

        {item.toUser?.username ? ( - , - }} + components={[]} /> ) : ( <>{t("ooo_not_forwarding")} diff --git a/packages/lib/CalEventParser.test.ts b/packages/lib/CalEventParser.test.ts index 8732bd3e18..716584b71b 100644 --- a/packages/lib/CalEventParser.test.ts +++ b/packages/lib/CalEventParser.test.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { describe, expect, it } from "vitest"; import type { CalendarEvent } from "@calcom/types/Calendar"; diff --git a/packages/lib/CalEventParser.ts b/packages/lib/CalEventParser.ts index 3de4a1016b..c7a52e2771 100644 --- a/packages/lib/CalEventParser.ts +++ b/packages/lib/CalEventParser.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import short from "short-uuid"; import { v5 as uuidv5 } from "uuid"; diff --git a/packages/lib/bookingSuccessRedirect.ts b/packages/lib/bookingSuccessRedirect.ts index 9dc57a5e85..c1e0dcb1d0 100644 --- a/packages/lib/bookingSuccessRedirect.ts +++ b/packages/lib/bookingSuccessRedirect.ts @@ -8,6 +8,8 @@ import type { BookingResponse } from "@calcom/features/bookings/types"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { navigateInTopWindow } from "@calcom/lib/navigateInTopWindow"; +import { getSafe } from "./getSafe"; + function getNewSearchParams(args: { query: Record; searchParams?: URLSearchParams; @@ -43,13 +45,6 @@ type ResultType = { attendeeLastName?: string | null; }; -export function getSafe(obj: unknown, path: (string | number)[]): T | undefined { - return path.reduce( - (acc, key) => (typeof acc === "object" && acc !== null ? (acc as any)[key] : undefined), - obj - ) as T | undefined; -} - export const getBookingRedirectExtraParams = (booking: SuccessRedirectBookingType) => { const redirectQueryParamKeys: BookingResponseKey[] = [ "title", diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts index 316e472e23..fffc5c4408 100644 --- a/packages/lib/constants.ts +++ b/packages/lib/constants.ts @@ -148,14 +148,6 @@ export const DEFAULT_DARK_BRAND_COLOR = "#fafafa"; export const TOP_BANNER_HEIGHT = 40; -const defaultOnNaN = (testedValue: number, defaultValue: number) => - !Number.isNaN(testedValue) ? testedValue : defaultValue; - -export const AB_TEST_BUCKET_PROBABILITY = defaultOnNaN( - parseInt(process.env.AB_TEST_BUCKET_PROBABILITY ?? "10", 10), - 10 -); - export const IS_PREMIUM_USERNAME_ENABLED = (IS_CALCOM || (process.env.NEXT_PUBLIC_IS_E2E && IS_STRIPE_ENABLED)) && process.env.NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE_MONTHLY; @@ -164,8 +156,6 @@ export const IS_PREMIUM_USERNAME_ENABLED = export const MAX_NB_INVITES = 100; export const URL_PROTOCOL_REGEX = /(^\w+:|^)\/\//; -export const FUTURE_ROUTES_OVERRIDE_COOKIE_NAME = "x-calcom-future-routes-override"; -export const FUTURE_ROUTES_ENABLED_COOKIE_NAME = "x-calcom-future-routes-enabled"; export const IS_VISUAL_REGRESSION_TESTING = Boolean(globalThis.window?.Meticulous?.isRunningAsTest); diff --git a/packages/lib/crmManager/crmManager.test.ts b/packages/lib/crmManager/crmManager.test.ts index 62143d771d..7e143fafff 100644 --- a/packages/lib/crmManager/crmManager.test.ts +++ b/packages/lib/crmManager/crmManager.test.ts @@ -1,6 +1,6 @@ import { mockCrmApp } from "@calcom/web/test/utils/bookingScenario/bookingScenario"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { describe, expect, test, vi } from "vitest"; import { getCrm } from "@calcom/app-store/_utils/getCrm"; diff --git a/packages/lib/event-types/utils/locationsResolver.ts b/packages/lib/event-types/utils/locationsResolver.ts index d533ab0f17..2aded2b2ca 100644 --- a/packages/lib/event-types/utils/locationsResolver.ts +++ b/packages/lib/event-types/utils/locationsResolver.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-empty-function */ import { isValidPhoneNumber } from "libphonenumber-js"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; // eslint-disable-next-line @calcom/eslint/deprecated-imports-next-router import { z } from "zod"; diff --git a/packages/lib/event.test.ts b/packages/lib/event.test.ts index 6d1168a5af..93380af141 100644 --- a/packages/lib/event.test.ts +++ b/packages/lib/event.test.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { describe, expect, it, vi } from "vitest"; import * as event from "./event"; diff --git a/packages/lib/event.ts b/packages/lib/event.ts index d65c0e68e7..d4ae8ad5ad 100644 --- a/packages/lib/event.ts +++ b/packages/lib/event.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import z from "zod"; import { guessEventLocationType } from "@calcom/app-store/locations"; diff --git a/packages/lib/getSafe.ts b/packages/lib/getSafe.ts new file mode 100644 index 0000000000..10b1d6f6d3 --- /dev/null +++ b/packages/lib/getSafe.ts @@ -0,0 +1,6 @@ +export function getSafe(obj: unknown, path: (string | number)[]): T | undefined { + return path.reduce( + (acc, key) => (typeof acc === "object" && acc !== null ? (acc as any)[key] : undefined), + obj + ) as T | undefined; +} diff --git a/packages/lib/hooks/useCompatSearchParams.tsx b/packages/lib/hooks/useCompatSearchParams.tsx index 3112bb3827..6a637ae1a1 100644 --- a/packages/lib/hooks/useCompatSearchParams.tsx +++ b/packages/lib/hooks/useCompatSearchParams.tsx @@ -1,3 +1,5 @@ +"use client"; + import { ReadonlyURLSearchParams, useParams, useSearchParams } from "next/navigation"; export const useCompatSearchParams = () => { diff --git a/packages/lib/hooks/useLocale.ts b/packages/lib/hooks/useLocale.ts index 6721972301..723e269215 100644 --- a/packages/lib/hooks/useLocale.ts +++ b/packages/lib/hooks/useLocale.ts @@ -1,4 +1,4 @@ -import { useTranslation } from "next-i18next"; +import { useTranslation } from "react-i18next"; import { useAtomsContext } from "@calcom/atoms/hooks/useAtomsContext"; diff --git a/packages/lib/hooks/useTelemetry.ts b/packages/lib/hooks/useTelemetry.ts new file mode 100644 index 0000000000..cd7f287ca0 --- /dev/null +++ b/packages/lib/hooks/useTelemetry.ts @@ -0,0 +1,5 @@ +"use client"; + +import { useCollector } from "next-collect/client"; + +export const useTelemetry = useCollector; diff --git a/packages/lib/package.json b/packages/lib/package.json index 34f32e5e80..4df48f8898 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -25,7 +25,7 @@ "ics": "^2.37.0", "jimp": "^0.16.1", "next-collect": "^0.2.1", - "next-i18next": "^13.2.2", + "next-i18next": "^15.4.2", "rrule": "^2.7.1", "sonner": "^1.7.4", "tsdav": "2.0.3", diff --git a/packages/lib/recurringStrings.ts b/packages/lib/recurringStrings.ts index a72ae4430d..6a27273995 100644 --- a/packages/lib/recurringStrings.ts +++ b/packages/lib/recurringStrings.ts @@ -1,4 +1,4 @@ -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { Frequency } from "@calcom/prisma/zod-utils"; import type { RecurringEvent } from "@calcom/types/Calendar"; diff --git a/packages/lib/server/i18n.ts b/packages/lib/server/i18n.ts index b49658d07e..972f6bfd71 100644 --- a/packages/lib/server/i18n.ts +++ b/packages/lib/server/i18n.ts @@ -1,18 +1,42 @@ -import i18next from "i18next"; -import { i18n as nexti18next } from "next-i18next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { createInstance } from "i18next"; + +import { WEBAPP_URL } from "@calcom/lib/constants"; + +const i18nInstanceCache = new Map(); + +async function loadTranslations(locale: string, ns: string) { + try { + const url = `${WEBAPP_URL}/static/locales/${locale}/${ns}.json`; + const response = await fetch(url); + return await response.json(); + } catch (error) { + const res = await fetch(`${WEBAPP_URL}/static/locales/en/common.json`); + if (res) { + return await res.json(); + } + return {}; + } +} export const getTranslation = async (locale: string, ns: string) => { - const create = async () => { - const { _nextI18Next } = await serverSideTranslations(locale, [ns]); - const _i18n = i18next.createInstance(); - _i18n.init({ - lng: locale, - resources: _nextI18Next?.initialI18nStore, - fallbackLng: _nextI18Next?.userConfig?.i18n.defaultLocale, - }); - return _i18n; - }; - const _i18n = nexti18next != null ? nexti18next : await create(); + const cacheKey = `${locale}-${ns}`; + if (i18nInstanceCache.has(cacheKey)) { + return i18nInstanceCache.get(cacheKey).getFixedT(locale, ns); + } + + const resources = await loadTranslations(locale, ns); + + const _i18n = createInstance(); + _i18n.init({ + lng: locale, + resources: { + [locale]: { + [ns]: resources, + }, + }, + fallbackLng: "en", + }); + + i18nInstanceCache.set(cacheKey, _i18n); return _i18n.getFixedT(locale, ns); }; diff --git a/packages/lib/telemetry.ts b/packages/lib/telemetry.ts index 8816bfd489..959f3acfe8 100644 --- a/packages/lib/telemetry.ts +++ b/packages/lib/telemetry.ts @@ -1,6 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; import type { CollectOpts, EventHandler } from "next-collect"; -import { useCollector } from "next-collect/client"; // Importing types so we're not directly importing next/server import type { NextRequest, NextResponse } from "next/server"; @@ -112,5 +111,3 @@ export const extendEventData = ( utc_time: new Date().toISOString(), }; }; - -export const useTelemetry = useCollector; diff --git a/packages/lib/test/builder.ts b/packages/lib/test/builder.ts index fb2759a900..0da24b1c10 100644 --- a/packages/lib/test/builder.ts +++ b/packages/lib/test/builder.ts @@ -1,6 +1,6 @@ import { faker } from "@faker-js/faker"; import type { Booking, EventType, Prisma, Webhook, BookingReference } from "@prisma/client"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import getICalUID from "@calcom/emails/lib/getICalUID"; import { CreationSource } from "@calcom/prisma/enums"; diff --git a/packages/platform/atoms/event-types/hooks/usePlatformTabsNavigations.tsx b/packages/platform/atoms/event-types/hooks/usePlatformTabsNavigations.tsx index 4e28d0c1b0..02eb6dce88 100644 --- a/packages/platform/atoms/event-types/hooks/usePlatformTabsNavigations.tsx +++ b/packages/platform/atoms/event-types/hooks/usePlatformTabsNavigations.tsx @@ -2,7 +2,7 @@ // eslint-disable-next-line @calcom/eslint/deprecated-imports-next-router // eslint-disable-next-line @calcom/eslint/deprecated-imports-next-router -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { useMemo, useState, useEffect } from "react"; import type { UseFormReturn } from "react-hook-form"; diff --git a/packages/platform/atoms/event-types/hooks/useTabsNavigations.tsx b/packages/platform/atoms/event-types/hooks/useTabsNavigations.tsx index 38c59be3df..1b3941adcc 100644 --- a/packages/platform/atoms/event-types/hooks/useTabsNavigations.tsx +++ b/packages/platform/atoms/event-types/hooks/useTabsNavigations.tsx @@ -1,7 +1,7 @@ "use client"; // eslint-disable-next-line @calcom/eslint/deprecated-imports-next-router -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { useMemo } from "react"; import type { UseFormReturn } from "react-hook-form"; diff --git a/packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx b/packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx index d89549e4dd..4080061624 100644 --- a/packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx +++ b/packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx @@ -11,9 +11,10 @@ import { EventType as EventTypeComponent } from "@calcom/features/eventtypes/com import type { EventTypeSetupProps } from "@calcom/features/eventtypes/lib/types"; import { WEBSITE_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { useTelemetry } from "@calcom/lib/hooks/useTelemetry"; import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery"; import { HttpError } from "@calcom/lib/http-error"; -import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; +import { telemetryEventTypes } from "@calcom/lib/telemetry"; import { SchedulingType } from "@calcom/prisma/enums"; import { trpc } from "@calcom/trpc/react"; import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery"; diff --git a/packages/prisma/client/index.js b/packages/prisma/client/index.js index b98f8c8fc6..fcab163dab 100644 --- a/packages/prisma/client/index.js +++ b/packages/prisma/client/index.js @@ -1 +1 @@ -export * from "../../../node_modules/.prisma/client"; +export * from "@prisma/client"; diff --git a/packages/prisma/zod-utils.ts b/packages/prisma/zod-utils.ts index 87fd2e6b98..3ec0f0aa1b 100644 --- a/packages/prisma/zod-utils.ts +++ b/packages/prisma/zod-utils.ts @@ -1,6 +1,6 @@ import type { Prisma } from "@prisma/client"; import type { UnitTypeLongPlural } from "dayjs"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import z, { ZodNullable, ZodObject, ZodOptional } from "zod"; import type { AnyZodObject, diff --git a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts index c8bf4a9111..2c52b5721d 100644 --- a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts @@ -1,5 +1,5 @@ import type { BookingReference, EventType } from "@prisma/client"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { getCalendar } from "@calcom/app-store/_utils/getCalendar"; import dayjs from "@calcom/dayjs"; diff --git a/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts b/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts index 9129c6a865..dc6f103b26 100644 --- a/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts +++ b/packages/trpc/server/routers/viewer/teams/inviteMember/utils.ts @@ -1,5 +1,5 @@ import { randomBytes } from "crypto"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains"; import { sendTeamInviteEmail } from "@calcom/emails"; diff --git a/packages/types/Calendar.d.ts b/packages/types/Calendar.d.ts index a7dfc7a797..16fbc60de3 100644 --- a/packages/types/Calendar.d.ts +++ b/packages/types/Calendar.d.ts @@ -7,7 +7,7 @@ import type { } from "@prisma/client"; import type { Dayjs } from "dayjs"; import type { Time } from "ical.js"; -import type { TFunction } from "next-i18next"; +import type { TFunction } from "i18next"; import type { Frequency } from "rrule"; import type z from "zod"; diff --git a/turbo.json b/turbo.json index f725dea3eb..0fb4b204b5 100644 --- a/turbo.json +++ b/turbo.json @@ -239,12 +239,9 @@ }, "globalDependencies": ["yarn.lock"], "globalEnv": [ - "AB_TEST_BUCKET_PROBABILITY", "ALLOWED_HOSTNAMES", "ANALYZE", "API_KEY_PREFIX", - "APP_ROUTER_APPS_SLUG_SETUP_ENABLED", - "APP_ROUTER_TEAM_ENABLED", "APP_USER_NAME", "BASECAMP3_CLIENT_ID", "BASECAMP3_CLIENT_SECRET", diff --git a/yarn.lock b/yarn.lock index c9b408a22e..69c5f3a68e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1931,6 +1931,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.21.0": + version: 7.26.10 + resolution: "@babel/runtime@npm:7.26.10" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 22d2e0abb86e90de489ab16bb578db6fe2b63a88696db431198b24963749820c723f1982298cdbbea187f7b2b80fb4d98a514faf114ddb2fdc14a4b96277b955 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.23.2": version: 7.23.5 resolution: "@babel/runtime@npm:7.23.5" @@ -2769,7 +2778,7 @@ __metadata: "@calcom/lib": "*" "@calcom/tsconfig": "*" "@calcom/types": "*" - next-i18next: ^13.2.2 + next-i18next: ^15.4.2 react: ^18.2.0 react-dom: ^18.2.0 rrule: ^2.7.1 @@ -3151,7 +3160,7 @@ __metadata: ics: ^2.37.0 jimp: ^0.16.1 next-collect: ^0.2.1 - next-i18next: ^13.2.2 + next-i18next: ^15.4.2 rrule: ^2.7.1 sonner: ^1.7.4 tsdav: 2.0.3 @@ -3804,7 +3813,7 @@ __metadata: "@stripe/stripe-js": ^1.35.0 "@tanstack/react-query": ^5.17.15 "@testing-library/react": ^13.3.0 - "@tremor/react": ^2.0.0 + "@tremor/react": ^2.11.0 "@types/accept-language-parser": 1.5.2 "@types/async": ^3.2.15 "@types/bcryptjs": ^2.4.2 @@ -3841,7 +3850,6 @@ __metadata: classnames: ^2.3.1 copy-webpack-plugin: ^11.0.0 cron: ^3.1.7 - deasync: ^0.1.30 detect-port: ^1.3.0 dompurify: ^3.1.7 dotenv-cli: ^6.0.0 @@ -3865,11 +3873,11 @@ __metadata: mime-types: ^2.1.35 module-alias: ^2.2.2 msw: ^0.42.3 - next: ^13.5.6 + next: ^15.1.6 next-auth: ^4.22.1 next-axiom: ^0.17.0 next-collect: ^0.2.1 - next-i18next: ^13.2.2 + next-i18next: ^15.4.2 next-seo: ^6.0.0 next-themes: ^0.2.0 node-html-parser: ^6.1.10 @@ -4363,6 +4371,15 @@ __metadata: languageName: node linkType: hard +"@emnapi/runtime@npm:^1.2.0": + version: 1.3.1 + resolution: "@emnapi/runtime@npm:1.3.1" + dependencies: + tslib: ^2.4.0 + checksum: 9a16ae7905a9c0e8956cf1854ef74e5087fbf36739abdba7aa6b308485aafdc993da07c19d7af104cd5f8e425121120852851bb3a0f78e2160e420a36d47f42f + languageName: node + linkType: hard + "@emotion/babel-plugin@npm:^11.7.1": version: 11.7.2 resolution: "@emotion/babel-plugin@npm:11.7.2" @@ -5387,6 +5404,181 @@ __metadata: languageName: node linkType: hard +"@img/sharp-darwin-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-arm64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-darwin-arm64": + optional: true + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-darwin-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-x64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-darwin-x64": + optional: true + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm@npm:1.0.5": + version: 1.0.5 + resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-s390x@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linux-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linux-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-arm@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm": 1.0.5 + dependenciesMeta: + "@img/sharp-libvips-linux-arm": + optional: true + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-s390x@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-s390x@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-s390x": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linux-s390x": + optional: true + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-x64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linux-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-x64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-wasm32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-wasm32@npm:0.33.5" + dependencies: + "@emnapi/runtime": ^1.2.0 + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@img/sharp-win32-ia32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-ia32@npm:0.33.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@img/sharp-win32-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-x64@npm:0.33.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@inquirer/confirm@npm:^5.0.0": version: 5.1.6 resolution: "@inquirer/confirm@npm:5.1.6" @@ -7122,6 +7314,13 @@ __metadata: languageName: node linkType: hard +"@next/env@npm:15.2.1": + version: 15.2.1 + resolution: "@next/env@npm:15.2.1" + checksum: 32aee52cad88cfff7c473f7089eff7fa0662f4d3d40a257ec6214e46f0df8d65f23486f73772a5efeb9d6750e8bdbdb7dff2cda08495b510299c267a17696f65 + languageName: node + linkType: hard + "@next/eslint-plugin-next@npm:13.2.1": version: 13.2.1 resolution: "@next/eslint-plugin-next@npm:13.2.1" @@ -7154,6 +7353,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-darwin-arm64@npm:15.2.1": + version: 15.2.1 + resolution: "@next/swc-darwin-arm64@npm:15.2.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@next/swc-darwin-x64@npm:13.5.7": version: 13.5.7 resolution: "@next/swc-darwin-x64@npm:13.5.7" @@ -7168,6 +7374,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-darwin-x64@npm:15.2.1": + version: 15.2.1 + resolution: "@next/swc-darwin-x64@npm:15.2.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@next/swc-linux-arm64-gnu@npm:13.5.7": version: 13.5.7 resolution: "@next/swc-linux-arm64-gnu@npm:13.5.7" @@ -7182,6 +7395,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-arm64-gnu@npm:15.2.1": + version: 15.2.1 + resolution: "@next/swc-linux-arm64-gnu@npm:15.2.1" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@next/swc-linux-arm64-musl@npm:13.5.7": version: 13.5.7 resolution: "@next/swc-linux-arm64-musl@npm:13.5.7" @@ -7196,6 +7416,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-arm64-musl@npm:15.2.1": + version: 15.2.1 + resolution: "@next/swc-linux-arm64-musl@npm:15.2.1" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@next/swc-linux-x64-gnu@npm:13.5.7": version: 13.5.7 resolution: "@next/swc-linux-x64-gnu@npm:13.5.7" @@ -7210,6 +7437,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-x64-gnu@npm:15.2.1": + version: 15.2.1 + resolution: "@next/swc-linux-x64-gnu@npm:15.2.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@next/swc-linux-x64-musl@npm:13.5.7": version: 13.5.7 resolution: "@next/swc-linux-x64-musl@npm:13.5.7" @@ -7224,6 +7458,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-linux-x64-musl@npm:15.2.1": + version: 15.2.1 + resolution: "@next/swc-linux-x64-musl@npm:15.2.1" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@next/swc-win32-arm64-msvc@npm:13.5.7": version: 13.5.7 resolution: "@next/swc-win32-arm64-msvc@npm:13.5.7" @@ -7238,6 +7479,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-win32-arm64-msvc@npm:15.2.1": + version: 15.2.1 + resolution: "@next/swc-win32-arm64-msvc@npm:15.2.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@next/swc-win32-ia32-msvc@npm:13.5.7": version: 13.5.7 resolution: "@next/swc-win32-ia32-msvc@npm:13.5.7" @@ -7266,6 +7514,13 @@ __metadata: languageName: node linkType: hard +"@next/swc-win32-x64-msvc@npm:15.2.1": + version: 15.2.1 + resolution: "@next/swc-win32-x64-msvc@npm:15.2.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@next/third-parties@npm:^14.2.5": version: 14.2.5 resolution: "@next/third-parties@npm:14.2.5" @@ -12981,13 +13236,22 @@ __metadata: languageName: node linkType: hard -"@swc/counter@npm:^0.1.3": +"@swc/counter@npm:0.1.3, @swc/counter@npm:^0.1.3": version: 0.1.3 resolution: "@swc/counter@npm:0.1.3" checksum: df8f9cfba9904d3d60f511664c70d23bb323b3a0803ec9890f60133954173047ba9bdeabce28cd70ba89ccd3fd6c71c7b0bd58be85f611e1ffbe5d5c18616598 languageName: node linkType: hard +"@swc/helpers@npm:0.5.15": + version: 0.5.15 + resolution: "@swc/helpers@npm:0.5.15" + dependencies: + tslib: ^2.8.0 + checksum: 1a9e0dbb792b2d1e0c914d69c201dbc96af3a0e6e6e8cf5a7f7d6a5d7b0e8b762915cd4447acb6b040e2ecc1ed49822875a7239f99a2d63c96c3c3407fb6fccf + languageName: node + linkType: hard + "@swc/helpers@npm:0.5.2": version: 0.5.2 resolution: "@swc/helpers@npm:0.5.2" @@ -13223,9 +13487,9 @@ __metadata: languageName: node linkType: hard -"@tremor/react@npm:^2.0.0": - version: 2.0.2 - resolution: "@tremor/react@npm:2.0.2" +"@tremor/react@npm:^2.11.0": + version: 2.11.0 + resolution: "@tremor/react@npm:2.11.0" dependencies: "@floating-ui/react": ^0.19.1 date-fns: ^2.28.0 @@ -13234,7 +13498,8 @@ __metadata: tailwind-merge: ^1.9.1 peerDependencies: react: ^18.0.0 - checksum: 4002a062a3bcdc164904187ffe53934d26edbb8d342a3f756b99c32beb0d997bf0937fdda39526d964e34cc996231b485fc68fc4a580c1d009b4a2fcb8ebdc27 + react-dom: ">=16.6.0" + checksum: 76bee230a819289a5e87204f51161724b49bcc281308b4c41a5918e57e93497e2e97eb85b951bd750b918093784fdb28a2d1060b89502544f1a9cf76232da6d3 languageName: node linkType: hard @@ -13843,6 +14108,16 @@ __metadata: languageName: node linkType: hard +"@types/hoist-non-react-statics@npm:^3.3.6": + version: 3.3.6 + resolution: "@types/hoist-non-react-statics@npm:3.3.6" + dependencies: + "@types/react": "*" + hoist-non-react-statics: ^3.3.0 + checksum: f03e43bd081876c49584ffa0eb690d69991f258203efca44dcc30efdda49a50653ff06402917d1edc9cb7e2adebbe9e2d1d0e739bc99c1b5372103b1cc534e47 + languageName: node + linkType: hard + "@types/http-assert@npm:*": version: 1.5.5 resolution: "@types/http-assert@npm:1.5.5" @@ -16960,15 +17235,6 @@ __metadata: languageName: node linkType: hard -"bindings@npm:^1.5.0": - version: 1.5.0 - resolution: "bindings@npm:1.5.0" - dependencies: - file-uri-to-path: 1.0.0 - checksum: 65b6b48095717c2e6105a021a7da4ea435aa8d3d3cd085cb9e85bcb6e5773cf318c4745c3f7c504412855940b585bdf9b918236612a1c7a7942491de176f1ae7 - languageName: node - linkType: hard - "biskviit@npm:1.0.1": version: 1.0.1 resolution: "biskviit@npm:1.0.1" @@ -17701,6 +17967,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001704 + resolution: "caniuse-lite@npm:1.0.30001704" + checksum: ac8c1b625198c9fdf03f55ef631a0917d29d368ded8e8b2e6a3111cb7433c30b2ef16a6dc44077fb6176e76881a51818d55f24efd04478f5e98b6724b64a8f5c + languageName: node + linkType: hard + "caniuse-lite@npm:^1.0.30001587, caniuse-lite@npm:^1.0.30001591": version: 1.0.30001597 resolution: "caniuse-lite@npm:1.0.30001597" @@ -18103,7 +18376,7 @@ __metadata: languageName: node linkType: hard -"classnames@npm:^2.2.5, classnames@npm:^2.2.6": +"classnames@npm:^2.2.6": version: 2.3.2 resolution: "classnames@npm:2.3.2" checksum: 2c62199789618d95545c872787137262e741f9db13328e216b093eea91c85ef2bfb152c1f9e63027204e2559a006a92eb74147d46c800a9f96297ae1d9f96f4e @@ -18430,7 +18703,7 @@ __metadata: languageName: node linkType: hard -"color-string@npm:^1.6.0": +"color-string@npm:^1.6.0, color-string@npm:^1.9.0": version: 1.9.1 resolution: "color-string@npm:1.9.1" dependencies: @@ -18459,6 +18732,16 @@ __metadata: languageName: node linkType: hard +"color@npm:^4.2.3": + version: 4.2.3 + resolution: "color@npm:4.2.3" + dependencies: + color-convert: ^2.0.1 + color-string: ^1.9.0 + checksum: 0579629c02c631b426780038da929cca8e8d80a40158b09811a0112a107c62e10e4aad719843b791b1e658ab4e800558f2e87ca4522c8b32349d497ecb6adeb4 + languageName: node + linkType: hard + "colorette@npm:^2.0.16": version: 2.0.16 resolution: "colorette@npm:2.0.16" @@ -19274,13 +19557,6 @@ __metadata: languageName: node linkType: hard -"css-unit-converter@npm:^1.1.1": - version: 1.1.2 - resolution: "css-unit-converter@npm:1.1.2" - checksum: 07888033346a5128f34dbe2f72884c966d24e9f29db24416dcde92860242490617ef9a178ac193a92f730834bbeea026cdc7027701d92ba9bbbe59db7a37eb2a - languageName: node - linkType: hard - "css-what@npm:^6.1.0": version: 6.1.0 resolution: "css-what@npm:6.1.0" @@ -19556,9 +19832,11 @@ __metadata: linkType: hard "date-fns@npm:^2.28.0": - version: 2.29.3 - resolution: "date-fns@npm:2.29.3" - checksum: e01cf5b62af04e05dfff921bb9c9933310ed0e1ae9a81eb8653452e64dc841acf7f6e01e1a5ae5644d0337e9a7f936175fd2cb6819dc122fdd9c5e86c56be484 + version: 2.30.0 + resolution: "date-fns@npm:2.30.0" + dependencies: + "@babel/runtime": ^7.21.0 + checksum: f7be01523282e9bb06c0cd2693d34f245247a29098527d4420628966a2d9aad154bd0e90a6b1cf66d37adcb769cd108cf8a7bd49d76db0fb119af5cdd13644f4 languageName: node linkType: hard @@ -19597,16 +19875,6 @@ __metadata: languageName: node linkType: hard -"deasync@npm:^0.1.30": - version: 0.1.30 - resolution: "deasync@npm:0.1.30" - dependencies: - bindings: ^1.5.0 - node-addon-api: ^1.7.1 - checksum: 1faeb20e1ec1c6ebde35a44f309e1b544804c782b25b513536e5a7313f89a45eb1565f228d06a1a233b285673137731822f81c6629a52a729f4fffb94f433549 - languageName: node - linkType: hard - "debounce-fn@npm:^4.0.0": version: 4.0.0 resolution: "debounce-fn@npm:4.0.0" @@ -19936,7 +20204,7 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^2.0.1": +"detect-libc@npm:^2.0.1, detect-libc@npm:^2.0.3": version: 2.0.3 resolution: "detect-libc@npm:2.0.3" checksum: 2ba6a939ae55f189aea996ac67afceb650413c7a34726ee92c40fb0deb2400d57ef94631a8a3f052055eea7efb0f99a9b5e6ce923415daa3e68221f963cfc27d @@ -20081,15 +20349,6 @@ __metadata: languageName: node linkType: hard -"dom-helpers@npm:^3.4.0": - version: 3.4.0 - resolution: "dom-helpers@npm:3.4.0" - dependencies: - "@babel/runtime": ^7.1.2 - checksum: 58d9f1c4a96daf77eddc63ae1236b826e1cddd6db66bbf39b18d7e21896d99365b376593352d52a60969d67fa4a8dbef26adc1439fa2c1b355efa37cacbaf637 - languageName: node - linkType: hard - "dom-helpers@npm:^5.0.1": version: 5.2.1 resolution: "dom-helpers@npm:5.2.1" @@ -22122,10 +22381,10 @@ __metadata: languageName: node linkType: hard -"fast-equals@npm:^4.0.3": - version: 4.0.3 - resolution: "fast-equals@npm:4.0.3" - checksum: 3d5935b757f9f2993e59b5164a7a9eeda0de149760495375cde14a4ed725186a7e6c1c0d58f7d42d2f91deb97f3fce1e0aad5591916ef0984278199a85c87c87 +"fast-equals@npm:^5.0.1": + version: 5.2.2 + resolution: "fast-equals@npm:5.2.2" + checksum: 7156bcade0be5ee4dc335969d255a5815348d57080e1876fa1584451eafd0c92588de5f5840e55f81841b6d907ade2a49a46e4ec33e6f7a283a209c0fd8f8a59 languageName: node linkType: hard @@ -22438,13 +22697,6 @@ __metadata: languageName: node linkType: hard -"file-uri-to-path@npm:1.0.0": - version: 1.0.0 - resolution: "file-uri-to-path@npm:1.0.0" - checksum: b648580bdd893a008c92c7ecc96c3ee57a5e7b6c4c18a9a09b44fb5d36d79146f8e442578bc0e173dc027adf3987e254ba1dfd6e3ec998b7c282873010502144 - languageName: node - linkType: hard - "filelist@npm:^1.0.4": version: 1.0.4 resolution: "filelist@npm:1.0.4" @@ -24489,10 +24741,10 @@ __metadata: languageName: node linkType: hard -"i18next-fs-backend@npm:^2.1.1": - version: 2.1.3 - resolution: "i18next-fs-backend@npm:2.1.3" - checksum: df3586f0958b5967674fa46aa7a579276156328b3f25e744c125b98bbeb8330c7a18a513a6224841e5732860c7bd54cb4a04b8d5a9eb521046dc37c254b67349 +"i18next-fs-backend@npm:^2.6.0": + version: 2.6.0 + resolution: "i18next-fs-backend@npm:2.6.0" + checksum: 2a34a6f0563f7cc5c98de93e66fff66696eaf19b295d073fb1fef426db75783ecfab10b0251272957c307cbb3ffb4e9b5073c17ddb10be2e352d9b6e6ee71a5a languageName: node linkType: hard @@ -29332,39 +29584,21 @@ __metadata: languageName: node linkType: hard -"next-i18next@npm:13.3.0": - version: 13.3.0 - resolution: "next-i18next@npm:13.3.0" +"next-i18next@npm:^15.4.2": + version: 15.4.2 + resolution: "next-i18next@npm:15.4.2" dependencies: - "@babel/runtime": ^7.20.13 - "@types/hoist-non-react-statics": ^3.3.1 + "@babel/runtime": ^7.23.2 + "@types/hoist-non-react-statics": ^3.3.6 core-js: ^3 hoist-non-react-statics: ^3.3.2 - i18next-fs-backend: ^2.1.1 + i18next-fs-backend: ^2.6.0 peerDependencies: - i18next: ^22.0.6 + i18next: ">= 23.7.13" next: ">= 12.0.0" react: ">= 17.0.2" - react-i18next: ^12.2.0 - checksum: 4c3aa5bbbc12964ed6f61f37d33f4319abd04932d6871baba9f209183952b286470fff80f90a94ccddba736c8fb13a9238effa1e8247dfb08e2239cbdc4fb769 - languageName: node - linkType: hard - -"next-i18next@patch:next-i18next@npm%3A13.3.0#./.yarn/patches/next-i18next-npm-13.3.0-bf25b0943c.patch::locator=calcom-monorepo%40workspace%3A.": - version: 13.3.0 - resolution: "next-i18next@patch:next-i18next@npm%3A13.3.0#./.yarn/patches/next-i18next-npm-13.3.0-bf25b0943c.patch::version=13.3.0&hash=bcbde7&locator=calcom-monorepo%40workspace%3A." - dependencies: - "@babel/runtime": ^7.20.13 - "@types/hoist-non-react-statics": ^3.3.1 - core-js: ^3 - hoist-non-react-statics: ^3.3.2 - i18next-fs-backend: ^2.1.1 - peerDependencies: - i18next: ^22.0.6 - next: ">= 12.0.0" - react: ">= 17.0.2" - react-i18next: ^12.2.0 - checksum: 7dcb7e2ec14a0164e2c803b5eb4be3d3198ff0db266fecd6225dfa99ec53bf923fe50230c413f2e9b9a795266fb4e31f129572865181df1eadcf8721ad138b3e + react-i18next: ">= 13.5.0" + checksum: d5c3d675b66ae4c65f96c040a031df0c81c23d2562c398f560c3e629e47fb67061053c0bb58cce41b9e45106a0c9cf7db05ef464991a6908ed5bb8fd85f50634 languageName: node linkType: hard @@ -29545,6 +29779,67 @@ __metadata: languageName: node linkType: hard +"next@npm:^15.1.6": + version: 15.2.1 + resolution: "next@npm:15.2.1" + dependencies: + "@next/env": 15.2.1 + "@next/swc-darwin-arm64": 15.2.1 + "@next/swc-darwin-x64": 15.2.1 + "@next/swc-linux-arm64-gnu": 15.2.1 + "@next/swc-linux-arm64-musl": 15.2.1 + "@next/swc-linux-x64-gnu": 15.2.1 + "@next/swc-linux-x64-musl": 15.2.1 + "@next/swc-win32-arm64-msvc": 15.2.1 + "@next/swc-win32-x64-msvc": 15.2.1 + "@swc/counter": 0.1.3 + "@swc/helpers": 0.5.15 + busboy: 1.6.0 + caniuse-lite: ^1.0.30001579 + postcss: 8.4.31 + sharp: ^0.33.5 + styled-jsx: 5.1.6 + peerDependencies: + "@opentelemetry/api": ^1.1.0 + "@playwright/test": ^1.41.2 + babel-plugin-react-compiler: "*" + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + dependenciesMeta: + "@next/swc-darwin-arm64": + optional: true + "@next/swc-darwin-x64": + optional: true + "@next/swc-linux-arm64-gnu": + optional: true + "@next/swc-linux-arm64-musl": + optional: true + "@next/swc-linux-x64-gnu": + optional: true + "@next/swc-linux-x64-musl": + optional: true + "@next/swc-win32-arm64-msvc": + optional: true + "@next/swc-win32-x64-msvc": + optional: true + sharp: + optional: true + peerDependenciesMeta: + "@opentelemetry/api": + optional: true + "@playwright/test": + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + bin: + next: dist/bin/next + checksum: 277aabc5f8c0aea6c2309adb4d251676652bb6eee2b625985a01d9039f945e1fbae7bc33ed7dde44de63a9f21da49bcc280df750bba76c3380c65ab0bce8d25e + languageName: node + linkType: hard + "nice-try@npm:^1.0.4": version: 1.0.5 resolution: "nice-try@npm:1.0.5" @@ -29575,15 +29870,6 @@ __metadata: languageName: node linkType: hard -"node-addon-api@npm:^1.7.1": - version: 1.7.2 - resolution: "node-addon-api@npm:1.7.2" - dependencies: - node-gyp: latest - checksum: 938922b3d7cb34ee137c5ec39df6289a3965e8cab9061c6848863324c21a778a81ae3bc955554c56b6b86962f6ccab2043dd5fa3f33deab633636bd28039333f - languageName: node - linkType: hard - "node-domexception@npm:1.0.0": version: 1.0.0 resolution: "node-domexception@npm:1.0.0" @@ -31643,13 +31929,6 @@ __metadata: languageName: node linkType: hard -"postcss-value-parser@npm:^3.3.0": - version: 3.3.1 - resolution: "postcss-value-parser@npm:3.3.1" - checksum: 62cd26e1cdbcf2dcc6bcedf3d9b409c9027bc57a367ae20d31dd99da4e206f730689471fd70a2abe866332af83f54dc1fa444c589e2381bf7f8054c46209ce16 - languageName: node - linkType: hard - "postcss-value-parser@npm:^4.0.0, postcss-value-parser@npm:^4.0.2, postcss-value-parser@npm:^4.2.0": version: 4.2.0 resolution: "postcss-value-parser@npm:4.2.0" @@ -32869,7 +33148,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.10.2, react-is@npm:^16.13.1, react-is@npm:^16.7.0": +"react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f @@ -32890,10 +33169,10 @@ __metadata: languageName: node linkType: hard -"react-lifecycles-compat@npm:^3.0.4": - version: 3.0.4 - resolution: "react-lifecycles-compat@npm:3.0.4" - checksum: a904b0fc0a8eeb15a148c9feb7bc17cec7ef96e71188280061fc340043fd6d8ee3ff233381f0e8f95c1cf926210b2c4a31f38182c8f35ac55057e453d6df204f +"react-is@npm:^18.3.1": + version: 18.3.1 + resolution: "react-is@npm:18.3.1" + checksum: e20fe84c86ff172fc8d898251b7cc2c43645d108bf96d0b8edf39b98f9a2cae97b40520ee7ed8ee0085ccc94736c4886294456033304151c3f94978cec03df21 languageName: node linkType: hard @@ -33095,18 +33374,6 @@ __metadata: languageName: node linkType: hard -"react-resize-detector@npm:^8.0.4": - version: 8.0.4 - resolution: "react-resize-detector@npm:8.0.4" - dependencies: - lodash: ^4.17.21 - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: f53a99cc5413844a6fc2a713b0b1094d23947897c14ab64481938632f4e77fadded52d91a6619055abf6240c7cacd6cc7dd492ea866639b302f81df680709d45 - languageName: node - linkType: hard - "react-schemaorg@npm:^2.0.0": version: 2.0.0 resolution: "react-schemaorg@npm:2.0.0" @@ -33158,17 +33425,17 @@ __metadata: languageName: node linkType: hard -"react-smooth@npm:^2.0.2": - version: 2.0.2 - resolution: "react-smooth@npm:2.0.2" +"react-smooth@npm:^4.0.4": + version: 4.0.4 + resolution: "react-smooth@npm:4.0.4" dependencies: - fast-equals: ^4.0.3 - react-transition-group: 2.9.0 + fast-equals: ^5.0.1 + prop-types: ^15.8.1 + react-transition-group: ^4.4.5 peerDependencies: - prop-types: ^15.6.0 - react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: 6b0a40a17314657ac6a187a3ad01fcdaa61d498979b6a07c424e20832110c99b4394c33209a0b39b897c13d113d8cb044e7a691b4965386a11b15bbfbacfba25 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 909305d40bae79a011ff21a10c4bc7ddadc87ac5ff093b4a5f827f730f093ec4e044c4330688d29b3ad2db83aab8997c3bb1bae550a9c66de74521b8ed52cc53 languageName: node linkType: hard @@ -33244,21 +33511,6 @@ __metadata: languageName: node linkType: hard -"react-transition-group@npm:2.9.0": - version: 2.9.0 - resolution: "react-transition-group@npm:2.9.0" - dependencies: - dom-helpers: ^3.4.0 - loose-envify: ^1.4.0 - prop-types: ^15.6.2 - react-lifecycles-compat: ^3.0.4 - peerDependencies: - react: ">=15.0.0" - react-dom: ">=15.0.0" - checksum: d8c9e50aabdc2cfc324e5cdb0ad1c6eecb02e1c0cd007b26d5b30ccf49015e900683dd489348c71fba4055858308d9ba7019e0d37d0e8d37bd46ed098788f670 - languageName: node - linkType: hard - "react-transition-group@npm:^4.3.0": version: 4.4.2 resolution: "react-transition-group@npm:4.4.2" @@ -33536,23 +33788,21 @@ __metadata: linkType: hard "recharts@npm:^2.3.2": - version: 2.5.0 - resolution: "recharts@npm:2.5.0" + version: 2.15.1 + resolution: "recharts@npm:2.15.1" dependencies: - classnames: ^2.2.5 + clsx: ^2.0.0 eventemitter3: ^4.0.1 - lodash: ^4.17.19 - react-is: ^16.10.2 - react-resize-detector: ^8.0.4 - react-smooth: ^2.0.2 + lodash: ^4.17.21 + react-is: ^18.3.1 + react-smooth: ^4.0.4 recharts-scale: ^0.4.4 - reduce-css-calc: ^2.1.8 + tiny-invariant: ^1.3.1 victory-vendor: ^36.6.8 peerDependencies: - prop-types: ^15.6.0 - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: a40d1788589926fa8a5844868a338aae75a2077a2bc2ac57fc5d61ad21fb62660aed6f00ae8d8a94948b9143255c1760db0d386ecb257ed8290dd7f164b5bd5f + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: c288012087424e7067bf4a48a3d50a7c0ea231188ecaaf17685d93711ef1846aedd37509dfc25c046052f671e7e19dd2de5d8b9c1e497a64c39995c9c338b40a languageName: node linkType: hard @@ -33630,16 +33880,6 @@ __metadata: languageName: node linkType: hard -"reduce-css-calc@npm:^2.1.8": - version: 2.1.8 - resolution: "reduce-css-calc@npm:2.1.8" - dependencies: - css-unit-converter: ^1.1.1 - postcss-value-parser: ^3.3.0 - checksum: 8fd27c06c4b443b84749a69a8b97d10e6ec7d142b625b41923a8807abb22b9e37e44df14e26cc606a802957be07bdce5e8ee2976a6952a7b438a7727007101e9 - languageName: node - linkType: hard - "redux-immutable@npm:^4.0.0": version: 4.0.0 resolution: "redux-immutable@npm:4.0.0" @@ -34717,6 +34957,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.6.3": + version: 7.7.1 + resolution: "semver@npm:7.7.1" + bin: + semver: bin/semver.js + checksum: 586b825d36874007c9382d9e1ad8f93888d8670040add24a28e06a910aeebd673a2eb9e3bf169c6679d9245e66efb9057e0852e70d9daa6c27372aab1dda7104 + languageName: node + linkType: hard + "semver@npm:~2.3.1": version: 2.3.2 resolution: "semver@npm:2.3.2" @@ -34907,6 +35156,75 @@ __metadata: languageName: node linkType: hard +"sharp@npm:^0.33.5": + version: 0.33.5 + resolution: "sharp@npm:0.33.5" + dependencies: + "@img/sharp-darwin-arm64": 0.33.5 + "@img/sharp-darwin-x64": 0.33.5 + "@img/sharp-libvips-darwin-arm64": 1.0.4 + "@img/sharp-libvips-darwin-x64": 1.0.4 + "@img/sharp-libvips-linux-arm": 1.0.5 + "@img/sharp-libvips-linux-arm64": 1.0.4 + "@img/sharp-libvips-linux-s390x": 1.0.4 + "@img/sharp-libvips-linux-x64": 1.0.4 + "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 + "@img/sharp-libvips-linuxmusl-x64": 1.0.4 + "@img/sharp-linux-arm": 0.33.5 + "@img/sharp-linux-arm64": 0.33.5 + "@img/sharp-linux-s390x": 0.33.5 + "@img/sharp-linux-x64": 0.33.5 + "@img/sharp-linuxmusl-arm64": 0.33.5 + "@img/sharp-linuxmusl-x64": 0.33.5 + "@img/sharp-wasm32": 0.33.5 + "@img/sharp-win32-ia32": 0.33.5 + "@img/sharp-win32-x64": 0.33.5 + color: ^4.2.3 + detect-libc: ^2.0.3 + semver: ^7.6.3 + dependenciesMeta: + "@img/sharp-darwin-arm64": + optional: true + "@img/sharp-darwin-x64": + optional: true + "@img/sharp-libvips-darwin-arm64": + optional: true + "@img/sharp-libvips-darwin-x64": + optional: true + "@img/sharp-libvips-linux-arm": + optional: true + "@img/sharp-libvips-linux-arm64": + optional: true + "@img/sharp-libvips-linux-s390x": + optional: true + "@img/sharp-libvips-linux-x64": + optional: true + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + "@img/sharp-libvips-linuxmusl-x64": + optional: true + "@img/sharp-linux-arm": + optional: true + "@img/sharp-linux-arm64": + optional: true + "@img/sharp-linux-s390x": + optional: true + "@img/sharp-linux-x64": + optional: true + "@img/sharp-linuxmusl-arm64": + optional: true + "@img/sharp-linuxmusl-x64": + optional: true + "@img/sharp-wasm32": + optional: true + "@img/sharp-win32-ia32": + optional: true + "@img/sharp-win32-x64": + optional: true + checksum: 04beae89910ac65c5f145f88de162e8466bec67705f497ace128de849c24d168993e016f33a343a1f3c30b25d2a90c3e62b017a9a0d25452371556f6cd2471e4 + languageName: node + linkType: hard + "shebang-command@npm:^1.2.0": version: 1.2.0 resolution: "shebang-command@npm:1.2.0" @@ -36019,6 +36337,22 @@ __metadata: languageName: node linkType: hard +"styled-jsx@npm:5.1.6": + version: 5.1.6 + resolution: "styled-jsx@npm:5.1.6" + dependencies: + client-only: 0.0.1 + peerDependencies: + react: ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + peerDependenciesMeta: + "@babel/core": + optional: true + babel-plugin-macros: + optional: true + checksum: 879ad68e3e81adcf4373038aaafe55f968294955593660e173fbf679204aff158c59966716a60b29af72dc88795cfb2c479b6d2c3c87b2b2d282f3e27cc66461 + languageName: node + linkType: hard + "stylis@npm:4.0.13": version: 4.0.13 resolution: "stylis@npm:4.0.13" @@ -36354,9 +36688,9 @@ __metadata: linkType: hard "tailwind-merge@npm:^1.9.1": - version: 1.10.0 - resolution: "tailwind-merge@npm:1.10.0" - checksum: 80eb30d0300ca912b4b910460497a1d5fb4e697c3aedb01513e633973328684fa7ddf9bfb8550dca28176971c93bcb7ecb7eec3097c01d9c55c191563c693aab + version: 1.14.0 + resolution: "tailwind-merge@npm:1.14.0" + checksum: 8cf5d37f51b3b32e4bdd5544feaed34357bfba2f64f14834cc4a21ac29b0ae22d7255386467a0f1dadb3e38499389efbbabeddcd0b16571af5a0d346a4921877 languageName: node linkType: hard @@ -37354,6 +37688,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.8.0": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: e4aba30e632b8c8902b47587fd13345e2827fa639e7c3121074d5ee0880723282411a8838f830b55100cbe4517672f84a2472667d355b81e8af165a55dc6203a + languageName: node + linkType: hard + "tslog@npm:^4.9.2": version: 4.9.2 resolution: "tslog@npm:4.9.2"