Skip to content

Frontend - User Wallet App

Overview

The User Wallet App is a React TypeScript web application that allows golf club members to: - View their wallet balance (giftcards, range tokens, greenfee tickets) - Redeem value from wallet items - Claim giftcards using codes - Track recent transactions

Technology Stack

  • Framework: React 18 with TypeScript
  • Build Tool: Create React App (Webpack)
  • State Management: React Hooks + Context (minimal, no Redux)
  • HTTP Client: Axios
  • Routing: React Router v6
  • Authentication: Firebase Auth
  • Styling: Vanilla CSS with responsive design

Project Structure

webapp/
├── public/                  # Static files
├── src/
   ├── config/             # Configuration
      ├── firebase.ts     # Firebase initialization
      └── api.ts          # API endpoints config
   
   ├── services/           # API integration layer
      └── walletApi.ts    # Wallet API client
   
   ├── hooks/              # Custom React hooks
      ├── useAuth.ts      # Auth state management
      └── useWalletProjection.ts  # Wallet data fetching
   
   ├── pages/              # Page components
      ├── LoginPage.tsx   # Authentication UI
      └── WalletPage.tsx  # Main wallet dashboard
   
   ├── types/              # TypeScript definitions
      └── index.ts        # All API types
   
   ├── styles/             # CSS stylesheets
      ├── Auth.css
      └── Wallet.css
   
   ├── App.tsx             # Main app + routing
   ├── index.tsx           # React root
   └── App.css             # Global styles

├── .env.example            # Environment template
├── package.json
├── tsconfig.json
└── README.md

Key Features

1. Authentication

  • Email/Password sign-up and login
  • Firebase Authentication
  • Session persistence
  • Automatic token refresh

File: src/pages/LoginPage.tsx

2. Wallet Dashboard

  • Real-time balance display
  • Four card summary (Giftcards, Tokens, 9-hole tickets, 18-hole tickets)
  • Recent transaction history
  • Pull-to-refresh capability

File: src/pages/WalletPage.tsx

3. Redemption

  • Select wallet item to redeem from
  • Enter amount
  • Automatic balance update

API Call: POST /wallet_redeem

4. Code-Based Claims

  • Enter claim code (e.g., ABCD-EFGH-IJKL-MNOP)
  • Automatic wallet item creation
  • Prevents duplicate claims (backend idempotency)

API Call: POST /wallet_claim

5. Real-time Sync

  • Automatic refresh every 30 seconds
  • Manual refresh button
  • Optimistic UI updates

Hook: useWalletProjection

API Integration

The app communicates with the backend REST API:

Configuration

// src/config/api.ts
export const FUNCTIONS = {
  GIFTCARDS_ISSUE: `${API_BASE_URL}/giftcards_issue`,
  WALLET_REDEEM: `${API_BASE_URL}/wallet_redeem`,
  WALLET_CLAIM: `${API_BASE_URL}/wallet_claim`,
  WALLET_PROJECTIONS: `${API_BASE_URL}/wallet_projections`,
  HEALTH_CHECK: `${API_BASE_URL}/healthCheck`,
};

Authentication

All API calls include Firebase ID token:

const headers = {
  Authorization: `Bearer ${idToken}`,
  "Content-Type": "application/json"
};

Error Handling

  • Automatic retry logic for network errors
  • User-friendly error messages
  • Detailed error logging to console

Setup Instructions

1. Clone & Install

cd Gavekort-multitennenant/webapp
npm install

2. Configure Environment

Create .env.local:

cp .env.example .env.local

Fill in your Firebase project credentials:

REACT_APP_FIREBASE_API_KEY=your-api-key
REACT_APP_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
REACT_APP_FIREBASE_PROJECT_ID=your-project-id
REACT_APP_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
REACT_APP_FIREBASE_APP_ID=your-app-id
REACT_APP_API_BASE_URL=https://us-central1-your-project.cloudfunctions.net

