Skip to main content
Back to all seeds
WebLive2025

ByteSpace Cyber

Complete business platform for a Nairobi tech hub — services booking, online shop for tech accessories, M-Pesa payments, blog with comments/likes, admin panel, dark mode, EN/SW bilingual.

React 18TypeScriptViteTailwind CSSshadcn/uiSupabaseTanStack QueryZodM-Pesa STK Push

What it is

A complete business platform for ByteSpace Cyber, a Nairobi tech hub. Services booking, an online shop for tech accessories, blog with comments and likes, an admin panel, and a user dashboard — all bilingual (EN / SW) with dark mode and M-Pesa STK Push payments built in.

The problem

Local tech hubs in Nairobi were running services, retail, and community on three separate tools — a Google Form for bookings, a WhatsApp group for the shop, a static site for the blog. Members fell through the cracks, payments were manual, and there was no single place to log in and see your orders, your bookings, and your activity.

What I built

Services + shop in one shell

Same auth session works across the booking flow and the e-commerce checkout. Members can book a coworking slot and add a USB-C dock to the cart in the same purchase, paid via M-Pesa STK Push.

Admin panel + user dashboard

Admins manage products, services, blog posts, and order fulfilment from one panel. Members get an order history, a bookings calendar, and notification preferences.

Stack

React 18 + Vite + TypeScript on the front end, shadcn/ui primitives composed with Tailwind, TanStack Query for server state, React Hook Form + Zod for validation. Supabase for auth, Postgres, RLS, and Edge Functions handling M-Pesa callbacks.

Bilingual (EN / SW)

Every user-facing string is keyed for English and Kiswahili. A pragmatic in-house i18n layer (no i18next) — keys live alongside components, language preference persists per user.

Engineering decisions

Why shadcn/ui over a packaged kit

shadcn drops the source for each primitive into your repo. That meant when ByteSpace wanted a small visual variant on the Card component, I edited the file in our codebase instead of fighting a CSS-variable override system.

Why TanStack Query instead of Redux

The vast majority of state in a booking + commerce app is server state. TanStack handles caching, invalidation, and optimistic updates with less ceremony than a global store.

Why Edge Functions for M-Pesa

Daraja callbacks have to respond fast and idempotently. Edge Functions live next to the database, accept the callback, validate the signature, and write the order in one round-trip — fewer moving parts than a separate webhook server.

What I'd do differently

Build the bilingual layer with proper namespaces from day one — colocating keys with components is fast for a single-feature site but as the surface grew I had a few duplicated keys to clean up. A v2 should also wire end-to-end tests for the M-Pesa happy path and timeout cases; right now those are exercised manually.