React 18
Functional components + Context for state. No prop drilling, no Redux overhead for a project this size.
E-Commerce + Booking · React Rebuild
A complete React rebuild of a 5-page college site into a production e-commerce + event booking platform for a mini pancake business in Mazatlán — with WhatsApp checkout, a 5-step booking wizard, and a 3-tab admin dashboard.
Mini Pancake Co. is a small mini pancake business in Mazatlán, Mexico. v1 was a 5-page vanilla HTML/Bootstrap college site — pretty, static, useless for the actual business. v2 is a full React single-page application: product catalog with cart, WhatsApp-integrated checkout, a 5-step event booking wizard for parties, and an admin dashboard. Two real revenue streams (retail orders + party packages) running off one codebase.
The problem
The college version had no commerce, no booking, no admin — just five static pages. The owner was managing every order over WhatsApp manually, with no way to show packages, take party reservations, or track what had been confirmed. The site looked nice and did nothing.
The goal
Ship two products from one codebase: a working e-commerce shop with cart and WhatsApp checkout, and a 5-step event booking wizard for party packages — both with a private admin dashboard so the owner can actually run the business from the site.
A 5-page static HTML site with no commerce, no booking, no admin. Adding a product meant editing HTML directly. Every order happened over WhatsApp manually because the site couldn't capture them.
Layer Bootstrap modals onto the static site for cart UX
Postpones the rebuild, doesn't solve persistence or admin. Buys weeks, costs months.
Use a SaaS like Shopify with a custom theme
Solves commerce instantly but locks the owner into monthly fees and removes the WhatsApp workflow entirely.
Rebuild as a React SPA with Context + localStorage, deploy via GitHub PagesChosen
Most code to write upfront, but full control over both flows, no recurring cost, and the data layer stays swappable for a real API later.
React 18 + Vite + Tailwind + Framer Motion, HashRouter for GitHub Pages compatibility, Context for cart and bookings, localStorage as the persistence layer. The architecture decision is to keep the data layer abstracted — a single context module — so swapping to a real backend later is a one-file change, not a rewrite.
Built a clean React product grid, search, sort, detail modal with topping picker, and cart. Wired it up to a generic checkout form. The owner pushed back: customers don't use forms here, they WhatsApp. The cart was a dead end.
Stripe Checkout — proper card payments
Adds a payment processor fee, requires KYC, breaks the WhatsApp habit customers already trust. Solves a problem nobody had.
Email order to the owner via EmailJS
Owner doesn't check email in the workflow loop — orders would land in a channel she's not in. Same dead-end as the form.
WhatsApp deep link with a pre-filled order message (items, toppings, quantities, total)Chosen
No card payments captured digitally — but matches the existing trusted channel exactly. The cart becomes an order builder, not a payment form.
Replaced the form with a single CTA that opens WhatsApp with a pre-formatted message. One tap, customer lands in the chat they already trust, owner's workflow is preserved, and the cart logic still produces a clean structured order. The site becomes a storefront and an order builder — the channel stays where it already worked.
The shop covered retail. Party bookings — the higher-revenue flow — still went through DMs with no structure. The owner had no view of pending vs confirmed bookings. The site was half a product.
Push bookings into a Notion database via API
Owner now has to learn Notion. Adds a third tool to the stack. Free, but introduces friction in the daily workflow.
Auto-generate a Google Sheet from each submission
Solves capture but not management — owner can see bookings, can't actually confirm/cancel/track from the spreadsheet without manual edits.
Build a password-gated admin dashboard inside the same React app, persisting to localStorageChosen
Bookings live in the device that opened the dashboard — but for a single-owner business, that's the right tradeoff. Full CRUD, no extra tools, same brand.
Built the 5-step booking wizard (Package → Date+Time with 7-day-min → Event details → Contact → Review) and the admin at /#/admin: stat tiles for total/pending/confirmed/revenue, full bookings table with confirm/cancel/delete, and packages overview. Same component library as the public site — every admin screen still feels on-brand.
Each tool earned its place. Here's why.
React 18
Functional components + Context for state. No prop drilling, no Redux overhead for a project this size.
Vite 5
Sub-second HMR. The animation work especially benefits from instant feedback during iteration.
Tailwind 3
Tokens defined once in config, consumed everywhere. Brand orange + peach + rose stayed consistent across shop, booking, and admin without a CSS file.
Framer Motion 11
Page transitions, modal entrances, scroll reveals via useInView. The motion system is what differentiates from a generic shop template.
React Router 6 (HashRouter)
GitHub Pages can't handle BrowserRouter without server-side rewrites. HashRouter ships with zero infra config.
date-fns 3
Calendar logic for the 7-day-minimum date picker. Smaller bundle than Moment, tree-shakable.
localStorage + Context
Persistence layer that mimics an API. The data layer is abstracted in one module — swappable for a real backend later.
GitHub Actions → GitHub Pages
Push to main, site rebuilds. No CI/CD config to maintain.
Shipped a deployed production e-commerce + booking app with two real revenue flows running off one codebase: a product catalog with cart and WhatsApp checkout, a 5-step party booking wizard, and a 3-tab admin dashboard. Built on React 18 + Vite + Tailwind + Framer Motion, deployed via GitHub Actions to GitHub Pages. The original 5-page static site rebuilt into something the owner could actually run two streams of her business through.
Build with the channel, not against it. WhatsApp checkout sounds unconventional but matches how customers actually buy — and the result is higher conversion than forcing a card form into a small-business context.
Two flows, one design system. Encoding the brand into Tailwind tokens once let the e-commerce, the booking wizard, and the admin all stay visually consistent without re-deciding anything per screen.
A site without an admin is just a brochure. The moment a small business has any real volume, the dashboard is what turns the site into a tool they can actually run revenue through.
Next case study
Design System · Component Library