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.
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.