A full-featured e-commerce storefront for authentic Bangladeshi natural products — built with React 18, Vite, Tailwind CSS 4, and Supabase.

GhorerBazar is an independent redesign of a Bangladeshi natural-products storefront — honey, dates, ghee, and more. The goal was to take a real-world e-commerce site and rebuild it with a modern React stack end to end: a fully relational Supabase backend, district-aware delivery logic, a live admin panel, and a checkout flow that handles both Cash on Delivery and mobile payment (bKash/Nagad). Everything is configurable from the admin without a redeploy.
Overview
The project covers the full commerce surface: browsing a catalog with filters and pagination, viewing product details with an image gallery, managing a persistent cart, completing checkout with real delivery-fee logic, and tracking orders from a user profile. On the other side, an isolated admin session provides a dashboard, order management, product CRUD, hero-banner controls, and a key-value settings store that drives live site content.
Authentication handles three entry paths — email/password, OTP magic link, and phone number resolved to email — all backed by Supabase Auth.
This is an independent redesign built for learning and portfolio purposes. It is not affiliated with the original GhorerBazar business. Product images and brand assets remain the intellectual property of their respective owners and are not deployed publicly.
Features
| Feature | Details |
|---|---|
| Product catalog | Browse by category, brand, or flag (Best Selling, New Arrival) with pagination and sidebar filters (category, brand, price range) |
| Product detail | Image gallery, tabbed description, related products |
| Cart | Persistent via localStorage, quantity controls, real-time subtotal, free-delivery threshold progress bar |
| Wishlist | Synced to Supabase for logged-in users; localStorage fallback for guests |
| Checkout | District-aware delivery fee (Dhaka ৳80 / Outside ৳120), Cash on Delivery, bKash/Nagad with transaction-ID verification |
| Authentication | Email/password, OTP magic link, and phone-number-to-email resolution |
| User profile | Edit name, phone, address; full order history |
| Contact form | Submissions stored in Supabase contact_messages table |
| Admin panel | Isolated auth session; dashboard, orders, product CRUD, hero banners, site settings |
| Live site settings | Announcement bar, payment numbers, delivery contact, discount thresholds — all configurable from admin without a redeploy |
Tech Stack
| Tool | Role |
|---|---|
| React 18 | UI layer |
| Vite | Build tooling and dev server |
| Tailwind CSS 4 | Utility-first styling |
| React Router v7 | Client-side routing |
| Supabase | PostgreSQL, Auth, Storage, RPCs |
| HeadlessUI | Accessible UI primitives |
| Swiper | Image gallery and banner carousel |
| Sonner | Toast notifications |
Architecture Highlights
Supabase Client Isolation
Three separate Supabase clients prevent session bleed between the user and admin surfaces:
| Client | Key | Purpose |
|---|---|---|
supabase | Anon | User-facing auth and data |
supabaseAdminAuth | Anon + custom storageKey | Admin auth session (isolated) |
supabaseAdmin | Service role | Admin DB writes that bypass RLS |
Live Site Settings
All operator-facing configuration lives in a site_settings key-value table. The SettingsContext fetches this once on mount and makes it available app-wide. Changing the announcement bar text, payment numbers, or discount threshold in the admin panel takes effect immediately for all visitors — no environment variable update, no redeploy.
District-Aware Delivery
Delivery fee is resolved at checkout by matching the customer's selected district against a lookup table of all Bangladeshi districts and thanas. Dhaka-district orders get ৳80; everything else gets ৳120. The constants live in src/config/constants.js so they are easy to update.
Shopping Flow
Browse the catalog
Products load server-side from Supabase with optional filters applied as query parameters. The sidebar lets users narrow by category, brand, and price range simultaneously. Pagination keeps payloads small.
View product detail
The detail page renders an image gallery (Swiper), a tabbed description panel, and a related-products strip. Stock state drives the add-to-cart button.
Manage the cart
Cart state lives in React Context and is serialised to localStorage so it survives page refreshes. The cart drawer shows per-item quantities, line totals, a subtotal, and a progress bar toward the free-delivery threshold.
Authenticate (if needed)
Guest users can check out without an account. Logged-in users get their wishlist synced and their orders tracked under their profile. Login options: email/password, OTP magic link, or phone number resolved to email via a Supabase RPC.
Complete checkout
The checkout form collects delivery address with district/thana dropdowns, resolves the delivery fee, and presents payment options (Cash on Delivery or bKash/Nagad with transaction-ID entry). The order is written to Supabase orders and the cart is cleared on success.
Database Schema
The full schema (tables, RLS policies, indexes, RPCs, and seed data) is in database/full-reset.sql — a single file that rebuilds everything from scratch in the Supabase SQL Editor.
| Table | Purpose |
|---|---|
products | Product catalog |
categories | Categories with images |
brands | Brand list |
profiles | User profile data |
orders | Guest and authenticated orders |
wishlists | Per-user wishlisted product slugs |
site_settings | Key-value store for admin-configurable values |
contact_messages | Contact form submissions |