diff --git a/pages/404.tsx b/pages/404.tsx index 28801cfbef..0c3f2430b3 100644 --- a/pages/404.tsx +++ b/pages/404.tsx @@ -1,5 +1,6 @@ import { BookOpenIcon, CheckIcon, CodeIcon, DocumentTextIcon } from "@heroicons/react/outline"; import { ChevronRightIcon } from "@heroicons/react/solid"; +import { GetStaticPropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; import React from "react"; @@ -8,6 +9,8 @@ import { useLocale } from "@lib/hooks/useLocale"; import { HeadSeo } from "@components/seo/head-seo"; +import { ssgInit } from "@server/lib/ssg"; + export default function Custom404() { const { t } = useLocale(); const router = useRouter(); @@ -170,3 +173,13 @@ export default function Custom404() { ); } + +export const getStaticProps = async (context: GetStaticPropsContext) => { + const ssr = await ssgInit(context); + + return { + props: { + trpcState: ssr.dehydrate(), + }, + }; +}; diff --git a/pages/cancel/[uid].tsx b/pages/cancel/[uid].tsx index 53fa331c20..2d60577671 100644 --- a/pages/cancel/[uid].tsx +++ b/pages/cancel/[uid].tsx @@ -15,6 +15,8 @@ import CustomBranding from "@components/CustomBranding"; import { HeadSeo } from "@components/seo/head-seo"; import { Button } from "@components/ui/Button"; +import { ssrInit } from "@server/lib/ssr"; + export default function Type(props: inferSSRProps) { const { t } = useLocale(); // Get router variables @@ -145,6 +147,7 @@ export default function Type(props: inferSSRProps) { } export const getServerSideProps = async (context: GetServerSidePropsContext) => { + const ssr = await ssrInit(context); const session = await getSession(context); const booking = await prisma.booking.findUnique({ where: { @@ -202,6 +205,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => booking: bookingObj, cancellationAllowed: (!!session?.user && session.user?.id === booking.user?.id) || booking.startTime >= new Date(), + trpcState: ssr.dehydrate(), }, }; }; diff --git a/pages/success.tsx b/pages/success.tsx index 78b57538a8..711f72ffe7 100644 --- a/pages/success.tsx +++ b/pages/success.tsx @@ -22,6 +22,8 @@ import CustomBranding from "@components/CustomBranding"; import { HeadSeo } from "@components/seo/head-seo"; import Button from "@components/ui/Button"; +import { ssrInit } from "@server/lib/ssr"; + dayjs.extend(utc); dayjs.extend(toArray); dayjs.extend(timezone); @@ -279,6 +281,7 @@ export default function Success(props: inferSSRProps) } export async function getServerSideProps(context: GetServerSidePropsContext) { + const ssr = await ssrInit(context); const typeId = parseInt(asStringOrNull(context.query.type) ?? ""); if (isNaN(typeId)) { @@ -358,6 +361,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { hideBranding: eventType.team ? eventType.team.hideBranding : isBrandingHidden(eventType.users[0]), profile, eventType, + trpcState: ssr.dehydrate(), }, }; } diff --git a/server/lib/ssg.ts b/server/lib/ssg.ts new file mode 100644 index 0000000000..5bf4104bed --- /dev/null +++ b/server/lib/ssg.ts @@ -0,0 +1,43 @@ +import { GetStaticPropsContext } from "next"; +import { i18n } from "next-i18next.config"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import superjson from "superjson"; + +import prisma from "@lib/prisma"; + +import { appRouter } from "@server/routers/_app"; +import { createSSGHelpers } from "@trpc/react/ssg"; + +/** + * Initialize static site rendering tRPC helpers. + * Provides a method to prefetch tRPC-queries in a `getStaticProps`-function. + * Automatically prefetches i18n based on the passed in `context`-object to prevent i18n-flickering. + * Make sure to `return { props: { trpcState: ssr.dehydrate() } }` at the end. + */ +export async function ssgInit(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"]); + + const ssg = createSSGHelpers({ + router: appRouter, + transformer: superjson, + ctx: { + prisma, + session: null, + user: null, + locale, + i18n: _i18n, + }, + }); + + // always preload i18n + await ssg.fetchQuery("viewer.i18n"); + + return ssg; +} diff --git a/server/lib/ssr.ts b/server/lib/ssr.ts index 076c5b8d05..8f492b9038 100644 --- a/server/lib/ssr.ts +++ b/server/lib/ssr.ts @@ -6,6 +6,12 @@ import { createSSGHelpers } from "@trpc/react/ssg"; import { appRouter } from "../routers/_app"; +/** + * Initialize server-side rendering tRPC helpers. + * Provides a method to prefetch tRPC-queries in a `getServerSideProps`-function. + * Automatically prefetches i18n based on the passed in `context`-object to prevent i18n-flickering. + * Make sure to `return { props: { trpcState: ssr.dehydrate() } }` at the end. + */ export async function ssrInit(context: GetServerSidePropsContext) { const ctx = await createContext(context); diff --git a/tsconfig.json b/tsconfig.json index 4a5418130e..685c599cf8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -38,7 +38,7 @@ "jest-playwright-preset", "expect-playwright" ], - "allowJs": false, + "allowJs": true, "incremental": true }, "include": [