# LOAF Membership Platform - Frontend

React 19-based frontend application for the LOAF (LGBT Organization and Friends) membership management platform.

## Table of Contents

- [Setup & Installation](#setup--installation)
- [Architecture & Code Structure](#architecture--code-structure)
- [Design System](#design-system)
- [Deployment Guide](#deployment-guide)
- [Troubleshooting](#troubleshooting)

---

## Setup & Installation

### Prerequisites

- **Node.js**: 18.0 or higher
- **Yarn**: 1.22+ (or npm 8+)
- **Backend API**: Running on http://localhost:8000

### 1. Install Dependencies

```bash
cd frontend

# Using Yarn (recommended)
yarn install

# Or using npm
npm install
```

**Key Dependencies:**
- `react@19.0.0` - UI library
- `react-router-dom@7.5.1` - Routing
- `axios@1.8.4` - HTTP client
- `react-hook-form@7.56.2` - Form handling
- `zod@3.24.4` - Schema validation
- `@radix-ui/*` - UI components (45+ components)
- `tailwindcss@3.4.17` - CSS framework
- `lucide-react@0.507.0` - Icons
- `sonner@1.7.4` - Toast notifications

### 2. Environment Configuration

Create `.env` file in the frontend directory:

```bash
# Backend API URL
REACT_APP_BACKEND_URL=http://localhost:8000

# Optional: Analytics, Sentry, etc.
# REACT_APP_SENTRY_DSN=your-sentry-dsn
# REACT_APP_GA_TRACKING_ID=UA-XXXXXXXXX-X
```

**Important:**
- All environment variables must start with `REACT_APP_`
- Restart development server after changing `.env`

### 3. Start Development Server

```bash
# Start development server
yarn start

# Or with npm
npm start
```

**Development server will be available at:**
- Frontend: http://localhost:3000
- Auto-reloads on file changes

### 4. Build for Production

```bash
# Create production build
yarn build

# Or with npm
npm build
```

Build output will be in `/build` directory.

### 5. Run Tests

```bash
# Run tests in watch mode
yarn test

# Run tests with coverage
yarn test --coverage

# Or with npm
npm test
```

---

## Architecture & Code Structure

### Project Structure

```
frontend/
├── public/                   # Static assets
│   ├── loaf-logo.png        # LOAF logo for admin sidebar
│   ├── hero-loaf.png        # Landing page hero image
│   └── index.html           # HTML template
├── src/
│   ├── pages/               # Page components (20+ pages)
│   │   ├── Landing.js       # Public landing page
│   │   ├── Register.js      # 4-step registration (388 lines)
│   │   ├── Login.js         # Authentication
│   │   ├── Dashboard.js     # Member dashboard
│   │   ├── Profile.js       # User profile with photo upload
│   │   ├── Events.js        # Event listing
│   │   ├── EventDetails.js  # Event details + RSVP
│   │   └── admin/           # Admin pages
│   │       ├── AdminDashboard.js
│   │       ├── AdminUsers.js
│   │       ├── AdminValidations.js   # Approve/reject workflow
│   │       ├── AdminEvents.js
│   │       ├── AdminSubscriptions.js # With CSV export
│   │       └── AdminDonations.js     # Donation tracking
│   ├── components/          # Reusable components
│   │   ├── Navbar.js        # Main navigation
│   │   ├── AdminSidebar.js  # Admin sidebar with logo
│   │   ├── RejectionDialog.js  # Rejection workflow dialog
│   │   └── ui/              # 45+ Radix UI components
│   │       ├── button.js
│   │       ├── dialog.js
│   │       ├── input.js
│   │       ├── select.js
│   │       └── ... (40+ more)
│   ├── context/
│   │   └── AuthContext.js   # Global auth state
│   ├── hooks/
│   │   └── use-toast.js     # Toast notification hook
│   ├── utils/
│   │   └── api.js           # Axios instance with JWT interceptor
│   ├── App.js               # Main routing setup
│   ├── index.js             # React entry point
│   └── index.css            # Global styles + Tailwind
├── craco.config.js          # Craco configuration
├── tailwind.config.js       # Tailwind CSS configuration
├── package.json             # Dependencies
└── .env                     # Environment variables (not in git)
```

### Core Technologies

| Technology | Purpose | Version |
|------------|---------|---------|
| React | UI library | 19.0.0 |
| React Router | Client-side routing | 7.5.1 |
| Axios | HTTP requests | 1.8.4 |
| React Hook Form | Form handling | 7.56.2 |
| Zod | Schema validation | 3.24.4 |
| Tailwind CSS | CSS framework | 3.4.17 |
| Radix UI | Component library | Latest |
| Lucide React | Icons | 0.507.0 |
| Sonner | Toast notifications | 1.7.4 |

### Key Features

#### Authentication System

**Global Auth Context** (`src/context/AuthContext.js`):
- JWT token storage in localStorage
- Automatic token injection via Axios interceptor
- User state management
- Protected route wrapper

**Usage:**
```jsx
import { useAuth } from '../context/AuthContext';

function MyComponent() {
  const { user, login, logout, isAuthenticated } = useAuth();

  // user contains: id, email, first_name, last_name, role, status
}
```

#### Protected Routes

**PrivateRoute Wrapper:**
```jsx
<Route path="/dashboard" element={
  <PrivateRoute>
    <Dashboard />
  </PrivateRoute>
} />

// Admin-only route
<Route path="/admin" element={
  <PrivateRoute adminOnly>
    <AdminDashboard />
  </PrivateRoute>
} />
```

#### API Integration

**Axios Instance** (`src/utils/api.js`):
- Automatic JWT token injection
- Request/response interceptors
- Error handling
- Base URL configuration

**Usage:**
```jsx
import api from '../utils/api';

// GET request
const response = await api.get('/members/profile');

// POST request with data
const response = await api.post('/admin/users/123/reject', {
  reason: 'Incomplete application'
});

// File upload
const formData = new FormData();
formData.append('file', file);
const response = await api.post('/members/profile/upload-photo', formData, {
  headers: { 'Content-Type': 'multipart/form-data' }
});
```

#### Form Handling

**React Hook Form + Zod Pattern:**
```jsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email('Invalid email address'),
  password: z.string().min(8, 'Password must be at least 8 characters')
});

function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: zodResolver(schema)
  });

  const onSubmit = async (data) => {
    try {
      await api.post('/auth/login', data);
      toast.success('Login successful!');
    } catch (error) {
      toast.error(error.response?.data?.detail || 'Login failed');
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Input {...register('email')} />
      {errors.email && <span>{errors.email.message}</span>}
      {/* ... */}
    </form>
  );
}
```

#### Toast Notifications

**Using Sonner:**
```jsx
import { toast } from 'sonner';

// Success
toast.success('Profile updated successfully!');

// Error
toast.error('Failed to upload photo');

// Custom
toast('Processing...', {
  description: 'Please wait while we process your request'
});
```

### Page Components

#### Public Pages

**Landing.js**
- Hero section with LOAF branding
- Feature highlights
- Call-to-action buttons

**Register.js** (388 lines)
- 4-step registration wizard:
  1. Basic Info (email, password, name)
  2. Personal Details (phone, address, DOB)
  3. Partner Information (optional)
  4. Lead Sources & Referral
- Form validation with Zod
- Progress indicator
- Email verification trigger

**Login.js**
- Email/password authentication
- JWT token storage
- Remember me functionality
- Redirect to dashboard on success

#### Member Pages

**Dashboard.js**
- Welcome message with user name
- Upcoming events preview
- Membership status card
- Quick action buttons

**Profile.js**
- Profile photo upload with Avatar component
- File validation (image types, 50MB max)
- Personal information editing
- Partner information
- Save changes with API update

**Events.js**
- Event listing with filters
- Search functionality
- Upcoming/past events toggle
- Event cards with cover images

**EventDetails.js**
- Full event information
- RSVP form (Yes/No/Maybe)
- Attendance confirmation
- Google Maps integration (optional)

#### Admin Pages

**AdminDashboard.js**
- Statistics overview
- Pending validations count
- Recent activity feed
- Quick links to management pages

**AdminUsers.js**
- User listing with search/filters
- Status badges
- Bulk operations
- CSV export

**AdminValidations.js**
- Pending user applications
- Approve button
- **Reject button with RejectionDialog**
- Validation workflow management

**AdminSubscriptions.js**
- Subscription listing
- Status filters (active, cancelled, expired)
- **CSV export dropdown** (Export All / Export Current View)
- Edit subscription dialog

**AdminDonations.js** (400+ lines)
- 4 stats cards: Total, Member, Public, Total Amount
- Filters: type, status, date range, search
- Responsive table with mobile cards
- **CSV export functionality**

**AdminEvents.js**
- Event management interface
- Create/edit events
- Publish/unpublish toggle
- Cover image upload
- RSVP tracking
- Attendance marking

### Component Library (Radix UI)

**45+ UI Components** in `src/components/ui/`:

**Form Components:**
- Button, Input, Textarea, Checkbox, Radio
- Select, Label, Form

**Layout Components:**
- Card, Dialog, Sheet (Drawer), Popover
- Dropdown Menu, Tabs, Accordion

**Feedback Components:**
- Alert, Badge, Toast (Sonner)
- Progress, Skeleton, Spinner

**Navigation:**
- Navigation Menu, Breadcrumb, Pagination

**Usage Example:**
```jsx
import { Button } from './components/ui/button';
import { Dialog, DialogContent, DialogTitle } from './components/ui/dialog';
import { Select, SelectTrigger, SelectContent, SelectItem } from './components/ui/select';

<Button className="bg-[#664fa3] text-white">
  Click me
</Button>
```

### Admin Sidebar Features

**Logo Integration:**
- LOAF logo in header
- Shows logo + "Admin" text when expanded
- Logo only when collapsed
- Smooth transition animations

**Navigation Groups:**
- **Dashboard** (standalone)
- **MEMBERSHIP** - Staff, Members, Validations
- **FINANCIALS** - Plans, Subscriptions, Donations
- **EVENTS & MEDIA** - Events, Gallery
- **DOCUMENTATION** - Newsletters, Financial Reports, Bylaws
- **Permissions** (Superadmin only)

---

## Design System

### Color Palette

**LOAF Brand Colors:**
```css
--primary: #422268      /* Deep Purple - Primary brand */
--secondary: #664fa3    /* Light Purple - Secondary elements */
--accent: #ff9e77       /* Coral - Accents and highlights */
--muted: #ddd8eb        /* Light Purple Gray - Borders */
--background: #f9f5ff   /* Very Light Purple - Backgrounds */
--foreground: #422268   /* Text color */
```

**Usage in Tailwind:**
```jsx
<div className="bg-[#422268] text-white">
  <h1 className="text-[#ff9e77]">Accent Text</h1>
  <p className="text-[#664fa3]">Secondary Text</p>
</div>
```

### Typography

**Font Families:**
- **Headings**: 'Inter', sans-serif
- **Body**: 'Nunito Sans', sans-serif
- **Code**: 'Fira Code', monospace (if needed)

**Font Sizes:**
```css
text-xs    → 0.75rem (12px)
text-sm    → 0.875rem (14px)
text-base  → 1rem (16px)
text-lg    → 1.125rem (18px)
text-xl    → 1.25rem (20px)
text-2xl   → 1.5rem (24px)
text-3xl   → 1.875rem (30px)
```

**Usage:**
```jsx
<h1 className="text-3xl font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
  Page Title
</h1>
<p className="text-base text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
  Body text
</p>
```

### Spacing System

**Tailwind Spacing Scale:**
```css
p-2  → 0.5rem (8px)
p-4  → 1rem (16px)
p-6  → 1.5rem (24px)
p-8  → 2rem (32px)

gap-2, gap-4, gap-6, gap-8 (same scale for flex/grid gaps)
```

### Component Styling Patterns

**Cards:**
```jsx
<Card className="p-6 bg-white rounded-2xl border-2 border-[#ddd8eb]">
  {/* Content */}
</Card>
```

**Buttons:**
```jsx
// Primary
<Button className="bg-[#664fa3] text-white hover:bg-[#422268] rounded-full px-6 py-3">
  Primary Action
</Button>

// Secondary
<Button variant="outline" className="border-2 border-[#ddd8eb] text-[#664fa3] hover:bg-[#f1eef9] rounded-full">
  Secondary Action
</Button>

// Destructive
<Button className="bg-red-600 text-white hover:bg-red-700 rounded-full">
  Delete
</Button>
```

**Form Inputs:**
```jsx
<Input className="rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" />
<Textarea className="rounded-xl border-2 border-[#ddd8eb] min-h-[120px]" />
<Select>
  <SelectTrigger className="rounded-xl border-2 border-[#ddd8eb]">
    <SelectValue placeholder="Select..." />
  </SelectTrigger>
</Select>
```

**Badges:**
```jsx
// Status badges
<Badge className="bg-green-100 text-green-800">Active</Badge>
<Badge className="bg-yellow-100 text-yellow-800">Pending</Badge>
<Badge className="bg-red-100 text-red-800">Rejected</Badge>
```

### Icons (Lucide React)

**Common Icons:**
```jsx
import {
  User, Mail, Phone, MapPin,         // User info
  Calendar, Clock, CheckCircle,      // Status
  Edit, Trash2, X, Check,            // Actions
  Search, Filter, Download,          // Utilities
  Heart, DollarSign, CreditCard,     // Financial
  AlertTriangle, Info, HelpCircle    // Alerts
} from 'lucide-react';

<User className="h-5 w-5 text-[#664fa3]" />
```

### Responsive Design

**Breakpoints:**
```css
sm: 640px   → @media (min-width: 640px)
md: 768px   → @media (min-width: 768px)
lg: 1024px  → @media (min-width: 1024px)
xl: 1280px  → @media (min-width: 1280px)
2xl: 1536px → @media (min-width: 1536px)
```

**Mobile-First Approach:**
```jsx
<div className="flex flex-col md:flex-row gap-4">
  {/* Stacks vertically on mobile, horizontal on tablet+ */}
</div>

<div className="hidden md:block">
  {/* Only shows on tablet+ */}
</div>

<div className="md:hidden">
  {/* Only shows on mobile */}
</div>
```

### Animations

**Tailwind Transitions:**
```jsx
<Button className="transition-all duration-200 hover:scale-105">
  Hover me
</Button>

<div className="animate-fade-in">
  {/* Fades in on mount */}
</div>
```

---

## Deployment Guide

### Production Build

#### 1. Environment Variables

Create `.env.production`:
```bash
REACT_APP_BACKEND_URL=https://api.loaf.org
REACT_APP_SENTRY_DSN=your-production-sentry-dsn
```

#### 2. Build Application

```bash
# Install dependencies
yarn install

# Create production build
yarn build
```

Build output will be in `/build` directory.

#### 3. Deployment Options

### Option A: Netlify (Recommended)

**Via Netlify CLI:**
```bash
# Install Netlify CLI
npm install -g netlify-cli

# Login
netlify login

# Deploy
netlify deploy --prod --dir=build
```

**Via Git Integration:**
1. Push code to GitHub/GitLab
2. Connect repository in Netlify dashboard
3. Configure:
   - Build command: `yarn build`
   - Publish directory: `build`
   - Environment variables (from .env.production)
4. Deploy automatically on push

**Configure Redirects** (`public/_redirects`):
```
/*    /index.html   200
```
This enables client-side routing.

### Option B: Vercel

```bash
# Install Vercel CLI
npm install -g vercel

# Deploy
vercel --prod
```

**Configure** (`vercel.json`):
```json
{
  "rewrites": [
    { "source": "/(.*)", "destination": "/index.html" }
  ],
  "env": {
    "REACT_APP_BACKEND_URL": "https://api.loaf.org"
  }
}
```

### Option C: Traditional Web Server (Nginx)

**1. Copy build files to server:**
```bash
scp -r build/* user@server:/var/www/loaf-frontend/
```

**2. Configure Nginx** (`/etc/nginx/sites-available/loaf-frontend`):
```nginx
server {
    listen 80;
    server_name app.loaf.org;
    root /var/www/loaf-frontend;
    index index.html;

    location / {
        try_files $uri /index.html;
    }

    # Cache static assets
    location /static/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
}
```

**3. Enable site and restart:**
```bash
sudo ln -s /etc/nginx/sites-available/loaf-frontend /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
```

**4. SSL Certificate:**
```bash
sudo certbot --nginx -d app.loaf.org
```

### Option D: AWS S3 + CloudFront

**1. Create S3 bucket:**
```bash
aws s3 mb s3://loaf-frontend
aws s3 sync build/ s3://loaf-frontend --delete
```

**2. Configure bucket for static hosting:**
```bash
aws s3 website s3://loaf-frontend --index-document index.html --error-document index.html
```

**3. Create CloudFront distribution** pointing to S3 bucket with custom error pages (all errors → /index.html).

### Performance Optimization

**1. Code Splitting:**
```jsx
// Lazy load routes
import { lazy, Suspense } from 'react';

const AdminDonations = lazy(() => import('./pages/admin/AdminDonations'));

<Route path="/admin/donations" element={
  <Suspense fallback={<div>Loading...</div>}>
    <AdminDonations />
  </Suspense>
} />
```

**2. Image Optimization:**
- Use WebP format when possible
- Compress images before upload
- Use lazy loading: `loading="lazy"`

**3. Bundle Analysis:**
```bash
# Install analyzer
yarn add --dev webpack-bundle-analyzer

# Analyze bundle
yarn build
npx webpack-bundle-analyzer build/static/js/*.js
```

### CI/CD Pipeline

**GitHub Actions** (`.github/workflows/deploy.yml`):
```yaml
name: Deploy Frontend

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: yarn install
      - run: yarn build
        env:
          REACT_APP_BACKEND_URL: ${{ secrets.BACKEND_URL }}
      - uses: netlify/actions/cli@master
        with:
          args: deploy --dir=build --prod
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
```

---

## Troubleshooting

### Common Issues

#### 1. Module Not Found Errors

**Error:** `Module not found: Can't resolve 'package-name'`

**Solution:**
```bash
# Clear node_modules and reinstall
rm -rf node_modules yarn.lock
yarn install

# Or with npm
rm -rf node_modules package-lock.json
npm install
```

#### 2. CORS Errors

**Error:** `Access to XMLHttpRequest blocked by CORS policy`

**Solution:**
- Backend must include frontend URL in CORS_ORIGINS
- Check REACT_APP_BACKEND_URL is correct
- Backend: `CORS_ORIGINS=http://localhost:3000,https://app.loaf.org`

#### 3. 401 Unauthorized

**Error:** API returns 401 after some time

**Solution:**
- JWT token expired (default 30 minutes)
- User needs to log in again
- Check token is being sent in Authorization header

#### 4. Environment Variables Not Working

**Error:** `process.env.REACT_APP_BACKEND_URL is undefined`

**Solution:**
- Ensure variable name starts with `REACT_APP_`
- Restart development server after changing .env
- Don't commit .env to git (use .env.example)

#### 5. Build Fails

**Error:** `npm run build` fails with memory error

**Solution:**
```bash
# Increase Node memory limit
NODE_OPTIONS=--max_old_space_size=4096 yarn build
```

#### 6. Routing Not Working in Production

**Error:** Refresh on /dashboard returns 404

**Solution:**
- Configure server to redirect all routes to index.html
- Netlify: Add `_redirects` file
- Nginx: Use `try_files $uri /index.html`
- Vercel: Add vercel.json with rewrites

#### 7. Images Not Loading

**Error:** Profile photos return 404

**Solution:**
- Check R2_PUBLIC_URL is correct in backend .env
- Verify Cloudflare R2 bucket is public
- Check CORS settings in R2 bucket

### Debug Mode

```jsx
// Add to any component for debugging
console.log('Component rendered', { user, props });

// Check API responses
api.interceptors.response.use(
  response => {
    console.log('API Response:', response);
    return response;
  },
  error => {
    console.error('API Error:', error.response);
    return Promise.reject(error);
  }
);
```

### Getting Help

- **Project Context**: See `CLAUDE.md` and `PRD.md`
- **API Docs**: http://localhost:8000/docs (backend Swagger)
- **React Docs**: https://react.dev/
- **Tailwind CSS**: https://tailwindcss.com/docs
- **Radix UI**: https://www.radix-ui.com/primitives

---

## Additional Resources

- **React Documentation**: https://react.dev/
- **React Router**: https://reactrouter.com/
- **Tailwind CSS**: https://tailwindcss.com/
- **Radix UI**: https://www.radix-ui.com/
- **React Hook Form**: https://react-hook-form.com/
- **Zod**: https://zod.dev/
- **Lucide Icons**: https://lucide.dev/

---

**Last Updated**: December 18, 2024
**Version**: 1.0.0
**Maintainer**: LOAF Development Team
