This commit is contained in:
Henrik Larsson 2023-08-21 10:16:11 +02:00
parent 1baa3c1f8d
commit e49b0a06ae
12 changed files with 193 additions and 74 deletions

View File

@ -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<Metadata> {
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 (
<PreviewProvider token={preview.token}>
{docType === 'page' && <SinglePagePreview initialData={pageData} params={queryParams} />}
{docType === 'search' && <SearchPagePreview initialData={pageData} params={queryParams} />}
</PreviewProvider>
);
if (!data) {
notFound();
}
return (
<>
{docType === 'page' && <SinglePage data={pageData} />}
{docType === 'product' && <ProductPage data={pageData} />}
{docType === 'category' && <CategoryPage data={pageData} />}
{docType === 'search' && <SearchPage data={pageData} />}
{docType === 'page' && <SinglePage data={data} />}
{docType === 'product' && <ProductPage data={data} />}
{docType === 'category' && <CategoryPage data={data} />}
{docType === 'search' && <SearchPage data={data} />}
</>
);
}

View File

@ -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 = (
<html lang={locale} className={inter.variable}>
<body className="flex min-h-screen flex-col">
<NextIntlClientProvider locale={locale} messages={messages}>
@ -70,4 +75,10 @@ export default async function LocaleLayout({ children, params: { locale } }: Loc
</body>
</html>
);
if (isDraftMode) {
return <PreviewProvider token={token!}>{layout}</PreviewProvider>;
}
return layout;
}

View File

@ -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 (
<LiveQuery
enabled={draftMode().isEnabled}

View File

@ -1,8 +1,7 @@
import { previewSecretId } from '@/lib/sanity/sanity.api'
import { client } from '@/lib/sanity/sanity.client'
// import { previewSecretId } from '@/lib/sanity/sanity.api'
// import { client } from '@/lib/sanity/sanity.client'
import { token } from '@/lib/sanity/sanity.fetch'
import { draftMode } from 'next/headers'
import { isValidSecret } from 'sanity-plugin-iframe-pane/is-valid-secret'
export const runtime = 'edge'
@ -18,24 +17,27 @@ export async function GET(request: Request) {
'The `SANITY_API_READ_TOKEN` environment variable is required.',
)
}
if (!secret) {
return new Response('Invalid secret', { status: 401 })
}
const authenticatedClient = client.withConfig({ token })
// const authenticatedClient = client.withConfig({ token })
const validSecret = await isValidSecret(
authenticatedClient,
previewSecretId,
secret,
)
// const validSecret = await isValidSecret(
// authenticatedClient,
// previewSecretId,
// secret,
// )
if (!validSecret) {
return new Response('Invalid secret', { status: 401 })
}
// if (!validSecret) {
// return new Response('Invalid secret', { status: 401 })
// }
draftMode().enable()
console.log(draftMode())
if (type === 'home') {
return new Response(null, {
status: 307,

View File

@ -1,24 +1,22 @@
'use client';
import { homePageQuery } from '@/lib/sanity/queries';
import { useLiveQuery } from '@sanity/preview-kit';
import dynamic from 'next/dynamic';
import PreviewBanner from '../ui/preview-banner';
import HomePage from './home-page';
import type { IndexPageParams } from './home-page';
interface HomePagePreviewParams {
initialData: [];
params: {
locale: string;
};
const HomePage = dynamic(() => import('./home-page'));
export default function HomePagePreview({ data }: IndexPageParams) {
if (!data) {
return (
<div className="text-center">Please start editing your Home document to see the preview!</div>
);
}
export default function HomePagePreview({ initialData, params }: HomePagePreviewParams) {
const [data] = useLiveQuery(initialData, homePageQuery, params);
return (
<>
<HomePage data={data} />;{/* @ts-ignore */}
<PreviewBanner title={data?.title} type={data?._type} />
<HomePage data={data} />
<PreviewBanner title={data?.title ? data.title : ''} />
</>
);
}

View File

@ -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 (
<>
<DynamicContentManager content={data?.content} />;

View File

@ -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 (
<LiveQueryProvider
client={client}
token={token}
// Uncomment below to see debug reports
logger={console}
>
{children}
</LiveQueryProvider>
);
}

View File

@ -4,7 +4,7 @@ import { useTranslations } from 'next-intl';
import Link from 'next/link';
interface PreviewBannerProps {
title: string;
title?: string;
type?: string;
}

View File

@ -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<HomePagePayload | null>({
query: homePageQuery,
params: { locale },
tags: ['home', 'products', 'categories'],
tags: ['home', 'products', 'categories', 'page'],
})
}
export function getPage(slug: string, locale: string) {
return sanityFetch<PagePayload | null>({
query: pageQuery,
params: { slug, locale },
tags: ['page'],
})
}
export function getProduct(slug: string, locale: string) {
return sanityFetch<ProductPayload | null>({
query: productQuery,
params: { slug, locale },
tags: ['product'],
})
}
export function getCategory(slug: string, locale: string) {
return sanityFetch<CategoryPayload | null>({
query: categoryQuery,
params: { slug, locale },
tags: ['category'],
})
}
export function getSearch(slug: string, locale: string) {
return sanityFetch<SearchPayload | null>({
query: searchPageQuery,
params: { slug, locale },
tags: ['search'],
})
}

View File

@ -10,3 +10,52 @@ export interface HomePagePayload {
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
}
}

View File

@ -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"
},

11
pnpm-lock.yaml generated
View File

@ -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