Skip to the article
Aniq-UI

E-CommerceThe storefront

The storefront

What the shop does for customers: its pages, cart and wishlist, checkout, accounts, order tracking, the fitting room, analytics tags and search engines.

For the Full Stack package

Pages

Every page exists in English under /en and in Arabic under /ar. A path without a language goes to /en.

PathWhat it shows
/enThe home page: hero, categories, new drops, an offer banner, best sellers and editorial sections.
/en/shopEvery product, with search, category, price and highlight filters, sorting and pages. The filters live in the address, so every view can be shared.
/en/categoriesThe categories, with search and sorting.
/en/products/<slug>A product: gallery, variants, price, rating, reviews, related products, and the wishlist and fitting room buttons.
/en/cartThe cart and its summary.
/en/checkoutShipping details and payment on one page, beside the order summary. Open to guests.
/en/order-confirmation/<number>The order number to keep for tracking, with links to keep shopping and to track the order.
/en/track-orderOrder tracking by order number and email, with no account.
/en/about, /en/contact, /en/faqSupport pages.
/en/auth/login, /en/auth/register, /en/auth/forgot-password, /en/auth/reset-passwordSign-in and account creation. A signed-in customer is sent away from them.
/en/accountThe signed-in area: an overview, orders and their detail, addresses, profile, order tracking and the wishlist. A visitor who is not signed in is sent to the sign-in page.

/en/wishlist redirects to /en/account/wishlist.

Wire these before going live

The contact form and the footer's newsletter form confirm to the shopper but send nothing until you connect them, and the template has no terms or privacy pages, although the registration form asks shoppers to accept them. Connect both forms to your own mail or helpdesk and add those pages before you sell.

Cart and wishlist

  • The cart and the wishlist are kept in the shopper's browser, for guests and signed-in customers alike, so they survive a reload and a return visit on the same device.
  • Anyone can add to the wishlist from a product card or page. The wishlist page itself is in the account area, so viewing it needs sign-in.
  • The cart shows the subtotal, the shipping (free from $75, otherwise $9.99) and the total. The API prices every order again from its own catalogue when it is placed, with the same shipping rule, and the cart never follows a shopper to another device.

Checkout

One page: first and last name, email, an optional phone number, address, city, postcode and country, then the payment method. Guests check out with their email.

  • Cash on delivery is selected by default and confirms the order straight away.
  • Card runs on Stripe, inside the page. It needs the publishable key in the storefront and the secret key and webhook in the API.
  • The summary shows the shipping the API charges, free from $75 and otherwise $9.99, with no tax.
  • There is no promo code field.
  • NEXT_PUBLIC_DEMO_CHECKOUT=true prefills a generated buyer and adds a button beside the shipping heading that draws a new one. Keep it false for a real shop.

Customer accounts

  • Registration asks for a first and last name, an email and a password of at least 8 characters, and the terms checkbox.
  • Sign-in works from its page and from a sign-in window that opens anywhere in the shop. Customers and staff are separate accounts: a customer cannot sign in to the admin dashboard.
  • Profile has two tabs: the customer's details and a password change.
  • Addresses can be added, edited, deleted and one set as the default.
  • Orders lists the customer's orders, each with its status, tracking number, items, totals and addresses.

Email needs your mailer

The template sends no email: no order confirmation, no shipping notice and no password reset message. Outside production the API writes the reset token to its log, and the reset page opens at /en/auth/reset-password?token= followed by that token. With NODE_ENV=production the token goes nowhere until you connect a mail provider in forgotPassword, in back-end/src/modules/customer-auth/customer-auth.controller.ts.

Reviews

  • Each product page shows its reviews and a rating summary. A review from a customer who bought the product carries a "Verified Purchase" badge.
  • Shoppers cannot write a review: neither the storefront nor the admin dashboard has a form for it, so the seeded reviews are what the shop shows.
  • The API accepts reviews from signed-in customers at POST /api/reviews, one per customer per product: posting again updates the first.

Order tracking

/en/track-order asks for the order number and the email the order was placed with, so a guessed number reveals nothing. A link with ?order= fills the number in. Signed-in customers track from their account with the order number alone.

The lookup allows 10 tries a minute from one address.

The fitting room

