diff --git a/apps/web/components/ImageUploader.tsx b/apps/web/components/ImageUploader.tsx index 11ceeeb394..650e39d50c 100644 --- a/apps/web/components/ImageUploader.tsx +++ b/apps/web/components/ImageUploader.tsx @@ -1,11 +1,11 @@ import { FormEvent, useCallback, useEffect, useState } from "react"; import Cropper from "react-easy-crop"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Button, Dialog, DialogClose, DialogContent, DialogTrigger } from "@calcom/ui"; import { Area, getCroppedImg } from "@lib/cropImage"; import { useFileReader } from "@lib/hooks/useFileReader"; +import { useLocale } from "@lib/hooks/useLocale"; import Slider from "@components/Slider"; diff --git a/apps/web/components/security/TwoFactorAuthSection.tsx b/apps/web/components/security/TwoFactorAuthSection.tsx index 05cf9e6882..c53feff3bf 100644 --- a/apps/web/components/security/TwoFactorAuthSection.tsx +++ b/apps/web/components/security/TwoFactorAuthSection.tsx @@ -1,8 +1,9 @@ import { useState } from "react"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Badge, Button } from "@calcom/ui"; +import { useLocale } from "@lib/hooks/useLocale"; + import DisableTwoFactorModal from "./DisableTwoFactorModal"; import EnableTwoFactorModal from "./EnableTwoFactorModal"; diff --git a/apps/web/components/team/screens/Team.tsx b/apps/web/components/team/screens/Team.tsx index c3527cc6fc..b00e5c3c31 100644 --- a/apps/web/components/team/screens/Team.tsx +++ b/apps/web/components/team/screens/Team.tsx @@ -3,9 +3,10 @@ import Link from "next/link"; import { TeamPageProps } from "pages/team/[slug]"; import { WEBAPP_URL } from "@calcom/lib/constants"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Avatar } from "@calcom/ui"; +import { useLocale } from "@lib/hooks/useLocale"; + const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true }); type TeamType = TeamPageProps["team"]; diff --git a/apps/web/lib/hooks/useLocale.ts b/apps/web/lib/hooks/useLocale.ts new file mode 100644 index 0000000000..9e8ca501fd --- /dev/null +++ b/apps/web/lib/hooks/useLocale.ts @@ -0,0 +1,11 @@ +import { useTranslation } from "next-i18next"; + +/** @deprecated use the one from `@calcom/lib/hooks/useLocale` */ +export const useLocale = () => { + const { i18n, t } = useTranslation("common"); + + return { + i18n, + t, + }; +}; diff --git a/apps/web/pages/404.tsx b/apps/web/pages/404.tsx index 5aa7f89cfd..44ac023d22 100644 --- a/apps/web/pages/404.tsx +++ b/apps/web/pages/404.tsx @@ -4,10 +4,11 @@ import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import { COMPANY_NAME, DEVELOPER_DOCS, DOCS_URL, JOIN_SLACK, WEBSITE_URL } from "@calcom/lib/constants"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; import { HeadSeo } from "@calcom/ui"; import { FiFileText, FiCheck, FiBookOpen, FiChevronRight } from "@calcom/ui/components/icon"; +import { useLocale } from "@lib/hooks/useLocale"; + import { ssgInit } from "@server/lib/ssg"; export default function Custom404() { diff --git a/apps/web/pages/api/trpc/[trpc].ts b/apps/web/pages/api/trpc/[trpc].ts index fe306a02d3..7204fc2a30 100644 --- a/apps/web/pages/api/trpc/[trpc].ts +++ b/apps/web/pages/api/trpc/[trpc].ts @@ -1,8 +1,6 @@ /** * This file contains tRPC's HTTP response handler */ -import { z } from "zod"; - import * as trpcNext from "@calcom/trpc/server/adapters/next"; import { createContext } from "@calcom/trpc/server/createContext"; import { appRouter } from "@calcom/trpc/server/routers/_app"; @@ -32,44 +30,34 @@ export default trpcNext.createNextApiHandler({ * @link https://trpc.io/docs/caching#api-response-caching */ responseMeta({ ctx, paths, type, errors }) { - // Some helpers relevant to this function only - const ONE_DAY_IN_SECONDS = 60 * 60 * 24; - // assuming you have all your public routes with the keyword `public` in them + // assuming we have all our public routes in `viewer.public` const allPublic = paths && paths.every((path) => path.startsWith("viewer.public.")); // checking that no procedures errored const allOk = errors.length === 0; // checking we're doing a query request const isQuery = type === "query"; - const noHeaders = {}; - // We cannot set headers on SSG queries - if (!ctx?.res) return noHeaders; + // i18n response depends on request header + const nonCacheableQueries = ["viewer.public.i18n"]; + const isThereANonCacheableQuery = paths?.some((path) => nonCacheableQueries.includes(path)); + const isThereACacheableQuery = paths?.some((path) => !nonCacheableQueries.includes(path)); + if (isThereANonCacheableQuery && isThereACacheableQuery) { + console.warn( + "Cacheable and Non-cacheable queries are mixed in the same request. Not going to cache the request" + ); + } - const defaultHeaders: Record<"headers", Record> = { - headers: {}, - }; - - const timezone = z.string().safeParse(ctx.req?.headers["x-vercel-ip-timezone"]); - if (timezone.success) defaultHeaders.headers["x-cal-timezone"] = timezone.data; - - // We need all these conditions to be true to set cache headers - if (!(allPublic && allOk && isQuery)) return defaultHeaders; - - defaultHeaders.headers["cache-control"] = `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`; - - // Our cache can change depending on our current paths value. Since paths is an array, - // we want to create a map that can match potential paths with their desired cache value - const cacheRules = { - "viewer.public.i18n": `max-age=${ONE_DAY_IN_SECONDS}, s-maxage=${ONE_DAY_IN_SECONDS}, stale-while-revalidate`, - // Revalidation time here should be 1 second, per https://github.com/calcom/cal.com/pull/6823#issuecomment-1423215321 - "viewer.public.slots.getSchedule": `max-age=0, s-maxage=1`, - } as const; - - // Find which element above is an exact match for this group of paths - const matchedPath = paths.find((v) => v in cacheRules) as keyof typeof cacheRules; - - if (matchedPath) defaultHeaders.headers["cache-control"] = cacheRules[matchedPath]; - - return defaultHeaders; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ctx.req is available for SSR but not SSG + if (!!ctx?.req && allPublic && allOk && isQuery && !isThereANonCacheableQuery) { + // cache request for 1 day + revalidate once every 5 seconds + const ONE_DAY_IN_SECONDS = 60 * 60 * 24; + return { + headers: { + "cache-control": `s-maxage=5, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`, + }, + }; + } + return {}; }, }); diff --git a/apps/web/pages/auth/forgot-password/[id].tsx b/apps/web/pages/auth/forgot-password/[id].tsx index 35450c2f59..ba4fec7760 100644 --- a/apps/web/pages/auth/forgot-password/[id].tsx +++ b/apps/web/pages/auth/forgot-password/[id].tsx @@ -6,10 +6,11 @@ import Link from "next/link"; import React, { useMemo } from "react"; import dayjs from "@calcom/dayjs"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; import prisma from "@calcom/prisma"; import { Button, TextField } from "@calcom/ui"; +import { useLocale } from "@lib/hooks/useLocale"; + import AuthContainer from "@components/ui/AuthContainer"; type Props = { diff --git a/apps/web/pages/auth/forgot-password/index.tsx b/apps/web/pages/auth/forgot-password/index.tsx index b995d33c4c..cc389a382b 100644 --- a/apps/web/pages/auth/forgot-password/index.tsx +++ b/apps/web/pages/auth/forgot-password/index.tsx @@ -5,10 +5,10 @@ import Link from "next/link"; import { useRouter } from "next/router"; import React, { SyntheticEvent } from "react"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Button, EmailField } from "@calcom/ui"; import { getSession } from "@lib/auth"; +import { useLocale } from "@lib/hooks/useLocale"; import AuthContainer from "@components/ui/AuthContainer"; diff --git a/apps/web/pages/settings/my-account/general.tsx b/apps/web/pages/settings/my-account/general.tsx index 7de2e10bf7..a6034594a8 100644 --- a/apps/web/pages/settings/my-account/general.tsx +++ b/apps/web/pages/settings/my-account/general.tsx @@ -69,9 +69,7 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => { const { t } = useLocale(); const mutation = trpc.viewer.updateProfile.useMutation({ - onSuccess: async () => { - // Invalidate our previous i18n cache - await utils.viewer.public.i18n.invalidate(); + onSuccess: () => { reset(getValues()); showToast(t("settings_updated_successfully"), "success"); },