Il s'agit d'un article de partenariat sponsorisé par OneEntry CMS .
Créer une application de commerce électronique est souvent une tâche difficile. Avec autant d'alternatives disponibles, il n'est pas facile de choisir une pile technologique qui répond aux exigences du projet, aux besoins d'évolutivité et à la durabilité à long terme.
Un autre point crucial est que les projets de commerce électronique traitent de nombreuses données et opérations CRUD. Créer un système backend solide, évolutif et sécurisé peut prendre beaucoup de temps, même pour les développeurs les plus expérimentés.
J'ai choisi une pile technologique basée sur NextJS, TypeScript, Tailwind CSS et OneEntry CMS. Nous construirons nous-mêmes un projet de commerce électronique pratique pour voir comment il fonctionne ensemble et comment il pourrait être utilisé pour simplifier la gestion de contenu.
Le code de ce projet sera disponible dans le référentiel GitHub .
NextJS est un framework React permettant de créer des applications Web rapides et efficaces, doté de fonctionnalités telles que le rendu client et serveur, la récupération de données, les gestionnaires de routes, le middleware, les optimisations intégrées et bien plus encore.
TypeScript ajoute un typage statique à JavaScript, ce qui facilite la détection et la correction des erreurs pour les projets évolutifs comme le commerce électronique. Il augmente également la productivité grâce à des fonctionnalités telles que la saisie semi-automatique et l'assistance à la refactorisation.
Tailwind CSS accélère la partie style des applications Web, permettant aux développeurs de styliser les éléments dans le balisage sans avoir besoin de basculer entre les fichiers CSS externes et de proposer les noms de classe pour chacun.
OneEntry CMS est un système de gestion de contenu sans tête avec une interface facile à utiliser, un backend facilement évolutif, une API rapide et une documentation claire pour augmenter votre productivité pour la création et l'expérience de gestion de contenu de sites Web.
La page de destination affichera le titre du titre, répertoriera les fonctionnalités de la boutique et inclura l'image du héros.
La première section boutique sera dédiée aux Vêtements.
La deuxième section de la boutique comprendra le Gear.
Chacun des éléments aura une page d'aperçu individuelle avec des détails.
Les articles déjà dans le panier auront la possibilité de les supprimer.
Le panier listera tous les articles sélectionnés et calculera le total.
Tout d’abord, l’utilisateur devra créer un nouveau compte. Pour ce faire, accédez à la page d'accueil de OneEntry et inscrivez-vous via votre compte de messagerie.
Après cela, connectez-vous et vous serez dirigé vers le tableau de bord OneEntry.
Commencez par créer un nouveau projet.
Vous recevrez le code gratuit pour utiliser le plan Study pendant un mois. Vous aurez la possibilité de l'activer lors du processus de création du projet.
La création du projet prendra quelques minutes. Une fois prêt, l'état du projet passera à « En cours » et l'indicateur d'état sera vert.
Une fois le projet créé, vous recevrez un e-mail avec les informations de connexion pour accéder à votre portail CMS afin de créer et stocker les données de l'application.
Après vous être connecté, vous pourrez créer votre première page.
Accédez à Gestion de contenu, cliquez sur Créer une nouvelle page et remplissez toutes les données requises : types de pages, titre de la page, ULR de la page et nom de l'élément de menu.
Toutes les données sont automatiquement enregistrées lors de la saisie.
Créez 4 pages différentes pour la maison, les vêtements, l'équipement et le panier. Une fois créées, les pages devraient ressembler à la capture d'écran ci-dessous.
Ensuite, nous devons créer la structure de données que nous allons stocker. Dans OneEntry CMS, cela est réalisé en créant les attributs des données.
Accédez à Paramètres et choisissez Attributs dans le menu horizontal. Créez un ensemble d'attributs pour la page d'accueil en fournissant le nom, le marqueur et le type :
Une fois créé, il ressemblera à la capture d'écran ci-dessous :
De même, créons deux ensembles d'attributs distincts pour les vêtements et l'équipement. Une fois créé, le résultat devrait ressembler à la capture d'écran ci-dessous.
Définissons maintenant des attributs spécifiques pour chaque ensemble.
Sur la base du contenu que nous avons inclus précédemment dans le wireframe de la section Accueil, nous souhaitons afficher le titre, la description et l'image.
Cliquez sur l'élément d'engrenage pour Accueil et créez les noms d'attributs, marqueurs et types d'attributs suivants, comme indiqué dans la liste ci-dessous.
Maintenant, revenez en arrière et cliquez sur l’icône d’engrenage pour les vêtements.
Les attributs de cette page seront un peu différents puisque nous souhaitons afficher le titre, le sous-titre, la description, l'image et le prix du produit.
Voici à quoi ressemblerait la structure des attributs :
Ensuite, faites de même pour la page Gear, qui utilisera la même structure :
À ce stade du projet, nous avons déjà défini la structure du contenu et sommes prêts à commencer à créer le contenu lui-même.
Accédez à la section Gestion de contenu où vous avez précédemment créé toutes vos pages pour le site :
Cliquez sur le bouton Modifier pour Accueil. Après cela, cliquez sur l'onglet Attributs du menu Horizontal :
Sélectionnez Accueil pour l'ensemble d'attributs. Cela chargera tous les attributs que nous avons créés précédemment dans les paramètres de la page d'accueil.
Remplissez maintenant quelques exemples de données que vous souhaitez afficher sur la page d'accueil.
Maintenant, ajoutons du contenu pour nos pages Vêtements et Équipement.
Puisque nous avons sélectionné le type de page comme catalogue, sélectionnez Catalogue dans le menu de gauche et les deux pages devraient y être visibles :
Maintenant, cliquez sur l'icône Ajouter pour les vêtements et ajoutez quelques éléments.
Tout d’abord, ajoutez l’en-tête du produit que vous souhaitez ajouter.
Passez maintenant à l'onglet Attributs, sélectionnez Vêtements pour l'ensemble d'attributs et remplissez les données requises.
Revenez au menu Catalogue et à quelques éléments supplémentaires pour les vêtements et l'équipement. Pour notre application de démonstration, j'ai ajouté 4 éléments comme indiqué dans la capture d'écran ci-dessous :
Toutes les données créées dans le CMS OneEntry sont protégées, nous devrons donc créer un jeton privé pour pouvoir y accéder.
Pour ce faire, accédez à Paramètres et sélectionnez Jetons d'application. Entrez le nom de l'application et la date d'expiration, puis cliquez sur Créer. Cela générera une clé API unique.
Cliquez sur l'icône d'affichage dans la liste d'actions et vous pourrez voir la clé. Copiez-le dans le presse-papiers car nous en aurons besoin dans la prochaine section du didacticiel.
Dans cette section du didacticiel, nous allons commencer à travailler avec le code et configurer le projet NextJS pour qu'il fonctionne avec OneEntry CMS.
Ouvrez le terminal et exécutez la commande npx create-next-app@latest
.
La CLI démarrera l’assistant de configuration. Entrez le nom de votre projet et sélectionnez toutes les valeurs par défaut comme indiqué ci-dessous :
Donnez une minute à la configuration et vous recevrez une notification lorsque l'application NextJS aura été créée.
Après cela, remplacez le répertoire par le dossier nouvellement créé à l'aide de la commande cd winter-sports
, puis exécutez npm run dev
pour démarrer le serveur de développement.
Pour y accéder, cliquez sur le lien fourni sur le terminal ou ouvrez votre navigateur Web et accédez manuellement à http://localhost:3000 .
La page de destination du serveur de développement NextJS devrait vous être présentée :
Maintenant, créons une valeur environnementale dont nous aurons besoin pour notre application. Revenez à votre éditeur de code et créez un fichier .env
à la racine de votre projet.
Collez la clé API que vous avez copiée précédemment dans le presse-papiers comme suit :
API_KEY=your-api-code-from-oneentry
Cela nous permettra d'accéder à la clé via process.env.API_KEY
une fois que nous aurons effectué les appels d'API pour récupérer les données du CMS OneEntry.
Nous devons également configurer NextJS, cela nous permet donc d'inclure les médias d'un domaine externe. Nous en aurons besoin pour accéder aux images de OneEntry CMS.
Ouvrez le fichier next.config.js
à la racine du projet et modifiez-le comme suit :
const nextConfig = { images: { remotePatterns: [ { hostname: "ecommerce.oneentry.cloud", }, ], }, }; module.exports = nextConfig;
Enfin, nous devrons réinitialiser le style par défaut de Tailwind pour l'application puisque nous allons écrire tous les styles à partir de zéro.
Ouvrez le fichier globals.css
dans le répertoire app
situé dans le dossier src
et modifiez le contenu du fichier comme suit :
@tailwind base; @tailwind components; @tailwind utilities;
Puisque nous travaillerons avec TypeScript, nous devrons définir les types de données que nous utiliserons dans notre application.
Nous pourrions le faire dans les pages et les composants, mais pour garder le code plus propre et éviter les répétitions, créez un nouveau dossier interfaces
dans le répertoire app
. Créez un fichier data.tsx
dans le dossier nouvellement créé et incluez le code :
export interface Product { id: string; category: string; title: string; subtitle: string; description: string; image: string; price: number; } export interface ProductAPI { id: string; attributeValues: { en_US: { producttitle: { value: { htmlValue: string }[]; }; productsubtitle: { value: { htmlValue: string }[]; }; productdescription: { value: { htmlValue: string }[]; }; productimage: { value: { downloadLink: string }[]; }; productprice: { value: number; }; }; }; } export interface Page { pageUrl: string; title: string; description: string; image: string; localizeInfos: { en_US: { title: string; }; }; } export interface PageAPI { attributeValues: { en_US: { herotitle: { value: { htmlValue: string }[]; }; herodescription: { value: { htmlValue: string }[]; }; heroimage: { value: { downloadLink: string }[]; }; }; }; } export interface URLProps { params: { category: string; productId: string; }; } export interface TextProps { className: string; text: string; }
Les produits et les données de page auront tous deux des types pour leur structure de données de rendu frontal et la réponse de l'API via la méthode fetch.
Nous avons également défini les types de données pour les données des paramètres URL et le moteur de rendu de texte pour les données reçues des champs de saisie de texte dans le CMS.
Créons maintenant quelques fonctions que nous utiliserons pour communiquer avec OneEntry CMS afin de récupérer les données des pages et des produits.
Encore une fois, nous pourrions faire cela dans chaque fichier, mais pour garder le code plus propre, créons un nouveau dossier services
dans le répertoire app
avec un fichier fetchData.tsx
à l'intérieur :
export async function getPages() { const response = await fetch( "https://ecommerce.oneentry.cloud/api/content/pages", { method: "GET", headers: { "x-app-token": `${process.env.API_KEY}`, }, } ); return await response.json(); } export async function getProducts(category: string) { const response = await fetch( `https://ecommerce.oneentry.cloud/api/content/products/page/url/${category}?limit=4&offset=0&langCode=en_US&sortOrder=DESC&sortKey=id`, { method: "GET", headers: { "x-app-token": `${process.env.API_KEY}`, }, } ); return await response.json(); } export async function getProduct(id: string) { const response = await fetch( `https://ecommerce.oneentry.cloud/api/content/products/${id}`, { method: "GET", headers: { "x-app-token": `${process.env.API_KEY}`, }, } ); return await response.json(); }
La fonction getPages
récupérera les données sur toutes les pages que nous avons créées dans le CMS OneEntry.
La fonction getProducts
récupérera les données d'une collection spécifique de produits en fonction du paramètre category
. Nous transmettrons le paramètre lorsque nous importerons la fonction dans la page produits.
La fonction getProduct
récupérera les données en fonction de l' id
du produit que nous ouvrons. Nous transmettrons le paramètre lorsque nous importerons la fonction dans la page d'aperçu d'un produit spécifique.
Notez que nous avons utilisé process.env.API_KEY
pour accéder à la clé API que nous avons définie précédemment dans le fichier .env
afin d'authentifier l'accès au CMS OneEntry.
De plus, pendant que nous sommes toujours dans le dossier services
, créons un autre nouveau fichier appelé helpers.tsx
qui comprendra de petites fonctions utilitaires :
export function calculateTotal(items: { price: number }[]) { return items.reduce((total, item) => total + Number(item.price), 0); } export function boughtStatus(items: { id: string }[], id: string) { return items.some((item) => item.id === id); } export function cartIndex(items: { id: string }[], id: string) { return items.findIndex((item) => item.id === id); }
La fonction calculateTotal
additionnera les prix des produits ajoutés au panier et renverra la valeur totale.
Le boughtStatus
détectera si les articles individuels de l'itinéraire d'aperçu ont déjà été ajoutés au panier.
Le cartIndex
détectera la position de l'article dans le tableau pour les produits qui ont été ajoutés au panier.
Revenez au répertoire app
et créez un nouveau dossier components
à l'intérieur.
Ouvrez le dossier nouvellement créé et incluez-y sept fichiers distincts : Header.tsx
, Footer.tsx
, Text.tsx
, Card.tsx
, Preview.tsx
, Order.tsx
, AddToCart.tsx
.
Composant d'en-tête
Ouvrez le fichier Header.tsx
et incluez le code suivant :
import Link from "next/link"; import { Page } from "../interfaces/data"; export default function Header({ pages }: { pages: Page[] }) { return ( <div className="flex justify-between items-center mb-10 p-6"> <Link href="/"> <h1 className="text-xl">🏂 Alpine Sports</h1> </Link> <div className="flex space-x-4 list-none"> {pages.map((page, index: number) => ( <Link key={index} href={page.pageUrl === "home" ? "/" : `/${page.pageUrl}`} > {page.localizeInfos.en_US.title} </Link> ))} </div> </div> ); }
Pour l'en-tête, nous avons affiché le nom de l'entreprise et parcouru les liens de navigation que nous obtiendrons de l'API une fois le composant importé dans les pages.
Nous avons créé une disposition à deux colonnes et positionné horizontalement les deux éléments sur les côtés opposés de l'écran pour obtenir l'apparence de navigation typique.
Composant de pied de page
Ouvrez le fichier Footer.tsx
et incluez le code suivant :
export default function Footer() { return ( <div className="text-center mt-auto p-6"> <h1>Alpine Sports, Inc.</h1> <p>All rights reserved, {new Date().getFullYear()}</p> </div> ); }
Dans le pied de page, nous avons inclus un exemple de nom de l'entreprise et les droits de contenu pour l'année en cours. Nous avons centré le contenu et ajouté du remplissage.
Composant texte
Ouvrez le fichier Text.tsx
et incluez le code suivant :
import { TextProps } from "../interfaces/data"; export default function Text({ className, text }: TextProps) { return ( <div className={className} dangerouslySetInnerHTML={{ __html: text }} /> ); }
Le composant Texte restituera les données texte que nous recevons du CMS OneEntry et les affichera correctement dans notre application sans balises HTML.
Composant de carte
Ouvrez le fichier Card.tsx
et incluez le code suivant :
import Link from "next/link"; import Text from "../components/Text"; import { Product } from "../interfaces/data"; export default function Card({ product }: { product: Product }) { return ( <Link href={`/${product.category}/${product.id}`}> <div className="group relative"> <div className="group-hover:opacity-75 h-80"> <img src={product.image} alt="Product card image" className="h-full w-full object-cover object-center" /> </div> <div className="mt-4 flex justify-between"> <div> <h3 className="text-sm text-gray-700"> <Text className="" text={product.title} /> </h3> <Text className="mt-1 text-sm text-gray-500" text={product.subtitle} /> </div> <p className="text-sm font-medium text-gray-900">${product.price}</p> </div> </div> </Link> ); }
Dans le composant carte, nous avons affiché l'image, le titre, le sous-titre et le prix de chaque produit. Nous cartographierons tous les éléments une fois importés dans les pages.
L'image sera affichée en haut de la carte, suivie du titre et de la description, ainsi que du prix en bas à droite du composant.
Composant d'aperçu
Ouvrez le fichier Preview.tsx
et incluez le code suivant :
"use-client"; import Image from "next/image"; import Text from "./Text"; import { Product } from "../interfaces/data"; export default function Preview({ children, productItem, }: { children: React.ReactNode; productItem: Product; }) { return ( <div className="flex mx-auto max-w-screen-xl"> <div className="flex-1 flex justify-start items-center"> <Image src={productItem.image} alt="Product preview image" width="450" height="900" /> </div> <div className="flex-1"> <Text className="text-5xl pb-8" text={productItem.title} /> <Text className="text-4xl pb-8 text-gray-700" text={`$${productItem.price}`} /> <Text className="pb-8 text-gray-500 text-justify" text={productItem.description} /> {children} </div> </div> ); }
Le composant d'aperçu sera utilisé pour afficher des informations supplémentaires sur chaque produit une fois que l'utilisateur aura cliqué dessus.
Nous afficherons l'image du produit, le titre, le prix et la description. La mise en page sera divisée en 2 colonnes, l'image étant affichée dans la colonne de gauche et le reste du contenu dans la colonne de droite.
Composant de commande
Ouvrez le fichier Order.tsx
et incluez le code suivant :
"use client"; import { useState, useEffect } from "react"; import Link from "next/link"; import Image from "next/image"; import Text from "./Text"; import { calculateTotal } from "../services/helpers"; import { Product } from "../interfaces/data"; export default function Order() { const [cartItems, setCartItems] = useState<Product[]>([]); useEffect(() => { const storedCartItems = localStorage.getItem("cartItems"); const cartItems = storedCartItems ? JSON.parse(storedCartItems) : []; setCartItems(cartItems); }, []); return ( <div> {cartItems.map((item, index) => ( <div key={index} className="flex items-center border-b border-gray-300 py-2" > <div className="w-20 h-20 mr-12"> <Image src={item.image} alt={item.title} width={80} height={80} /> </div> <div> <Link href={`/${item.category}/${item.id}`} className="text-lg font-semibold" > <Text className="" text={item.title} /> </Link> <Text className="text-gray-600" text={item.subtitle} /> <p className="text-gray-800">Price: ${item.price}</p> </div> </div> ))} <div className="mt-4 text-end"> <h2 className="text-xl font-semibold mb-8"> Total Amount: ${calculateTotal(cartItems)} </h2> <button className="bg-blue-500 hover:bg-blue-700 py-2 px-8 rounded"> Proceed to checkout </button> </div> </div> ); }
Le composant de commande répertoriera tous les articles que l'utilisateur a ajoutés au panier. Pour chaque article, l'image, le titre, le sous-titre et le prix seront affichés.
Une fois le composant rendu, l'application accédera à tous les articles actuellement dans le panier, les définira sur la variable d'état cardItems
et les affichera à l'écran via la méthode map
.
Le montant total des éléments rendus sera calculé via la fonction calculateTotal
, que nous avons importée du fichier helpers.tsx
.
Composant AddToCart
Ouvrez le fichier AddToCart.tsx
et incluez le code suivant :
"use client"; import React, { useState, useEffect } from "react"; import { boughtStatus, cartIndex } from "../services/helpers"; import { Product } from "../interfaces/data"; export default function AddToCart({ category, id, title, subtitle, image, price, }: Product) { const storedCartItems = JSON.parse(localStorage.getItem("cartItems") || "[]"); const isPurchased = boughtStatus(storedCartItems, id); const indexInCart = cartIndex(storedCartItems, id); const [btnState, setBtnState] = useState(false); useEffect(() => { isPurchased && setBtnState(true); }, []); const handleButtonClick = () => { const updatedCartItems = [...storedCartItems]; if (!btnState && !isPurchased) { updatedCartItems.push({ category, id, title, subtitle, image, price }); } else if (isPurchased) { updatedCartItems.splice(indexInCart, 1); } localStorage.setItem("cartItems", JSON.stringify(updatedCartItems)); setBtnState(!btnState); }; return ( <button className={`${ !btnState ? "bg-blue-500 hover:bg-blue-600" : "bg-yellow-300 hover:bg-yellow-400" } py-2 px-8 rounded`} onClick={handleButtonClick} > {!btnState ? "Add to Cart" : "Remove from Cart"} </button> ); }
Le composant addToCart sera affiché sur la page d'aperçu du produit individuel et permettra à l'utilisateur d'ajouter le produit au panier.
Lors du rendu, la fonction isPurchased
détectera si le produit a déjà été ajouté au panier auparavant. Si ce n'est pas le bouton rendu, affichera "Ajouter au panier", sinon il dira "Supprimer du panier".
La fonction de clic de la fonction handleButtonClick
ajoutera ou supprimera le produit du tableau d'éléments en fonction de l'état ci-dessus en conséquence.
Enfin, importons les composants que nous avons créés dans la section précédente du didacticiel et créons la logique de page pour l'application.
Page d'accueil
Ouvrez page.tsx
dans le répertoire app
et modifiez-en le contenu comme suit :
import Image from "next/image"; import Header from "./components/Header"; import Text from "./components/Text"; import Footer from "./components/Footer"; import { getPages } from "./services/fetchData"; import { PageAPI } from "./interfaces/data"; export default async function Home() { const pages = await getPages(); const getValues = (el: PageAPI) => { const { herotitle, herodescription, heroimage } = el.attributeValues.en_US; return { title: herotitle.value[0].htmlValue, description: herodescription.value[0].htmlValue, image: heroimage.value[0].downloadLink, }; }; const pageContent = getValues(pages[0]); return ( <div className="flex flex-col min-h-screen"> <Header pages={pages} /> <div className="flex flex-row mx-auto max-w-screen-xl"> <div className="flex-1"> <Text className="text-6xl pb-10 text-gray-900" text={pageContent.title} /> <Text className="text-xl pb-8 text-gray-500 text-justify" text={pageContent.description} /> </div> <div className="flex-1 flex justify-end items-center"> <Image src={pageContent.image} alt="Photo by Karsten Winegeart on Unsplash" width={450} height={900} /> </div> </div> <Footer /> </div> ); }
Sur la page d'accueil, nous appellerons d'abord la fonction getPages
pour obtenir les données de l'en-tête.
Ensuite, nous utilisons la fonction getValues
pour récupérer les données de la page Hero, puis les transformons en objet pageContent
pour un traitement plus facile.
Ensuite, nous rendons les composants d'en-tête et de pied de page importés et transmettons les valeurs nécessaires pour le titre, la description et l'image du héros.
Page produits
Créez un nouveau dossier [category]
dans le répertoire app
et à l'intérieur - un fichier page.tsx
.
L'utilisation de noms de fichiers spécifiques est importante puisque c'est ce que NextJS utilise pour gérer les routes et accéder aux paramètres d'URL.
Incluez le code suivant dans le page.tsx
:
import Header from "../components/Header"; import Footer from "../components/Footer"; import Card from "../components/Card"; import { getPages, getProducts } from "../services/fetchData"; import { ProductAPI, URLProps } from "../interfaces/data"; export default async function Product({ params }: URLProps) { const { category } = params; const pages = await getPages(); const products = await getProducts(category); const getValues = (products: ProductAPI[]) => { return products.map((el) => { const { producttitle, productsubtitle, productdescription, productimage, productprice, } = el.attributeValues.en_US; return { id: el.id, category: category, title: producttitle.value[0].htmlValue, subtitle: productsubtitle.value[0].htmlValue, description: productdescription.value[0].htmlValue, image: productimage.value[0].downloadLink, price: productprice.value, }; }); }; const productItems = getValues(products.items); return ( <div className="flex flex-col min-h-screen"> <Header pages={pages} /> <div className="mx-auto max-w-screen-xl px-8"> <h2 className="text-4xl text-gray-900 mb-12"> Browse our {category} collection: </h2> <div className="grid gap-x-6 gap-y-10 grid-cols-4 mt-6"> {productItems.map((product) => { return <Card key={product.id} product={product} />; })} </div> </div> <Footer /> </div> ); }
Pour la page de produits, nous obtenons d'abord le paramètre category
de l'URL, que nous transmettons ensuite à la fonction getProducts
, pour décrire la catégorie de produits que nous devons récupérer en fonction de la page du site visitée.
Une fois les données reçues, nous créons un tableau d'objets productItems
qui comprend tous les attributs nécessaires à la page pour un traitement plus facile.
Ensuite, nous le parcourons via la méthode map
et le restituons à l'écran en passant des accessoires au composant Card que nous avons importé depuis le dossier du component
.
Page d'aperçu
Dans le dossier [category]
, créez un autre dossier appelé [productId]
.
Ouvrez le dossier nouvellement créé et créez un fichier page.tsx
à l'intérieur avec le code :
import Header from "../../components/Header"; import Preview from "../../components/Preview"; import AddToCart from "../../components/AddToCart"; import Footer from "../../components/Footer"; import { getPages, getProduct } from "../../services/fetchData"; import { ProductAPI, URLProps } from "../../interfaces/data"; export default async function Product({ params }: URLProps) { const { category, productId } = params; const pages = await getPages(); const product = await getProduct(productId); const getValues = (el: ProductAPI) => { const { producttitle, productsubtitle, productdescription, productimage, productprice, } = el.attributeValues.en_US; return { id: el.id, category: category, title: producttitle.value[0].htmlValue, subtitle: productsubtitle.value[0].htmlValue, description: productdescription.value[0].htmlValue, image: productimage.value[0].downloadLink, price: productprice.value, }; }; const productItem = getValues(product); return ( <div className="flex flex-col min-h-screen"> <Header pages={pages} /> <div className="flex mx-auto max-w-screen-xl"> <div className="flex-1 flex justify-start items-center"> <Preview productItem={productItem}> <AddToCart id={productId} category={category} title={productItem.title} subtitle={productItem.subtitle} description={productItem.description} image={productItem.image} price={productItem.price} /> </Preview> </div> </div> <Footer /> </div> ); }
Cette page permettra aux utilisateurs d'afficher plus de détails sur n'importe quel produit individuel une fois qu'ils auront cliqué sur leurs cartes sur la page des produits.
Nous récupérons d'abord le paramètre productId
de l'URL, que nous transmettons ensuite à la fonction getProduct
, pour spécifier le produit que nous devons récupérer en fonction du produit affiché sur la page d'aperçu.
Une fois les données reçues, nous créons un objet productItem
qui comprend tous les attributs nécessaires à transmettre au composant Preview en tant qu'accessoires.
Nous obtenons également le paramètre category
, car nous devons le transmettre au composant Ajouter au panier, afin que nous puissions créer un lien valide pour l'article dans la page Panier.
Page du panier
Enfin, créez un nouveau cart
de dossiers dans le répertoire app
.
Ouvrez-le, créez un nouveau fichier page.tsx
à l'intérieur avec le code suivant :
import Header from "../components/Header"; import Order from "../components/Order"; import Footer from "../components/Footer"; import { getPages } from "../services/fetchData"; export default async function Cart() { const pages = await getPages(); return ( <div className="flex flex-col min-h-screen"> <Header pages={pages} /> <div className="container mx-auto max-w-screen-xl px-8"> <h2 className="text-4xl text-gray-900 mb-12">Shopping cart summary:</h2> <Order /> </div> <Footer /> </div> ); }
Nous avons d'abord récupéré les données nécessaires, puis les avons transmises dans l'en-tête en tant qu'accessoires.
Ensuite, nous avons rendu le composant Header avec la navigation, le composant Order qui listera tous les articles que l'utilisateur a ajoutés au panier et également le composant Footer avec le nom de l'entreprise et les informations de copyright.
Félicitations, vous avez réalisé un projet fonctionnel !
Tout d’abord, vérifiez si le serveur de développement est toujours en cours d’exécution. Si ce n'est pas le cas, exécutez la commande npm run dev
pour le redémarrer et accédez à localhost:3000 pour le visualiser.
Votre projet devrait maintenant ressembler à ceci :
Comme vous pouvez le constater, le contenu de la section Accueil a été récupéré avec succès à partir de l'ensemble d'attributs Accueil que nous avons spécifié dans les champs de données.
De plus, tous les articles du catalogue OneEntry CMS ont été récupérés dans les sections Vêtements et Équipement avec toutes les informations correctement restituées.
Les utilisateurs peuvent également prévisualiser chaque produit séparément sur sa page dédiée, grâce à la gestion des itinéraires NextJS et aux paramètres du produit.
De plus, toutes les fonctions et événements fonctionnent comme prévu, et l'utilisateur peut ajouter et supprimer des articles du panier, le total étant calculé.
Dans ce didacticiel, nous avons créé un projet de commerce électronique qui permet aux utilisateurs de créer, mettre à jour et supprimer des pages de sites Web et leur contenu, ainsi que de gérer facilement des produits avec une interface de catalogue facile à utiliser, grâce au CMS OneEntry .
Le code est disponible sur GitHub , alors n'hésitez pas à le cloner et à lui ajouter plus de fonctionnalités en fonction de vos besoins. Vous pouvez y ajouter plus de sections de menu, étendre des composants individuels ou même ajouter plus de composants pour implémenter de nouvelles fonctionnalités.
J'espère que cela vous sera utile et que vous aurez un aperçu de la façon d'utiliser OneEntry CMS comme solution backend, comment l'associer au front-end de votre application et comment utiliser les meilleures fonctionnalités de NextJS, Typescript et Tailwind. .
Assurez-vous de recevoir les meilleures ressources, outils, conseils de productivité et conseils d'évolution de carrière que je découvre en vous abonnant à ma newsletter !
Connectez-vous également avec moi sur Twitter , LinkedIn et GitHub !
Également publié ici