A fully-functional e-commerce demo built with Next.js and TypeScript as part of the JavaScript Frameworks course assignment. The goal is to practice modern React patterns, data fetching, client state, and accessible UI on a realistic shop.
Pistachio lets users browse products, view rich product details, and manage a simple cart with a friendly, responsive UI. It uses the Noroff public API (no auth required) and common production patterns like state persistence, form validation, and optimized images.
- Dynamic product pages with images, tags, description, price & discount
- Search and sort for quick product discovery
- Cart with increment/decrement/remove and a playful checkout success flow
- Contact form with client-side validation and helpful toasts
- Product Listing
• Fetches products from the public API (GET /online-shop)
• Responsive grid of product cards with image, title, price (original & discounted), rating and discount badge - Product Details
• Dynamic route at/product/[id]
• Displays full product info: images, title, description, tags, reviews
• “Add to Bag” button with success toast - Search & Sort
• Real-time filtering by title
• Sort by price (asc/desc) or name (A→Z / Z→A) - Shopping Cart
• Global cart state via Zustand persisted tolocalStorage
• Increment, decrement, or remove individual items with toasts
• Clear all & checkout flow → success page + toast - Contact Form
• Client-side form with React Hook Form & TypeScript validation
• Fields: Full Name, Subject, Email, Message
• Validation toasts for success / failure - Styling & UX
• Tailwind CSS v4 for utility-first styling
• Google Fonts vianext/font– Chango for headings, Roboto Mono for body text
• Custom CSS variables for colors (#C8C9B3background,#FDFCEDcard,#696956text)
• Toast notifications withreact-hot-toast
• Next.js<Image>optimized loading (configured innext.config.js)
• Mobile ↔ desktop responsive breakpoints
- Framework: Next.js 15 + React 19
- Language: TypeScript 5
- Styling: Tailwind CSS 4
- State: Zustand (with
persist) - Forms: React Hook Form
- Notifications: react-hot-toast
- HTTP: axios
Clone the repo: git clone cd jsframeworks
Install dependencies (use the lockfile if present): npm ci # or npm install
Start the dev server: npm run dev
Build and run for production: npm run build npm start
Your app will be available at http://localhost:3000.
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "static.cloud.noroff.dev",
port: "",
pathname: "/api/online-shop/**",
},
],
},
};
export default nextConfig;
import { Chango, Roboto_Mono } from "next/font/google";
interface NextFontWithVar {
className: string;
variable: string;
}
export const chango = Chango({
subsets: ["latin"],
weight: "400",
variable: "--font-chango",
}) as NextFontWithVar;
export const robotoMono = Roboto_Mono({
subsets: ["latin"],
weight: ["400", "700"],
variable: "--font-roboto-mono",
}) as NextFontWithVar;
- All products:
GET https://v2.api.noroff.dev/online-shop - Single product:
GET https://v2.api.noroff.dev/online-shop/:id
No API key or auth needed.
Deploy easily to Vercel or Netlify:
-
Push your repo to GitHub.
-
Create a new project in Vercel or Netlify and link your repository.
-
Use the default Next.js build settings:
npm run build -
Deploy!
src/
├─ app/
│ ├─ layout.tsx # Root layout + Toaster
│ ├─ page.tsx # Home (with client wrapper)
│ ├─ cart/page.tsx # Cart page (client)
│ └─ product/[id]/page.tsx # Product details
├─ components/
│ ├─ Header.tsx
│ ├─ Footer.tsx
│ ├─ ProductCard.tsx
│ ├─ AddToCartButton.tsx
│ ├─ SearchBar.tsx
│ └─ SortDropdown.tsx
├─ lib/
│ ├─ productApi.ts
│ ├─ cartStore.ts
│ └─ fonts.ts
└─ styles/
└─ globals.css
- Next.js 15
- React 19
- TypeScript 5
- Tailwind CSS 4
- Zustand (persist)
- React Hook Form
- react-hot-toast
- axios
This is a small educational project. If you want to contribute:
- Open an issue describing the change.
- Create a feature branch from
main. - Keep commits focused and include clear messages.
- Open a pull request for review.
Thank you for keeping the code clean and accessible 💚
- Portfolio: https://idatoldportfolio.netlify.app/
- LinkedIn: https://www.linkedin.com/in/ida-charlotte-loriann-toldn%C3%A6s-920190117/
- Email: idatoldnaes@icloud.com
This repository is for educational purposes. If you plan to reuse parts of the code, please credit the author.
Add a LICENSE file (e.g., MIT) if you intend to open-source it.
- Noroff API team for the public
online-shopendpoints - Next.js & Vercel for excellent tooling and docs
- React Hook Form, Zustand, and Tailwind communities for great DX
- Classmates and instructors for feedback and inspiration
