Это партнерская статья, спонсируемая OneEntry CMS .
Создание приложения электронной коммерции часто является сложной задачей. При таком большом количестве доступных альтернатив нелегко выбрать технологический стек, который соответствует требованиям проекта, потребностям в масштабируемости и долгосрочной устойчивости.
Еще одним важным моментом является то, что проекты электронной коммерции имеют дело с большим количеством данных и операций CRUD. Создание надежной, масштабируемой и безопасной серверной системы может занять много времени даже у самых опытных разработчиков.
Я выбрал технологический стек, основанный на NextJS, TypeScript, Tailwind CSS и OneEntry CMS. Мы сами создадим практический проект электронной коммерции, чтобы увидеть, как он работает вместе и как его можно использовать для упрощения управления контентом.
Код этого проекта будет доступен в репозитории GitHub .
NextJS — это платформа React для создания быстрых и эффективных веб-приложений, которая включает в себя такие функции, как рендеринг клиента и сервера, выборку данных, обработчики маршрутов, промежуточное программное обеспечение, встроенные оптимизации и многое другое.
TypeScript добавляет статическую типизацию в JavaScript, что упрощает выявление и исправление ошибок в масштабируемых проектах, таких как электронная коммерция. Он также повышает производительность благодаря таким функциям, как автодополнение и помощь в рефакторинге.
Tailwind CSS ускоряет стилизацию веб-приложений, позволяя разработчикам стилизовать элементы внутри разметки без необходимости переключаться между внешними файлами CSS и придумывать имена классов для каждого.
OneEntry CMS — это автономная система управления контентом с простым в использовании интерфейсом, легко масштабируемым серверным интерфейсом, быстрым API и понятной документацией, позволяющая повысить вашу производительность при создании контента веб-сайта и управлении им.
На целевой странице будет отображаться заголовок, перечислены функции магазина и включено главное изображение.
Первый раздел магазина будет посвящен одежде.
Второй раздел магазина будет включать в себя Gear.
Каждый из элементов будет иметь отдельную страницу предварительного просмотра с подробной информацией.
Товары, уже находящиеся в корзине, будут иметь возможность удалить их.
В корзине будут перечислены все выбранные товары и подсчитана общая сумма.
Сначала пользователю необходимо будет зарегистрировать новую учетную запись. Для этого перейдите на домашнюю страницу OneEntry и зарегистрируйтесь через свою учетную запись электронной почты.
После этого войдите в систему , и вы будете перенаправлены на панель управления OneEntry.
Начните с создания нового проекта.
Вы получите бесплатный код для использования плана обучения в течение месяца. У вас будет возможность активировать его в процессе создания проекта.
Создание проекта займет несколько минут. Как только он будет готов, статус проекта изменится на «Работает», а индикатор статуса станет зеленым.
После создания проекта вы получите электронное письмо с данными для входа в систему для доступа к порталу CMS для создания и хранения данных для приложения.
После входа в систему вы сможете создать свою первую страницу.
Перейдите в «Управление контентом», нажмите «Создать новую страницу» и заполните все необходимые данные — типы страниц, заголовок страницы, ULR страницы и название пункта меню.
Все данные автоматически сохраняются при входе.
Создайте 4 разные страницы: «Дом», «Одежда», «Снаряжение» и «Корзина». После создания страницы должны выглядеть так, как показано на скриншоте ниже.
Далее нам нужно создать структуру данных, которую мы будем хранить. В OneEntry CMS это достигается путем создания атрибутов данных.
Перейдите в «Настройки» и выберите «Атрибуты» в горизонтальном меню. Создайте набор атрибутов для домашней страницы, указав имя, маркер и тип:
После создания он будет выглядеть так, как показано на скриншоте ниже:
Аналогичным образом давайте создадим два отдельных набора атрибутов для одежды и снаряжения. После создания результат должен выглядеть так, как показано на скриншоте ниже.
Теперь давайте определим конкретные атрибуты для каждого набора.
Основываясь на содержимом, которое мы ранее включили в каркас раздела «Главная», мы хотим отобразить заголовок, описание и изображение.
Нажмите на элемент шестеренки для дома и создайте следующие имена атрибутов, маркеры и типы атрибутов, как показано в списке ниже.
Теперь вернитесь и нажмите на значок шестеренки для одежды.
Атрибуты этой страницы будут немного другими, поскольку мы хотим отображать название продукта, подзаголовок, описание, изображение и цену.
Вот как будет выглядеть структура атрибутов:
Затем сделайте то же самое для страницы Gear, которая будет использовать ту же структуру:
На этом этапе проекта мы уже определили структуру контента и готовы приступить к созданию самого контента.
Перейдите в раздел «Управление контентом», где вы ранее создали все свои страницы сайта:
Нажмите кнопку редактирования для дома. После этого нажмите на вкладку Атрибуты в Горизонтальном меню:
Выберите «Домой» для набора атрибутов. Это загрузит все атрибуты, которые мы создали ранее в настройках домашней страницы.
Теперь заполните несколько примеров данных, которые вы хотите отобразить на главной странице.
Теперь давайте добавим немного контента для наших страниц «Одежда» и «Снаряжение».
Поскольку мы выбрали тип страницы «Каталог», выберите «Каталог» в левом меню, и там должны быть видны обе страницы:
Теперь нажмите значок «Добавить» для одежды и добавьте несколько предметов.
Сначала добавьте заголовок продукта, который вы хотите добавить.
Теперь перейдите на вкладку «Атрибуты», выберите «Одежда» для набора атрибутов и заполните необходимые данные.
Вернитесь в меню «Каталог» и еще несколько предметов для одежды и снаряжения. Для нашего демо-приложения я добавил 4 элемента, как показано на скриншоте ниже:
Все данные, созданные в OneEntry CMS, защищены, поэтому нам придется создать частный токен, чтобы иметь к ним доступ.
Для этого перейдите в «Настройки» и выберите «Токены приложений». Введите название приложения и дату окончания срока действия и нажмите «Создать». Это создаст уникальный ключ API.
Нажмите значок просмотра в списке действий, и вы сможете увидеть ключ. Скопируйте его в буфер обмена, так как он понадобится нам в следующем разделе урока.
В этом разделе руководства мы начнем работать с кодом и настроим проект NextJS для работы с OneEntry CMS.
Откройте терминал и выполните команду npx create-next-app@latest
.
CLI запустит мастер установки. Введите имя вашего проекта и выберите все значения по умолчанию, как показано ниже:
Дайте настройке минуту, чтобы завершить, и вы получите уведомление, когда приложение NextJS будет создано.
После этого измените каталог на вновь созданную папку с помощью команды cd winter-sports
, а затем запустите npm run dev
чтобы запустить сервер разработчика.
Чтобы получить к нему доступ, щелкните ссылку, представленную на терминале, или откройте веб-браузер и вручную перейдите по адресу http://localhost:3000 .
Вам должна быть представлена целевая страница сервера разработчика NextJS:
Теперь давайте создадим экологическую ценность, которая понадобится нашему приложению. Вернитесь в редактор кода и создайте файл .env
в корне вашего проекта.
Вставьте ключ API, который вы скопировали в буфер обмена ранее, следующим образом:
API_KEY=your-api-code-from-oneentry
Это позволит нам получить доступ к ключу process.env.API_KEY
после того, как мы выполним вызовы API для получения данных из OneEntry CMS.
Нам также необходимо настроить NextJS, чтобы он позволял нам включать медиафайлы из внешнего домена. Это понадобится нам для доступа к изображениям из OneEntry CMS.
Откройте файл next.config.js
в корне проекта и отредактируйте его следующим образом:
const nextConfig = { images: { remotePatterns: [ { hostname: "ecommerce.oneentry.cloud", }, ], }, }; module.exports = nextConfig;
Наконец, нам нужно будет сбросить стиль Tailwind по умолчанию для приложения, поскольку мы будем писать все стили с нуля.
Откройте файл globals.css
в каталоге app
, расположенном в папке src
, и измените содержимое файла на следующее:
@tailwind base; @tailwind components; @tailwind utilities;
Поскольку мы будем работать с TypeScript, нам нужно будет определить, какие типы данных мы будем использовать в нашем приложении.
Мы могли бы сделать это внутри страниц и компонентов, но чтобы сохранить чистоту кода и избежать повторения, создайте новую папку interfaces
в каталоге app
. Создайте файл data.tsx
внутри вновь созданной папки и включите в него код:
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; }
Данные продуктов и страниц будут иметь типы для структуры данных внешнего рендеринга и ответа от API через метод выборки.
Также мы определили типы данных для данных из параметров URL и средства рендеринга текста для данных, полученных из полей ввода текста в CMS.
Теперь давайте создадим несколько функций, которые мы будем использовать для взаимодействия с OneEntry CMS для получения данных для страниц и продуктов.
Опять же, мы могли бы сделать это в каждом файле, но чтобы код был чище, давайте создадим новую папку services
в каталоге app
с файлом fetchData.tsx
внутри нее:
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(); }
Функция getPages
получит данные обо всех страницах, которые мы создали в OneEntry CMS.
Функция getProducts
извлекает данные для определенной коллекции продуктов на основе параметра category
. Мы передадим параметр при импорте функции на страницу продуктов.
Функция getProduct
будет получать данные на основе id
продукта, который мы открываем. Мы передадим параметр при импорте функции на страницу предварительного просмотра для любого конкретного продукта.
Обратите внимание, что мы использовали process.env.API_KEY
для доступа к ключу API, который мы определили в файле .env
ранее, для аутентификации доступа к OneEntry CMS.
Кроме того, пока мы все еще находимся в папке services
, давайте создадим внутри нее еще один новый файл под названием helpers.tsx
, который будет включать небольшие служебные функции:
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); }
Функция calculateTotal
суммирует цены на товары, добавленные в корзину, и возвращает общее значение.
boughtStatus
определит, были ли уже добавлены в корзину отдельные товары из маршрута предварительного просмотра.
cartIndex
определит положение элемента в массиве для продуктов, которые были добавлены в корзину.
Вернитесь в каталог app
и создайте внутри него новую папку components
.
Откройте вновь созданную папку и включите в нее семь отдельных файлов: Header.tsx
, Footer.tsx
, Text.tsx
, Card.tsx
, Preview.tsx
, Order.tsx
, AddToCart.tsx
.
Компонент заголовка
Откройте файл Header.tsx
и включите следующий код:
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> ); }
В заголовке мы отобразили название компании и пропустили навигационные ссылки, которые получим от API после импорта компонента на страницы.
Мы создали макет из двух столбцов и расположили оба элемента на противоположных сторонах экрана по горизонтали, чтобы добиться типичного вида навигации.
Компонент нижнего колонтитула
Откройте файл Footer.tsx
и включите следующий код:
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> ); }
В нижнем колонтитуле мы включили образец названия компании и права на контент текущего года. Мы центрировали содержимое и добавили отступы.
Текстовый компонент
Откройте файл Text.tsx
и включите следующий код:
import { TextProps } from "../interfaces/data"; export default function Text({ className, text }: TextProps) { return ( <div className={className} dangerouslySetInnerHTML={{ __html: text }} /> ); }
Компонент «Текст» будет отображать текстовые данные, которые мы получаем от OneEntry CMS, и правильно отображать их в нашем приложении без HTML-тегов.
Компонент карты
Откройте файл Card.tsx
и включите следующий код:
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> ); }
В компоненте карточки мы отображали изображение, заголовок, подзаголовок и цену для каждого продукта. Мы сопоставим все элементы после их импорта на страницы.
Изображение будет отображаться в верхней части карточки, за ним следуют название и описание, а цена — в правом нижнем углу компонента.
Компонент предварительного просмотра
Откройте файл Preview.tsx
и включите следующий код:
"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> ); }
Компонент предварительного просмотра будет использоваться для отображения дополнительной информации о каждом продукте после того, как пользователь нажмет на него.
Мы отобразим изображение продукта, название, цену и описание. Макет будет разделен на 2 столбца: в левом столбце будет отображаться изображение, а в правом — остальной контент.
Компонент заказа
Откройте файл Order.tsx
и включите следующий код:
"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> ); }
В компоненте заказа будут перечислены все товары, которые пользователь добавил в корзину. Для каждого товара будут отображаться изображение, заголовок, подзаголовок и цена.
Как только компонент будет отображен, приложение получит доступ ко всем элементам, которые сейчас находятся в корзине, установит для них переменную состояния cardItems
и отобразит их на экране с помощью метода map
.
Общее количество отображаемых элементов будет рассчитано с помощью функции calculateTotal
, которую мы импортировали из файла helpers.tsx
.
Компонент AddToCart
Откройте файл AddToCart.tsx
и включите следующий код:
"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> ); }
Компонент addToCart будет отображаться на странице предварительного просмотра отдельного продукта и позволит пользователю добавить продукт в корзину.
При рендеринге функция isPurchased
определит, был ли продукт уже добавлен в корзину ранее. Если это не отображаемая кнопка, отобразится «Добавить в корзину», в противном случае — «Удалить из корзины».
Функция щелчка функции handleButtonClick
добавит или удалит продукт из массива элементов в зависимости от вышеуказанного состояния соответственно.
Наконец, давайте импортируем компоненты, которые мы создали в предыдущем разделе руководства, и создадим логику страницы для приложения.
Домашняя страница
Откройте page.tsx
в каталоге app
и отредактируйте его содержимое следующим образом:
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> ); }
На домашней странице мы сначала вызовем функцию getPages
, чтобы получить данные для заголовка.
Затем мы используем функцию getValues
для получения данных страницы Hero, а затем превращаем их в объект pageContent
для упрощения обработки.
Затем мы визуализируем импортированные компоненты верхнего и нижнего колонтитула, а также передаем необходимые значения для заголовка, описания и изображения героя.
Страница продуктов
Создайте новую папку [category]
в каталоге app
и внутри нее — файл page.tsx
.
Использование определенных имен файлов важно, поскольку именно это NextJS использует для обработки маршрутов и доступа к параметрам URL.
Включите следующий код в 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> ); }
Для страницы продуктов мы сначала получаем параметр category
из URL-адреса, который далее передаем в функцию getProducts
, чтобы описать, какую категорию продуктов нам нужно получить в зависимости от того, какая страница сайта посещается.
После получения данных мы создаем массив объектов productItems
, состоящий из всех необходимых атрибутов страницы для упрощения обработки.
Затем мы просматриваем его с помощью метода map
и отображаем на экране, передавая реквизиты компоненту Card, который мы импортировали из папки component
.
Страница предварительного просмотра
Внутри папки [category]
создайте еще одну папку с именем [productId]
.
Откройте вновь созданную папку и создайте внутри нее файл page.tsx
с кодом:
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> ); }
Эта страница позволит пользователям просмотреть более подробную информацию о любом отдельном продукте, как только они нажмут на свои карточки на странице продуктов.
Сначала мы получаем параметр productId
из URL-адреса, который далее передаем в функцию getProduct
, чтобы указать, какой продукт нам нужно получить, в зависимости от того, какой продукт просматривается на странице предварительного просмотра.
После получения данных мы создаем объект productItem
, который состоит из всех необходимых атрибутов, которые будут переданы в компонент Preview в качестве реквизита.
Мы также получаем параметр category
, поскольку нам нужно передать его компоненту «Добавить в корзину», чтобы мы могли создать действительную ссылку для товара на странице корзины.
Страница корзины
Наконец, создайте новую cart
папок в каталоге app
.
Откройте его, создайте внутри него новый файл page.tsx
со следующим кодом:
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> ); }
Сначала мы получили необходимые данные, а затем передали их в заголовок в качестве реквизита.
Затем мы визуализировали компонент «Заголовок» с навигацией, компонент «Заказ», в котором будут перечислены все элементы, которые пользователь добавил в корзину, а также компонент «Нижний колонтитул» с названием компании и информацией об авторских правах.
Поздравляем, вы сделали рабочий проект!
Сначала проверьте, работает ли сервер разработчика. Если это не так, запустите команду npm run dev
, чтобы запустить ее снова, и получите доступ к localhost:3000, чтобы просмотреть ее.
Теперь ваш проект должен выглядеть так:
Как видите, содержимое раздела «Главная» было успешно получено из набора атрибутов «Главная», который мы указали в полях данных.
Кроме того, все товары из каталога OneEntry CMS были загружены в разделы «Одежда» и «Снаряжение», и вся информация отобразилась правильно.
Пользователи также могут просмотреть каждый продукт отдельно на отдельной странице благодаря обработке маршрутов NextJS и параметрам продукта.
Кроме того, все функции и события работают должным образом, и пользователь может добавлять и удалять товары из корзины с подсчетом общей суммы.
В этом руководстве мы создали проект электронной коммерции, который позволяет пользователям создавать, обновлять и удалять страницы веб-сайта и их контент, а также легко управлять продуктами с помощью простого в использовании интерфейса каталога благодаря OneEntry CMS .
Код доступен на GitHub , поэтому смело клонируйте его и добавляйте к нему больше функций в соответствии с вашими потребностями. Вы можете добавить к нему больше разделов меню, расширить отдельные компоненты или даже добавить больше компонентов для реализации новых функций.
Надеюсь, это будет полезно для вас, и вы получите представление о том, как использовать OneEntry CMS в качестве серверного решения, как связать его с интерфейсом вашего приложения и как использовать лучшие функции NextJS, Typescript и Tailwind. .
Подписавшись на мою рассылку, обязательно получайте лучшие ресурсы, инструменты, советы по продуктивности и карьерному росту!
Также свяжитесь со мной в Twitter , LinkedIn и GitHub !
Также опубликовано здесь