From 91253c4d5d1863c3979fd857a6305e45e757880d Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Thu, 3 Oct 2024 22:30:59 +0200 Subject: [PATCH 01/24] make it sdk like --- next/.env.sample | 4 +- next/app/[locale]/(marketing)/[slug]/page.tsx | 39 +- .../[locale]/(marketing)/blog/[slug]/page.tsx | 40 +- next/app/[locale]/(marketing)/blog/page.tsx | 36 +- next/app/[locale]/(marketing)/page.tsx | 33 +- .../(marketing)/products/[slug]/page.tsx | 32 +- .../[locale]/(marketing)/products/page.tsx | 31 +- next/app/[locale]/layout.tsx | 109 +- next/app/api/exit-preview/route.ts | 7 + next/app/api/preview/route.ts | 22 + next/app/api/revalidate/route.ts | 13 + next/app/layout.tsx | 4 +- next/components/blog-layout.tsx | 26 +- .../decorations/star-background.tsx | 3 +- next/components/draft-banner.tsx | 24 + next/components/dynamic-zone/brands.tsx | 23 +- next/components/event.tsx | 8 + next/components/navbar/index.tsx | 24 +- next/components/ui/globe.tsx | 1 - next/lib/strapi/fetchContentType.ts | 34 +- next/lib/strapi/nextjs/client.ts | 28 + next/lib/strapi/nextjs/server.ts | 36 + next/middleware.ts | 38 +- next/package.json | 4 + next/pnpm-lock.yaml | 5341 +++++++++++++++++ next/yarn.lock | 44 +- strapi/.env.example | 4 +- strapi/config/admin.ts | 86 +- strapi/config/features.ts | 5 + strapi/package.json | 8 +- strapi/src/admin/app.example.tsx | 39 - strapi/src/admin/app.tsx | 64 + .../components/PreviewButton/index.tsx | 158 +- strapi/src/index.ts | 31 +- strapi/types/generated/components.d.ts | 632 +- strapi/types/generated/contentTypes.d.ts | 1460 ++--- strapi/yarn.lock | 1775 ++---- 37 files changed, 7839 insertions(+), 2427 deletions(-) create mode 100644 next/app/api/exit-preview/route.ts create mode 100644 next/app/api/preview/route.ts create mode 100644 next/app/api/revalidate/route.ts create mode 100644 next/components/draft-banner.tsx create mode 100644 next/components/event.tsx create mode 100644 next/lib/strapi/nextjs/client.ts create mode 100644 next/lib/strapi/nextjs/server.ts create mode 100644 next/pnpm-lock.yaml create mode 100644 strapi/config/features.ts delete mode 100644 strapi/src/admin/app.example.tsx create mode 100644 strapi/src/admin/app.tsx diff --git a/next/.env.sample b/next/.env.sample index 62310fb..145d2d4 100644 --- a/next/.env.sample +++ b/next/.env.sample @@ -1,5 +1,5 @@ WEBSITE_URL=http://localhost:3000 # Add the correct ENV var for this onto your hosting platform, point it to your production website. PORT=3000 -NEXT_PUBLIC_API_URL=url-of-strapi -PREVIEW_SECRET=the-same-random-token-as-for-strapi \ No newline at end of file +NEXT_PUBLIC_API_URL=http://localhost:1337 +PREVIEW_SECRET=tobemodified \ No newline at end of file diff --git a/next/app/[locale]/(marketing)/[slug]/page.tsx b/next/app/[locale]/(marketing)/[slug]/page.tsx index 6d6abc5..07eb41b 100644 --- a/next/app/[locale]/(marketing)/[slug]/page.tsx +++ b/next/app/[locale]/(marketing)/[slug]/page.tsx @@ -1,8 +1,8 @@ -import { Metadata } from 'next'; +import { Metadata } from "next"; -import PageContent from '@/lib/shared/PageContent'; -import fetchContentType from '@/lib/strapi/fetchContentType'; -import { generateMetadataObject } from '@/lib/shared/metadata'; +import PageContent from "@/lib/shared/PageContent"; +import fetchContentType from "@/lib/strapi/fetchContentType"; +import { generateMetadataObject } from "@/lib/shared/metadata"; export async function generateMetadata({ params, @@ -10,8 +10,14 @@ export async function generateMetadata({ params: { locale: string; slug: string }; }): Promise { const pageData = await fetchContentType( - 'pages', - `filters[slug][$eq]=${params.slug}&filters[locale][$eq]=${params.locale}&populate=seo.metaImage`, + "pages", + { + filters: { + slug: params.slug, + locale: params.locale, + }, + populate: "seo.metaImage", + }, true ); @@ -20,14 +26,21 @@ export async function generateMetadata({ return metadata; } -export default async function Page({ params }: { params: { locale: string, slug: string } }) { +export default async function Page({ + params, +}: { + params: { locale: string; slug: string }; +}) { const pageData = await fetchContentType( - 'pages', - `filters[slug][$eq]=${params.slug}&filters[locale][$eq]=${params.locale}`, + "pages", + { + filters: { + slug: params.slug, + locale: params.locale, + }, + }, true ); - return ( - - ); -} \ No newline at end of file + return ; +} diff --git a/next/app/[locale]/(marketing)/blog/[slug]/page.tsx b/next/app/[locale]/(marketing)/blog/[slug]/page.tsx index 7de4e32..c02b3e7 100644 --- a/next/app/[locale]/(marketing)/blog/[slug]/page.tsx +++ b/next/app/[locale]/(marketing)/blog/[slug]/page.tsx @@ -1,25 +1,49 @@ -import { Metadata } from 'next'; +import { Metadata } from "next"; import { BlogLayout } from "@/components/blog-layout"; import fetchContentType from "@/lib/strapi/fetchContentType"; -import { BlocksRenderer } from '@strapi/blocks-react-renderer'; +import { BlocksRenderer } from "@strapi/blocks-react-renderer"; -import { generateMetadataObject } from '@/lib/shared/metadata'; +import { generateMetadataObject } from "@/lib/shared/metadata"; export async function generateMetadata({ params, }: { - params: { locale: string, slug: string }; + params: { locale: string; slug: string }; }): Promise { - const pageData = await fetchContentType("articles", `filters[slug]=${params?.slug}&filters[locale][$eq]=${params.locale}&populate=seo.metaImage`, true) + const pageData = await fetchContentType( + "articles", + { + filters: { + slug: params.slug, + locale: params.locale, + }, + populate: "seo.metaImage", + }, + true + ); const seo = pageData?.seo; const metadata = generateMetadataObject(seo); return metadata; } -export default async function singleArticlePage({ params }: { params: { slug: string, locale: string } }) { - const article = await fetchContentType("articles", `filters[slug]=${params?.slug}&filters[locale][$eq]=${params.locale}`, true) +export default async function singleArticlePage({ + params, +}: { + params: { slug: string; locale: string }; +}) { + const article = await fetchContentType( + "articles", + // `filters[slug]=${params?.slug}&filters[locale][$eq]=${params.locale}`, + { + filters: { + slug: params.slug, + locale: params.locale, + }, + }, + true + ); if (!article) { return
Blog not found
; @@ -30,4 +54,4 @@ export default async function singleArticlePage({ params }: { params: { slug: st ); -} \ No newline at end of file +} diff --git a/next/app/[locale]/(marketing)/blog/page.tsx b/next/app/[locale]/(marketing)/blog/page.tsx index ab49e97..bd021bd 100644 --- a/next/app/[locale]/(marketing)/blog/page.tsx +++ b/next/app/[locale]/(marketing)/blog/page.tsx @@ -9,28 +9,38 @@ import { BlogPostRows } from "@/components/blog-post-rows"; import { AmbientColor } from "@/components/decorations/ambient-color"; import fetchContentType from "@/lib/strapi/fetchContentType"; import { Article } from "@/types/types"; -import { generateMetadataObject } from '@/lib/shared/metadata'; - +import { generateMetadataObject } from "@/lib/shared/metadata"; export async function generateMetadata({ params, }: { params: { locale: string }; }): Promise { - const pageData = await fetchContentType('blog-page', `filters[locale]=${params.locale}&populate=seo.metaImage`, true) + const pageData = await fetchContentType( + "blog-page", + { + filters: { locale: params.locale }, + populate: "seo.metaImage", + }, + true + ); const seo = pageData?.seo; const metadata = generateMetadataObject(seo); return metadata; } -export default async function Blog({ - params, -}: { - params: { locale: string }; -}) { - const blogPage = await fetchContentType('blog-page', `filters[locale]=${params.locale}`, true) - const articles = await fetchContentType('articles', `filters[locale]=${params.locale}`) +export default async function Blog({ params }: { params: { locale: string } }) { + const blogPage = await fetchContentType( + "blog-page", + { + filters: { locale: params.locale }, + }, + true + ); + const articles = await fetchContentType("articles", { + filters: { locale: params.locale }, + }); return (
@@ -49,7 +59,11 @@ export default async function Blog({
{articles.data.slice(0, 1).map((article: Article) => ( - + ))} diff --git a/next/app/[locale]/(marketing)/page.tsx b/next/app/[locale]/(marketing)/page.tsx index 695e258..e25f2e6 100644 --- a/next/app/[locale]/(marketing)/page.tsx +++ b/next/app/[locale]/(marketing)/page.tsx @@ -1,8 +1,8 @@ -import { Metadata } from 'next'; +import { Metadata } from "next"; -import PageContent from '@/lib/shared/PageContent'; -import fetchContentType from '@/lib/strapi/fetchContentType'; -import { generateMetadataObject } from '@/lib/shared/metadata'; +import PageContent from "@/lib/shared/PageContent"; +import fetchContentType from "@/lib/strapi/fetchContentType"; +import { generateMetadataObject } from "@/lib/shared/metadata"; export async function generateMetadata({ params, @@ -10,8 +10,14 @@ export async function generateMetadata({ params: { locale: string }; }): Promise { const pageData = await fetchContentType( - 'pages', - `filters[slug][$eq]=homepage&filters[locale][$eq]=${params.locale}&populate=seo.metaImage`, + "pages", + { + filters: { + slug: "homepage", + locale: params.locale, + }, + populate: "seo.metaImage", + }, true ); @@ -20,10 +26,19 @@ export async function generateMetadata({ return metadata; } -export default async function HomePage({ params }: { params: { locale: string } }) { +export default async function HomePage({ + params, +}: { + params: { locale: string }; +}) { const pageData = await fetchContentType( - 'pages', - `filters[slug][$eq]=homepage&filters[locale][$eq]=${params.locale}`, + "pages", + { + filters: { + slug: "homepage", + locale: params.locale, + }, + }, true ); diff --git a/next/app/[locale]/(marketing)/products/[slug]/page.tsx b/next/app/[locale]/(marketing)/products/[slug]/page.tsx index ee1cf65..842cd6b 100644 --- a/next/app/[locale]/(marketing)/products/[slug]/page.tsx +++ b/next/app/[locale]/(marketing)/products/[slug]/page.tsx @@ -3,17 +3,24 @@ import { redirect } from "next/navigation"; import { Container } from "@/components/container"; import { AmbientColor } from "@/components/decorations/ambient-color"; import { SingleProduct } from "@/components/products/single-product"; -import DynamicZoneManager from '@/components/dynamic-zone/manager' -import { generateMetadataObject } from '@/lib/shared/metadata'; +import DynamicZoneManager from "@/components/dynamic-zone/manager"; +import { generateMetadataObject } from "@/lib/shared/metadata"; import fetchContentType from "@/lib/strapi/fetchContentType"; export async function generateMetadata({ params, }: { - params: { locale: string, slug: string }; + params: { locale: string; slug: string }; }): Promise { - const pageData = await fetchContentType("products", `filters[slug]=${params?.slug}&populate=seo.metaImage`, true) + const pageData = await fetchContentType( + "products", + { + filters: { slug: params.slug }, + populate: "seo.metaImage", + }, + true + ); const seo = pageData?.seo; const metadata = generateMetadataObject(seo); @@ -23,9 +30,15 @@ export async function generateMetadata({ export default async function SingleProductPage({ params, }: { - params: { slug: string, locale: string }; + params: { slug: string; locale: string }; }) { - const product = await fetchContentType("products", `filters[slug]=${params?.slug}`, true) + const product = await fetchContentType( + "products", + { + filters: { slug: params.slug }, + }, + true + ); if (!product) { redirect("/products"); @@ -36,7 +49,12 @@ export default async function SingleProductPage({ - {product?.dynamic_zone && ()} + {product?.dynamic_zone && ( + + )} ); diff --git a/next/app/[locale]/(marketing)/products/page.tsx b/next/app/[locale]/(marketing)/products/page.tsx index 5d74ad4..c928a9a 100644 --- a/next/app/[locale]/(marketing)/products/page.tsx +++ b/next/app/[locale]/(marketing)/products/page.tsx @@ -1,4 +1,4 @@ -import { Metadata } from 'next'; +import { Metadata } from "next"; import { AmbientColor } from "@/components/decorations/ambient-color"; import { Container } from "@/components/container"; @@ -9,14 +9,23 @@ import { ProductItems } from "@/components/products/product-items"; import { Subheading } from "@/components/elements/subheading"; import { IconShoppingCartUp } from "@tabler/icons-react"; import fetchContentType from "@/lib/strapi/fetchContentType"; -import { generateMetadataObject } from '@/lib/shared/metadata'; +import { generateMetadataObject } from "@/lib/shared/metadata"; export async function generateMetadata({ params, }: { params: { locale: string }; }): Promise { - const pageData = await fetchContentType("product-page", `filters[locale][$eq]=${params.locale}&populate=seo.metaImage`, true) + const pageData = await fetchContentType( + "product-page", + { + filters: { + locale: params.locale, + }, + populate: "seo.metaImage", + }, + true + ); const seo = pageData?.seo; const metadata = generateMetadataObject(seo); @@ -29,10 +38,20 @@ export default async function Products({ params: { locale: string }; }) { // Fetch the product-page and products data - const productPage = await fetchContentType('product-page', `filters[locale]=${params.locale}`, true); - const products = await fetchContentType('products', ``); + const productPage = await fetchContentType( + "product-page", + { + filters: { + locale: params.locale, + }, + }, + true + ); + const products = await fetchContentType("products"); - const featured = products?.data.filter((product: { featured: boolean }) => product.featured); + const featured = products?.data.filter( + (product: { featured: boolean }) => product.featured + ); return (
diff --git a/next/app/[locale]/layout.tsx b/next/app/[locale]/layout.tsx index f5d3447..e2e9be7 100644 --- a/next/app/[locale]/layout.tsx +++ b/next/app/[locale]/layout.tsx @@ -1,64 +1,79 @@ -import React from 'react' +import React from "react"; -import { Metadata } from 'next'; -import { Inter } from 'next/font/google'; -import { generateMetadataObject } from '@/lib/shared/metadata'; +import { Metadata } from "next"; +import { Inter } from "next/font/google"; +import { generateMetadataObject } from "@/lib/shared/metadata"; -import { Footer } from '@/components/footer'; -import { Navbar } from '@/components/navbar'; -import { CartProvider } from '@/context/cart-context'; -import { cn } from '@/lib/utils'; -import { ViewTransitions } from 'next-view-transitions'; -import fetchContentType from '@/lib/strapi/fetchContentType'; +import { Footer } from "@/components/footer"; +import { Navbar } from "@/components/navbar"; +import { CartProvider } from "@/context/cart-context"; +import { cn } from "@/lib/utils"; +import { ViewTransitions } from "next-view-transitions"; +import fetchContentType from "@/lib/strapi/fetchContentType"; +import { EventHandler } from "@/components/event"; +import { draftMode } from "next/headers"; +import { DraftBanner } from "@/components/draft-banner"; const inter = Inter({ - subsets: ["latin"], - display: "swap", - weight: ["400", "500", "600", "700", "800", "900"], + subsets: ["latin"], + display: "swap", + weight: ["400", "500", "600", "700", "800", "900"], }); // Default Global SEO for pages without them export async function generateMetadata({ - params, + params, }: { - params: { locale: string; slug: string }; + params: { locale: string; slug: string }; }): Promise { - const pageData = await fetchContentType( - 'global', - `&filters[locale][$eq]=${params.locale}&populate=seo.metaImage`, - true - ); + const pageData = await fetchContentType( + "global", + { + filters: { locale: params.locale }, + populate: "seo.metaImage", + }, + true + ); - const seo = pageData?.seo; - const metadata = generateMetadataObject(seo); - return metadata; + const seo = pageData?.seo; + const metadata = generateMetadataObject(seo); + return metadata; } export default async function LocaleLayout({ - children, - params: { locale } + children, + params: { locale }, }: { - children: React.ReactNode; - params: { locale: string }; + children: React.ReactNode; + params: { locale: string }; }) { + const { isEnabled } = draftMode(); - const pageData = await fetchContentType('global', `filters[locale][$eq]=${locale}`, true); - return ( - - - - - - {children} -