Overview
Customer rewards app for Tor Home, a Thai construction-materials retailer. Built mobile-first with a hard 430px max-width layout — this is a phone app delivered as a web app, not a marketing site that happens to work on mobile. Customers collect points on purchases, redeem rewards, and manage their profile; the staff manage the catalog through a separate admin app. Designed for the retail customer journey, not for desktop browsing.
What I built
Customer-facing app
- Multi-step phone-and-birthdate login — phone number first, then 8-digit DDMMYYYY birth date as the password (no email, no traditional password reset)
- If the phone isn't registered, the flow drops into a registration form that captures personal + business info (tax ID, company, full Thai address)
- Home with profile card, banner, and quick-access cards for Points / Redeem / Profile
- Reward redemption catalog with detail views and confirmation dialogs
- Transaction history (points collected + rewards redeemed)
- Profile management with full Thai address picker (provinces / districts / sub-districts hierarchy)
Backend integration
- Two API client setups:
api.main.jsfor client-side calls (with automatic token refresh on 401) andapi.server.jsfor server-component calls - JWT stored in both cookies and Zustand store, persisted to localStorage as
torhomeuser - Hydration-aware — the store knows whether SSR has hydrated to avoid flash of unauthenticated state
Tech stack
- Frontend: Next.js 16 App Router, React 19, Tailwind CSS v4
- UI library: PureKit UI (in-house design system) + Radix UI dialog
- State: Zustand with localStorage persistence
- Animations: Framer Motion for transitions
- Backend: AWS Amplify (Lambda + Express + MongoDB)
- Auth: JWT in HTTP-only cookies + Zustand store, auto-refresh on 401
- Localization: Custom font
LINESeedSansTHfor Thai readability; brand colors blue (#255dc6) + orange CTAs
My role
Built the customer-facing app end-to-end. The login flow was the most carefully designed piece — construction-materials retail customers are not tech-power-users, so the login had to be foolproof: no email, no password reset, no "check your inbox". Phone number plus birth date is what they remember. Coordinated with the admin app's owner for shared API contracts and the JWT auth flow.
What I learned
Designing auth for a non-technical retail audience is a different problem than designing it for a SaaS audience. Email-based password resets assume everyone has reliable email and remembers the address they signed up with — neither is true here. Phone + birthdate is the right answer for this audience, but it means thinking carefully about the registration flow when a phone number isn't found (drop into registration, not into an error). The other lesson was the value of hard 430px max-width as a constraint: knowing the layout never goes wider than a phone simplified every design decision and made the responsive work trivial.



