- Profile Picture\
Donation Tracking\ Validation Rejection\ Subscription Data Export\ Admin Dashboard Logo\ Admin Navbar Reorganization
This commit is contained in:
918
README.md
918
README.md
@@ -1,70 +1,912 @@
|
||||
# Getting Started with Create React App
|
||||
# LOAF Membership Platform - Frontend
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
React 19-based frontend application for the LOAF (LGBT Organization and Friends) membership management platform.
|
||||
|
||||
## Available Scripts
|
||||
## Table of Contents
|
||||
|
||||
In the project directory, you can run:
|
||||
- [Setup & Installation](#setup--installation)
|
||||
- [Architecture & Code Structure](#architecture--code-structure)
|
||||
- [Design System](#design-system)
|
||||
- [Deployment Guide](#deployment-guide)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
### `npm start`
|
||||
---
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
||||
## Setup & Installation
|
||||
|
||||
The page will reload when you make changes.\
|
||||
You may also see any lint errors in the console.
|
||||
### Prerequisites
|
||||
|
||||
### `npm test`
|
||||
- **Node.js**: 18.0 or higher
|
||||
- **Yarn**: 1.22+ (or npm 8+)
|
||||
- **Backend API**: Running on http://localhost:8000
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
### 1. Install Dependencies
|
||||
|
||||
### `npm run build`
|
||||
```bash
|
||||
cd frontend
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
# Using Yarn (recommended)
|
||||
yarn install
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
# Or using npm
|
||||
npm install
|
||||
```
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
**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
|
||||
|
||||
### `npm run eject`
|
||||
### 2. Environment Configuration
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
||||
Create `.env` file in the frontend directory:
|
||||
|
||||
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
```bash
|
||||
# Backend API URL
|
||||
REACT_APP_BACKEND_URL=http://localhost:8000
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
||||
# Optional: Analytics, Sentry, etc.
|
||||
# REACT_APP_SENTRY_DSN=your-sentry-dsn
|
||||
# REACT_APP_GA_TRACKING_ID=UA-XXXXXXXXX-X
|
||||
```
|
||||
|
||||
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
||||
**Important:**
|
||||
- All environment variables must start with `REACT_APP_`
|
||||
- Restart development server after changing `.env`
|
||||
|
||||
## Learn More
|
||||
### 3. Start Development Server
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
```bash
|
||||
# Start development server
|
||||
yarn start
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
# Or with npm
|
||||
npm start
|
||||
```
|
||||
|
||||
### Code Splitting
|
||||
**Development server will be available at:**
|
||||
- Frontend: http://localhost:3000
|
||||
- Auto-reloads on file changes
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
||||
### 4. Build for Production
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
```bash
|
||||
# Create production build
|
||||
yarn build
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
||||
# Or with npm
|
||||
npm build
|
||||
```
|
||||
|
||||
### Making a Progressive Web App
|
||||
Build output will be in `/build` directory.
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
||||
### 5. Run Tests
|
||||
|
||||
### Advanced Configuration
|
||||
```bash
|
||||
# Run tests in watch mode
|
||||
yarn test
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
||||
# Run tests with coverage
|
||||
yarn test --coverage
|
||||
|
||||
### Deployment
|
||||
# Or with npm
|
||||
npm test
|
||||
```
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
||||
---
|
||||
|
||||
### `npm run build` fails to minify
|
||||
## Architecture & Code Structure
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
### 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
|
||||
|
||||
Reference in New Issue
Block a user