3. Run Development Server

npm start

Opens at http://localhost:3000

4. Build for Production

npm run build

Creates optimized bundle in build/ directory (128.88 kB gzipped)

Development Guide

Custom Hooks

useAuth()

const { user, loading, error } = useAuth();

// Returns:
// - user: { uid, email, displayName, photoURL }
// - loading: boolean (initial auth check)
// - error: Error | null

useWalletProjection(userId)

const { projection, loading, error, refresh } = useWalletProjection(userId);

// Returns:
// - projection: WalletProjection | null
// - loading: boolean
// - error: Error | null
// - refresh: () => Promise<void>  // Manual refresh

API Service

// src/services/walletApi.ts

// Get wallet balance
await getWalletProjection(userId);

// Redeem value
await redeemValue(walletItemId, amount, reason);

// Claim code
await claimCode(code, externalAccountId);

// Check health
await checkHealth();

Adding a New Page

  1. Create component in src/pages/NewPage.tsx
  2. Add route in App.tsx: typescript <Route path="/new" element={<NewPage />} />
  3. Create styles in src/styles/NewPage.css
  4. Use hooks for data fetching

Adding a Component

  1. Create in src/components/MyComponent.tsx
  2. Create styles in src/styles/MyComponent.css
  3. Export from component file
  4. Use in pages

Styling

Color Scheme

  • Primary: #667eea (Purple)
  • Secondary: #764ba2 (Dark Purple)
  • Success: #3a3 (Green)
  • Error: #c33 (Red)
  • Background: #f5f5f5 (Light Gray)

Responsive Breakpoints

/* Tablet */
@media (max-width: 768px) { }

/* Mobile */
@media (max-width: 480px) { }

CSS Grid

Balance cards use CSS Grid for responsive layout:

grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

Security Features

  1. Protected Routes
  2. Login redirect for unauthenticated users
  3. Session persistence

  4. API Authentication

  5. Firebase ID tokens included in all requests
  6. Automatic token refresh before expiry

  7. CORS

  8. Cloud Functions configured for public CORS
  9. API endpoints validated in config/api.ts

  10. Input Validation

  11. Client-side form validation
  12. Server-side validation on backend

Testing

npm test

Integration Testing

# With Firebase Emulator
firebase emulators:start

# In another terminal
npm start

Test user: test@example.com / password123

Deployment

Firebase Hosting

# Install Firebase tools
npm install -g firebase-tools

# Login
firebase login

# Deploy
firebase deploy --only hosting

Environment-Specific Builds

# Development
REACT_APP_API_BASE_URL=http://localhost:5001 npm build

# Production
REACT_APP_API_BASE_URL=https://prod.example.com npm build

Performance Optimization

Current Optimizations

  • Code splitting via React Router
  • CSS minification
  • Gzipped bundle size: 128.88 kB
  • Add React.memo() for expensive components
  • Lazy load pages with React.lazy()
  • Cache API responses with SWR or React Query
  • PWA capabilities for offline support

Browser Support

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+
  • Mobile browsers (iOS Safari, Chrome Mobile)

Troubleshooting

Build Fails with TypeScript Errors

npm run build -- --verbose

Check error output and fix type issues.

API Calls Return 401 (Unauthorized)

  1. Verify .env.local has correct Firebase credentials
  2. Check Firebase project has Authentication enabled
  3. Verify ID token is valid: auth.currentUser?.getIdToken()

"Cannot find module" Errors

rm -rf node_modules package-lock.json
npm install

Dev Server Won't Start

# Kill existing process on port 3000
lsof -ti:3000 | xargs kill -9

# Or use different port
PORT=3001 npm start

Next Steps

  1. Add Admin Features (if user is ADMIN role)
  2. Implement Transaction Filtering
  3. Add Dark Mode
  4. Setup CI/CD Pipeline
  5. Add Analytics
  6. Multi-language Support (i18n)
  7. QR Code Scanner for claiming codes