From e49b0a06aea3aeb3926696af9b032ec1f5f0eca7 Mon Sep 17 00:00:00 2001 From: Henrik Larsson Date: Mon, 21 Aug 2023 10:16:11 +0200 Subject: [PATCH] Test --- app/(site)/[locale]/[...slug]/page.tsx | 61 ++++++++----------- app/(site)/[locale]/layout.tsx | 13 +++- app/(site)/[locale]/page.tsx | 5 -- app/api/preview/route.ts | 26 ++++---- components/pages/home-page-preview.tsx | 24 ++++---- components/pages/home-page.tsx | 7 +-- components/preview/preview-provider.tsx | 30 +++++++++ .../ui/preview-banner/preview-banner.tsx | 2 +- lib/sanity/sanity.fetch.ts | 38 +++++++++++- lib/sanity/sanity.types.ts | 49 +++++++++++++++ package.json | 1 + pnpm-lock.yaml | 11 ++++ 12 files changed, 193 insertions(+), 74 deletions(-) create mode 100644 components/preview/preview-provider.tsx diff --git a/app/(site)/[locale]/[...slug]/page.tsx b/app/(site)/[locale]/[...slug]/page.tsx index b32c0d92f..be21d0282 100644 --- a/app/(site)/[locale]/[...slug]/page.tsx +++ b/app/(site)/[locale]/[...slug]/page.tsx @@ -1,17 +1,14 @@ import CategoryPage from '@/components/pages/category-page'; import ProductPage from '@/components/pages/product-page'; import SearchPage from '@/components/pages/search-page'; -import SearchPagePreview from '@/components/pages/search-page-preview'; import SinglePage from '@/components/pages/single-page'; -import SinglePagePreview from '@/components/pages/single-page-preview'; -import PreviewProvider from '@/components/preview-provider'; +// import PreviewProvider from '@/components/preview-provider'; import getQueryFromSlug from '@/helpers/get-query-from-slug'; -import { getCachedClient } from 'lib/sanity/sanity.client'; +import { getCategory, getPage, getProduct, getSearch } from '@/lib/sanity/sanity.fetch'; import type { Metadata } from 'next'; -import { draftMode } from 'next/headers'; import { notFound } from 'next/navigation'; -export const dynamic = 'force-dynamic'; +export const runtime = 'edge'; export async function generateMetadata({ params @@ -20,18 +17,23 @@ export async function generateMetadata({ }): Promise { const { slug, locale } = params; - const { query = '', queryParams } = getQueryFromSlug(slug, locale); + const { queryParams, docType } = getQueryFromSlug(slug, locale); - const page = await getCachedClient()(query, queryParams); + let page; + + docType === 'page' && (page = await getPage(queryParams.slug, queryParams.locale)); + docType === 'product' && (page = await getProduct(queryParams.slug, queryParams.locale)); + docType === 'category' && (page = await getCategory(queryParams.slug, queryParams.locale)); + docType === 'search' && (page = await getSearch(queryParams.slug, queryParams.locale)); if (!page) return notFound(); return { title: `${page.seo?.title || page.title}`, - description: page.seo?.description || page.bodySummary, + description: page.seo?.description, openGraph: { - publishedTime: page.createdAt, - modifiedTime: page.updatedAt, + // publishedTime: page.createdAt, + // modifiedTime: page.updatedAt, type: 'article' } }; @@ -39,49 +41,38 @@ export async function generateMetadata({ interface PageParams { params: { - locale: string; slug: string[]; + locale: string; }; } export default async function Page({ params }: PageParams) { - const preview = draftMode().isEnabled ? { token: process.env.SANITY_API_READ_TOKEN } : undefined; - const { slug, locale } = params; - const { query = '', queryParams, docType } = getQueryFromSlug(slug, locale); + const { queryParams, docType } = getQueryFromSlug(slug, locale); - let pageData; + let data; if (docType === 'page') { - pageData = await getCachedClient()(query, queryParams); + data = await getPage(queryParams.slug, queryParams.locale); } else if (docType === 'product') { - pageData = await getCachedClient()(query, queryParams); + data = await getProduct(queryParams.slug, queryParams.locale); } else if (docType === 'category') { - pageData = await getCachedClient()(query, queryParams); + data = await getCategory(queryParams.slug, queryParams.locale); } else if (docType === 'search') { - pageData = await getCachedClient()(query, queryParams); - } else { - return; + data = await getSearch(queryParams.slug, queryParams.locale); } - if (!pageData) return notFound(); - - if (preview && preview.token) { - return ( - - {docType === 'page' && } - {docType === 'search' && } - - ); + if (!data) { + notFound(); } return ( <> - {docType === 'page' && } - {docType === 'product' && } - {docType === 'category' && } - {docType === 'search' && } + {docType === 'page' && } + {docType === 'product' && } + {docType === 'category' && } + {docType === 'search' && } ); } diff --git a/app/(site)/[locale]/layout.tsx b/app/(site)/[locale]/layout.tsx index 0347a72d8..4a6eaa2db 100644 --- a/app/(site)/[locale]/layout.tsx +++ b/app/(site)/[locale]/layout.tsx @@ -1,8 +1,11 @@ +import PreviewProvider from '@/components/preview/preview-provider'; +import { token } from '@/lib/sanity/sanity.fetch'; import { Analytics } from '@vercel/analytics/react'; import Footer from 'components/layout/footer/footer'; import Header from 'components/layout/header/header'; import { NextIntlClientProvider } from 'next-intl'; import { Inter } from 'next/font/google'; +import { draftMode } from 'next/headers'; import { notFound } from 'next/navigation'; import { ReactNode, Suspense } from 'react'; import { supportedLanguages } from '../../../i18n-config'; @@ -54,7 +57,9 @@ export default async function LocaleLayout({ children, params: { locale } }: Loc notFound(); } - return ( + const isDraftMode = draftMode().isEnabled; + + const layout = ( @@ -70,4 +75,10 @@ export default async function LocaleLayout({ children, params: { locale } }: Loc ); + + if (isDraftMode) { + return {layout}; + } + + return layout; } diff --git a/app/(site)/[locale]/page.tsx b/app/(site)/[locale]/page.tsx index 23d19eee4..542665fb5 100644 --- a/app/(site)/[locale]/page.tsx +++ b/app/(site)/[locale]/page.tsx @@ -8,7 +8,6 @@ import { draftMode } from 'next/headers'; import { notFound } from 'next/navigation'; export const runtime = 'edge'; -export const dynamic = 'force-dynamic'; export async function generateMetadata({ params @@ -31,16 +30,12 @@ interface HomePageParams { } export default async function IndexPage({ params }: HomePageParams) { - // const preview = draftMode().isEnabled ? { token: process.env.SANITY_API_READ_TOKEN } : undefined; - const data = await getHomePage(params.locale); if (!data && !draftMode().isEnabled) { notFound(); } - console.log('Preview:', draftMode().isEnabled); - return ( import('./home-page')); -export default function HomePagePreview({ initialData, params }: HomePagePreviewParams) { - const [data] = useLiveQuery(initialData, homePageQuery, params); +export default function HomePagePreview({ data }: IndexPageParams) { + if (!data) { + return ( +
Please start editing your Home document to see the preview!
+ ); + } return ( <> - ;{/* @ts-ignore */} - + + ); } diff --git a/components/pages/home-page.tsx b/components/pages/home-page.tsx index 7c8998708..19226ba99 100644 --- a/components/pages/home-page.tsx +++ b/components/pages/home-page.tsx @@ -1,12 +1,11 @@ import DynamicContentManager from '@/components/layout/dynamic-content-manager/dynamic-content-manager'; import type { HomePagePayload } from '@/lib/sanity/sanity.types'; -interface IndexPageParams { + +export type IndexPageParams = { data: HomePagePayload | null; -} +}; export default function HomePage({ data }: IndexPageParams) { - // console.log(data); - return ( <> ; diff --git a/components/preview/preview-provider.tsx b/components/preview/preview-provider.tsx new file mode 100644 index 000000000..303bc681e --- /dev/null +++ b/components/preview/preview-provider.tsx @@ -0,0 +1,30 @@ +'use client'; + +import dynamic from 'next/dynamic'; +import { suspend } from 'suspend-react'; + +const LiveQueryProvider = dynamic(() => import('next-sanity/preview')); + +// suspend-react cache is global, so we use a unique key to avoid collisions +const UniqueKey = Symbol('lib/sanity.client'); + +export default function PreviewProvider({ + children, + token +}: { + children: React.ReactNode; + token: string; +}) { + const { client } = suspend(() => import('@/lib/sanity/sanity.client'), [UniqueKey]); + if (!token) throw new TypeError('Missing token'); + return ( + + {children} + + ); +} diff --git a/components/ui/preview-banner/preview-banner.tsx b/components/ui/preview-banner/preview-banner.tsx index a595d9317..a262127ab 100644 --- a/components/ui/preview-banner/preview-banner.tsx +++ b/components/ui/preview-banner/preview-banner.tsx @@ -4,7 +4,7 @@ import { useTranslations } from 'next-intl'; import Link from 'next/link'; interface PreviewBannerProps { - title: string; + title?: string; type?: string; } diff --git a/lib/sanity/sanity.fetch.ts b/lib/sanity/sanity.fetch.ts index aefb15aad..8ff472635 100644 --- a/lib/sanity/sanity.fetch.ts +++ b/lib/sanity/sanity.fetch.ts @@ -7,9 +7,9 @@ import { draftMode } from 'next/headers' import { revalidateSecret } from './sanity.api' -import { homePageQuery } from './queries' +import { categoryQuery, homePageQuery, pageQuery, productQuery, searchPageQuery } from './queries' -import { HomePagePayload } from './sanity.types' +import { CategoryPayload, HomePagePayload, PagePayload, ProductPayload, SearchPayload } from './sanity.types' export const token = process.env.SANITY_API_READ_TOKEN @@ -56,6 +56,38 @@ export function getHomePage(locale: string) { return sanityFetch({ query: homePageQuery, params: { locale }, - tags: ['home', 'products', 'categories'], + tags: ['home', 'products', 'categories', 'page'], + }) +} + +export function getPage(slug: string, locale: string) { + return sanityFetch({ + query: pageQuery, + params: { slug, locale }, + tags: ['page'], + }) +} + +export function getProduct(slug: string, locale: string) { + return sanityFetch({ + query: productQuery, + params: { slug, locale }, + tags: ['product'], + }) +} + +export function getCategory(slug: string, locale: string) { + return sanityFetch({ + query: categoryQuery, + params: { slug, locale }, + tags: ['category'], + }) +} + +export function getSearch(slug: string, locale: string) { + return sanityFetch({ + query: searchPageQuery, + params: { slug, locale }, + tags: ['search'], }) } \ No newline at end of file diff --git a/lib/sanity/sanity.types.ts b/lib/sanity/sanity.types.ts index 4f2c8c0f8..bffb8fd22 100644 --- a/lib/sanity/sanity.types.ts +++ b/lib/sanity/sanity.types.ts @@ -9,4 +9,53 @@ export interface HomePagePayload { description?: string; image: Image } +} + +export interface PagePayload { + content?: [] + title?: string + _type?: string + slug?: string + seo?: { + title?: string; + description?: string; + image: Image + } +} + +export interface ProductPayload { + title?: string + name?: string + description?: string + images?: Image[] + currencyCode?: string + _type?: string + slug?: string + seo?: { + title?: string; + description?: string; + image: Image + } +} + +export interface CategoryPayload { + title?: string + _type?: string + slug?: string + seo?: { + title?: string; + description?: string; + image: Image + } +} + +export interface SearchPayload { + title?: string + _type?: string + slug?: string + seo?: { + title?: string; + description?: string; + image: Image + } } \ No newline at end of file diff --git a/package.json b/package.json index 9215bd8be..1be536e01 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "slug": "^8.2.2", "slugify": "^1.6.5", "styled-components": "^5.3.10", + "suspend-react": "^0.1.3", "tailwind-merge": "^1.12.0", "tailwindcss-animate": "^1.0.5" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 429617795..e1fc5fdf8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -119,6 +119,9 @@ dependencies: styled-components: specifier: ^5.3.10 version: 5.3.11(@babel/core@7.22.10)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0) + suspend-react: + specifier: ^0.1.3 + version: 0.1.3(react@18.2.0) tailwind-merge: specifier: ^1.12.0 version: 1.14.0 @@ -8169,6 +8172,14 @@ packages: react: 18.2.0 dev: false + /suspend-react@0.1.3(react@18.2.0): + resolution: {integrity: sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==} + peerDependencies: + react: '>=17.0' + dependencies: + react: 18.2.0 + dev: false + /symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: false