mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 16:07:01 +00:00
Test
This commit is contained in:
parent
1baa3c1f8d
commit
e49b0a06ae
@ -1,17 +1,14 @@
|
|||||||
import CategoryPage from '@/components/pages/category-page';
|
import CategoryPage from '@/components/pages/category-page';
|
||||||
import ProductPage from '@/components/pages/product-page';
|
import ProductPage from '@/components/pages/product-page';
|
||||||
import SearchPage from '@/components/pages/search-page';
|
import SearchPage from '@/components/pages/search-page';
|
||||||
import SearchPagePreview from '@/components/pages/search-page-preview';
|
|
||||||
import SinglePage from '@/components/pages/single-page';
|
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 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 type { Metadata } from 'next';
|
||||||
import { draftMode } from 'next/headers';
|
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
|
|
||||||
export const dynamic = 'force-dynamic';
|
export const runtime = 'edge';
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params
|
params
|
||||||
@ -20,18 +17,23 @@ export async function generateMetadata({
|
|||||||
}): Promise<Metadata> {
|
}): Promise<Metadata> {
|
||||||
const { slug, locale } = params;
|
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();
|
if (!page) return notFound();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: `${page.seo?.title || page.title}`,
|
title: `${page.seo?.title || page.title}`,
|
||||||
description: page.seo?.description || page.bodySummary,
|
description: page.seo?.description,
|
||||||
openGraph: {
|
openGraph: {
|
||||||
publishedTime: page.createdAt,
|
// publishedTime: page.createdAt,
|
||||||
modifiedTime: page.updatedAt,
|
// modifiedTime: page.updatedAt,
|
||||||
type: 'article'
|
type: 'article'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -39,49 +41,38 @@ export async function generateMetadata({
|
|||||||
|
|
||||||
interface PageParams {
|
interface PageParams {
|
||||||
params: {
|
params: {
|
||||||
locale: string;
|
|
||||||
slug: string[];
|
slug: string[];
|
||||||
|
locale: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Page({ params }: PageParams) {
|
export default async function Page({ params }: PageParams) {
|
||||||
const preview = draftMode().isEnabled ? { token: process.env.SANITY_API_READ_TOKEN } : undefined;
|
|
||||||
|
|
||||||
const { slug, locale } = params;
|
const { slug, locale } = params;
|
||||||
|
|
||||||
const { query = '', queryParams, docType } = getQueryFromSlug(slug, locale);
|
const { queryParams, docType } = getQueryFromSlug(slug, locale);
|
||||||
|
|
||||||
let pageData;
|
let data;
|
||||||
|
|
||||||
if (docType === 'page') {
|
if (docType === 'page') {
|
||||||
pageData = await getCachedClient()(query, queryParams);
|
data = await getPage(queryParams.slug, queryParams.locale);
|
||||||
} else if (docType === 'product') {
|
} else if (docType === 'product') {
|
||||||
pageData = await getCachedClient()(query, queryParams);
|
data = await getProduct(queryParams.slug, queryParams.locale);
|
||||||
} else if (docType === 'category') {
|
} else if (docType === 'category') {
|
||||||
pageData = await getCachedClient()(query, queryParams);
|
data = await getCategory(queryParams.slug, queryParams.locale);
|
||||||
} else if (docType === 'search') {
|
} else if (docType === 'search') {
|
||||||
pageData = await getCachedClient()(query, queryParams);
|
data = await getSearch(queryParams.slug, queryParams.locale);
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pageData) return notFound();
|
if (!data) {
|
||||||
|
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{docType === 'page' && <SinglePage data={pageData} />}
|
{docType === 'page' && <SinglePage data={data} />}
|
||||||
{docType === 'product' && <ProductPage data={pageData} />}
|
{docType === 'product' && <ProductPage data={data} />}
|
||||||
{docType === 'category' && <CategoryPage data={pageData} />}
|
{docType === 'category' && <CategoryPage data={data} />}
|
||||||
{docType === 'search' && <SearchPage data={pageData} />}
|
{docType === 'search' && <SearchPage data={data} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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 { Analytics } from '@vercel/analytics/react';
|
||||||
import Footer from 'components/layout/footer/footer';
|
import Footer from 'components/layout/footer/footer';
|
||||||
import Header from 'components/layout/header/header';
|
import Header from 'components/layout/header/header';
|
||||||
import { NextIntlClientProvider } from 'next-intl';
|
import { NextIntlClientProvider } from 'next-intl';
|
||||||
import { Inter } from 'next/font/google';
|
import { Inter } from 'next/font/google';
|
||||||
|
import { draftMode } from 'next/headers';
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
import { ReactNode, Suspense } from 'react';
|
import { ReactNode, Suspense } from 'react';
|
||||||
import { supportedLanguages } from '../../../i18n-config';
|
import { supportedLanguages } from '../../../i18n-config';
|
||||||
@ -54,7 +57,9 @@ export default async function LocaleLayout({ children, params: { locale } }: Loc
|
|||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const isDraftMode = draftMode().isEnabled;
|
||||||
|
|
||||||
|
const layout = (
|
||||||
<html lang={locale} className={inter.variable}>
|
<html lang={locale} className={inter.variable}>
|
||||||
<body className="flex min-h-screen flex-col">
|
<body className="flex min-h-screen flex-col">
|
||||||
<NextIntlClientProvider locale={locale} messages={messages}>
|
<NextIntlClientProvider locale={locale} messages={messages}>
|
||||||
@ -70,4 +75,10 @@ export default async function LocaleLayout({ children, params: { locale } }: Loc
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isDraftMode) {
|
||||||
|
return <PreviewProvider token={token!}>{layout}</PreviewProvider>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import { draftMode } from 'next/headers';
|
|||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
|
|
||||||
export const runtime = 'edge';
|
export const runtime = 'edge';
|
||||||
export const dynamic = 'force-dynamic';
|
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params
|
params
|
||||||
@ -31,16 +30,12 @@ interface HomePageParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function IndexPage({ params }: 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);
|
const data = await getHomePage(params.locale);
|
||||||
|
|
||||||
if (!data && !draftMode().isEnabled) {
|
if (!data && !draftMode().isEnabled) {
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Preview:', draftMode().isEnabled);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LiveQuery
|
<LiveQuery
|
||||||
enabled={draftMode().isEnabled}
|
enabled={draftMode().isEnabled}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { previewSecretId } from '@/lib/sanity/sanity.api'
|
// import { previewSecretId } from '@/lib/sanity/sanity.api'
|
||||||
import { client } from '@/lib/sanity/sanity.client'
|
// import { client } from '@/lib/sanity/sanity.client'
|
||||||
import { token } from '@/lib/sanity/sanity.fetch'
|
import { token } from '@/lib/sanity/sanity.fetch'
|
||||||
import { draftMode } from 'next/headers'
|
import { draftMode } from 'next/headers'
|
||||||
import { isValidSecret } from 'sanity-plugin-iframe-pane/is-valid-secret'
|
|
||||||
|
|
||||||
export const runtime = 'edge'
|
export const runtime = 'edge'
|
||||||
|
|
||||||
@ -18,24 +17,27 @@ export async function GET(request: Request) {
|
|||||||
'The `SANITY_API_READ_TOKEN` environment variable is required.',
|
'The `SANITY_API_READ_TOKEN` environment variable is required.',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!secret) {
|
if (!secret) {
|
||||||
return new Response('Invalid secret', { status: 401 })
|
return new Response('Invalid secret', { status: 401 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const authenticatedClient = client.withConfig({ token })
|
// const authenticatedClient = client.withConfig({ token })
|
||||||
|
|
||||||
const validSecret = await isValidSecret(
|
// const validSecret = await isValidSecret(
|
||||||
authenticatedClient,
|
// authenticatedClient,
|
||||||
previewSecretId,
|
// previewSecretId,
|
||||||
secret,
|
// secret,
|
||||||
)
|
// )
|
||||||
|
|
||||||
if (!validSecret) {
|
// if (!validSecret) {
|
||||||
return new Response('Invalid secret', { status: 401 })
|
// return new Response('Invalid secret', { status: 401 })
|
||||||
}
|
// }
|
||||||
|
|
||||||
draftMode().enable()
|
draftMode().enable()
|
||||||
|
|
||||||
|
console.log(draftMode())
|
||||||
|
|
||||||
if (type === 'home') {
|
if (type === 'home') {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 307,
|
status: 307,
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { homePageQuery } from '@/lib/sanity/queries';
|
import dynamic from 'next/dynamic';
|
||||||
import { useLiveQuery } from '@sanity/preview-kit';
|
|
||||||
import PreviewBanner from '../ui/preview-banner';
|
import PreviewBanner from '../ui/preview-banner';
|
||||||
import HomePage from './home-page';
|
import type { IndexPageParams } from './home-page';
|
||||||
|
|
||||||
interface HomePagePreviewParams {
|
const HomePage = dynamic(() => import('./home-page'));
|
||||||
initialData: [];
|
|
||||||
params: {
|
|
||||||
locale: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function HomePagePreview({ initialData, params }: HomePagePreviewParams) {
|
export default function HomePagePreview({ data }: IndexPageParams) {
|
||||||
const [data] = useLiveQuery(initialData, homePageQuery, params);
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<div className="text-center">Please start editing your Home document to see the preview!</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<HomePage data={data} />;{/* @ts-ignore */}
|
<HomePage data={data} />
|
||||||
<PreviewBanner title={data?.title} type={data?._type} />
|
<PreviewBanner title={data?.title ? data.title : ''} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import DynamicContentManager from '@/components/layout/dynamic-content-manager/dynamic-content-manager';
|
import DynamicContentManager from '@/components/layout/dynamic-content-manager/dynamic-content-manager';
|
||||||
import type { HomePagePayload } from '@/lib/sanity/sanity.types';
|
import type { HomePagePayload } from '@/lib/sanity/sanity.types';
|
||||||
interface IndexPageParams {
|
|
||||||
|
export type IndexPageParams = {
|
||||||
data: HomePagePayload | null;
|
data: HomePagePayload | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default function HomePage({ data }: IndexPageParams) {
|
export default function HomePage({ data }: IndexPageParams) {
|
||||||
// console.log(data);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DynamicContentManager content={data?.content} />;
|
<DynamicContentManager content={data?.content} />;
|
||||||
|
30
components/preview/preview-provider.tsx
Normal file
30
components/preview/preview-provider.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
@ -4,7 +4,7 @@ import { useTranslations } from 'next-intl';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
interface PreviewBannerProps {
|
interface PreviewBannerProps {
|
||||||
title: string;
|
title?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@ import { draftMode } from 'next/headers'
|
|||||||
|
|
||||||
import { revalidateSecret } from './sanity.api'
|
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
|
export const token = process.env.SANITY_API_READ_TOKEN
|
||||||
|
|
||||||
@ -56,6 +56,38 @@ export function getHomePage(locale: string) {
|
|||||||
return sanityFetch<HomePagePayload | null>({
|
return sanityFetch<HomePagePayload | null>({
|
||||||
query: homePageQuery,
|
query: homePageQuery,
|
||||||
params: { locale },
|
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'],
|
||||||
})
|
})
|
||||||
}
|
}
|
@ -9,4 +9,53 @@ export interface HomePagePayload {
|
|||||||
description?: string;
|
description?: string;
|
||||||
image: Image
|
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
|
||||||
|
}
|
||||||
}
|
}
|
@ -57,6 +57,7 @@
|
|||||||
"slug": "^8.2.2",
|
"slug": "^8.2.2",
|
||||||
"slugify": "^1.6.5",
|
"slugify": "^1.6.5",
|
||||||
"styled-components": "^5.3.10",
|
"styled-components": "^5.3.10",
|
||||||
|
"suspend-react": "^0.1.3",
|
||||||
"tailwind-merge": "^1.12.0",
|
"tailwind-merge": "^1.12.0",
|
||||||
"tailwindcss-animate": "^1.0.5"
|
"tailwindcss-animate": "^1.0.5"
|
||||||
},
|
},
|
||||||
|
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@ -119,6 +119,9 @@ dependencies:
|
|||||||
styled-components:
|
styled-components:
|
||||||
specifier: ^5.3.10
|
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)
|
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:
|
tailwind-merge:
|
||||||
specifier: ^1.12.0
|
specifier: ^1.12.0
|
||||||
version: 1.14.0
|
version: 1.14.0
|
||||||
@ -8169,6 +8172,14 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
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:
|
/symbol-tree@3.2.4:
|
||||||
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user