When the API has the fitting room switched on, shoppers can see a product worn before they buy it. Without it, none of this appears.

  • A "Try it on" hanger on each product card, a button in the product gallery, and a fitting room panel docked on every page.
  • The look is drawn on a model, or on the shopper's own full-body photo (JPG, PNG or WebP, up to 12 MB) with "Use my photo".
  • On the sample store it shows the product's own photo, with a note that the look was not drawn.

Analytics and tracking pixels

Six networks are built in. Paste an id into storefront/.env (with Docker Compose, the .env next to docker-compose.yml) and rebuild. An id left blank loads no script at all.

VariableNetwork
NEXT_PUBLIC_GTM_IDGoogle Tag Manager
NEXT_PUBLIC_GA4_MEASUREMENT_IDGoogle Analytics 4
NEXT_PUBLIC_META_PIXEL_IDFacebook and Instagram
NEXT_PUBLIC_TIKTOK_PIXEL_IDTikTok
NEXT_PUBLIC_SNAPCHAT_PIXEL_IDSnapchat
NEXT_PUBLIC_PINTEREST_TAG_IDPinterest

NEXT_PUBLIC_ANALYTICS_CURRENCY (USD by default) is sent with every value, and NEXT_PUBLIC_ANALYTICS_DEBUG=true logs every event to the browser console. If you set only one id, set Tag Manager: it can load the others from its own interface. If GA4 runs inside your Tag Manager container, leave NEXT_PUBLIC_GA4_MEASUREMENT_ID blank, or every session is counted twice.

EventRaised when
page_viewEvery navigation, the first one included
view_itemA product page finishes loading
add_to_cartAdd to cart, Buy now, or a quantity increase in the cart
remove_from_cartA line is deleted, or its quantity decreased
add_to_wishlistA product is added to the wishlist
view_cartThe cart page opens with something in it
begin_checkoutThe checkout page opens
purchaseThe order is created and the payment cleared
searchA search term settles in the search panel
sign_upAn account is created
loginA shopper signs in

Consent

The tags load as soon as the page does. If you sell into the EU or the UK, put a consent banner in front of them before going live: the tags are mounted by <AnalyticsScripts /> in src/app/layout.tsx.

Search engines and sharing

  • Every public page has its own title and description, from messages/seo/, with a canonical link and English, Arabic and default language alternates.
  • /robots.txt keeps the account, sign-in, cart, checkout and order confirmation pages out of search engines, and points to the sitemap.
  • /sitemap.xml lists the public pages in both languages, plus every product when the server can reach the API.
  • Every page carries the shop's organisation and website details for search engines, including the site search.
  • All of these are built from NEXT_PUBLIC_SITE_URL: set it to your real address before going live, and rebuild.

The sample store

Without NEXT_PUBLIC_API_BASE_URL, the storefront runs on a sample store in the browser and shows a "Sample data" notice that a visitor can dismiss until the next page load.

  • Any email and password sign you in as the sample shopper. Browsing, filtering, the cart, the wishlist, addresses and order history all work, and changes are kept in the browser.
  • Checkout charges shipping as the API does and completes without calling Stripe.
  • Once your API is connected, yarn remove:mock deletes the sample store and its notice. It keeps public/mock-media/, which a backend seeded without a bucket still points at.
Terminalin storefront
yarn remove:mock

Where to change things

WhatWhere, in storefront/
Name, logo, contact details, social links, sharing imagessrc/config/brand.config.ts
Colourssrc/styles/theme-variables.css
Every visible wordmessages/<namespace>/en.json and ar.json
Page titles for search resultsmessages/seo/
A page's layoutsrc/app/[locale]/ for the route, src/features/ for its parts
Marketing tagssrc/config/analytics.config.ts, switched on from .env

How the storefront's code fits together

Included with your purchase. Sign in to read, or open it in your download.

The code's structure and conventions, and how to add a tracking network.

What the API does for the shop

The storefront's catalogue, accounts, addresses, orders, tracking, reviews and fitting room are served by the API's public and customer routes.

Stuck on a step?

Find a fix before you start over.

Troubleshooting

Cookie Preferences

We use cookies to enhance your browsing experience, analyze site traffic, and personalize content. By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising.