Fixed critical issues with the profile page (/dashboard/profile):
1. **Form data not persisting on page refresh**:
- Added useEffect to update form values when user data loads
- Forms now properly populate after auth context loads user data
2. **Blank page on refresh**:
- Added loading and error states for better UX
- Handle case where user is not loaded yet (loading spinner)
- Handle case where user fails to load (retry button)
3. **Password change API endpoint correction**:
- Fixed: POST /api/v1/users/change-password (incorrect)
- Corrected to: PATCH /api/v1/users/me/password (matches backend)
- Updated return type to include { message: string }
The root cause was that useForm defaultValues were set once at
component mount when user was still null. The form never updated
when user data was subsequently loaded by the auth context.
Now the form properly resets with user data via useEffect, and
proper loading/error states prevent showing a blank page.
Refs: apps/frontend/app/dashboard/profile/page.tsx:68-78
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| app | ||
| e2e | ||
| lib | ||
| public | ||
| src | ||
| .dockerignore | ||
| .env.example | ||
| .eslintrc.json | ||
| .gitignore | ||
| DESIGN_QUICK_START.md | ||
| DESIGN_SYSTEM.md | ||
| Dockerfile | ||
| FRONTEND_API_CONNECTION_COMPLETE.md | ||
| IMPLEMENTATION_COMPLETE.md | ||
| LOGIN_PAGE_COMPLETE.md | ||
| middleware.ts | ||
| next.config.js | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| postcss.config.js | ||
| README.md | ||
| tailwind.config.ts | ||
| tsconfig.json | ||
Xpeditis Frontend
Application Next.js 14 pour la plateforme de réservation de fret maritime Xpeditis.
✅ Status Actuel: INFRASTRUCTURE COMPLÈTE
| Domaine | Status | Notes |
|---|---|---|
| API Integration | ✅ 100% | 60 endpoints connectés |
| Design System | ✅ 100% | Couleurs + Typos + Composants CSS |
| TypeScript Types | ✅ 100% | Types complets pour toutes les API |
| Assets Structure | ✅ 100% | Dossiers + utilitaires + docs |
| Documentation | ✅ 100% | 5 guides complets |
Infrastructure Frontend: PRODUCTION READY ✅
🎨 Design System Xpeditis
Couleurs de Marque ✅
| Couleur | Hex | Usage |
|---|---|---|
| Navy Blue | #10183A |
Headers, titres principaux |
| Turquoise | #34CCCD |
CTAs, liens, accents |
| Green | #067224 |
Success states, confirmations |
| Light Gray | #F2F2F2 |
Backgrounds, sections |
| White | #FFFFFF |
Cards, backgrounds principaux |
Typographies ✅
- Manrope (Google Fonts) - Titres H1-H6, navigation, boutons
- Montserrat (Google Fonts) - Corps de texte, formulaires, UI
Classes Tailwind Pré-configurées ✅
// Couleurs
bg-brand-navy, bg-brand-turquoise, bg-brand-green
text-accent, text-success
// Typographie
font-heading (Manrope), font-body (Montserrat)
text-h1, text-h2, text-body, text-body-sm, text-label
// Composants
btn-primary, btn-secondary, btn-success, btn-outline
card, badge-success, badge-info, link, input, label
📚 Documentation: DESIGN_SYSTEM.md | Quick Start
🔌 API Client (60 Endpoints) ✅
Tous les endpoints backend connectés avec types TypeScript:
import { login, searchCsvRates, createBooking } from '@/lib/api';
// Recherche avec pricing détaillé
const rates = await searchCsvRates({
origin: 'FRFOS',
destination: 'CNSHA',
volumeCBM: 6,
weightKG: 2500,
requiresSpecialHandling: true
});
// rates[0].priceBreakdown → basePrice, volumeCharge, surcharges[], totalPrice
Modules disponibles: auth (5), rates (4), bookings (7), users (6), organizations (4), notifications (7), audit (5), webhooks (7), gdpr (6), admin (5)
📚 Documentation: FRONTEND_API_CONNECTION_COMPLETE.md
🏗️ Tech Stack
- Framework: Next.js 14 (App Router)
- Language: TypeScript 5+
- Styling: Tailwind CSS v4 + shadcn/ui
- Fonts: Google Fonts (Manrope + Montserrat) ✅
- State Management: TanStack Query + Zustand
- Forms: react-hook-form + zod
- HTTP Client: Fetch API (custom wrapper) ✅
- Icons: lucide-react
- Testing: Jest + React Testing Library + Playwright
🚀 Quick Start
Install Dependencies
npm install
Setup Environment
cp .env.example .env
Default values work for local development!
Start Development Server
npm run dev
Open: http://localhost:3000
📝 Available Scripts
Development
npm run dev- Start development server (port 3000)npm run build- Build for productionnpm run start- Start production servernpm run lint- Lint codenpm test- Run testsnpm run test:watch- Run tests in watch modenpm run test:e2e- Run Playwright E2E tests
📁 Project Structure
app/
├── layout.tsx # Root layout
├── page.tsx # Home page
├── globals.css # Global styles
├── (routes)/ # Route groups
│ ├── search/ # Rate search
│ ├── bookings/ # Booking management
│ ├── dashboard/ # User dashboard
│ └── auth/ # Authentication
└── api/ # API routes (if needed)
components/
├── ui/ # shadcn/ui components
├── search/ # Search-specific components
├── bookings/ # Booking-specific components
└── shared/ # Shared components
lib/
├── api/ # API client & hooks
├── hooks/ # Custom React hooks
├── types/ # TypeScript types
├── utils.ts # Utility functions
└── validators/ # Zod schemas
🎨 Styling
Tailwind CSS
Using Tailwind CSS with custom theme configuration.
CSS Variables (defined in globals.css):
--background,--foreground--primary,--secondary--muted,--accent--destructive,--border- etc.
shadcn/ui Components
Pre-built accessible components:
- Buttons, Cards, Dialogs
- Forms, Inputs, Selects
- Tables, Tabs, Dropdowns
- And more...
Adding components:
npx shadcn-ui@latest add button
npx shadcn-ui@latest add card
# etc.
🔌 API Integration
API Client Setup
// lib/api/client.ts
import axios from 'axios';
const apiClient = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
export default apiClient;
React Query Hooks
// lib/api/rates.ts
import { useQuery } from '@tanstack/react-query';
import apiClient from './client';
export function useSearchRates(params: RateSearchParams) {
return useQuery({
queryKey: ['rates', params],
queryFn: async () => {
const { data } = await apiClient.post('/api/v1/rates/search', params);
return data;
},
});
}
Usage in Components
// components/search/SearchResults.tsx
import { useSearchRates } from '@/lib/api/rates';
export function SearchResults({ params }: Props) {
const { data, isLoading, error } = useSearchRates(params);
if (isLoading) return <LoadingSkeleton />;
if (error) return <ErrorMessage error={error} />;
return <RatesList rates={data} />;
}
📋 Forms
Using react-hook-form + zod for type-safe form validation.
Example:
// lib/validators/search.ts
import { z } from 'zod';
export const searchSchema = z.object({
origin: z.string().min(3, 'Invalid port code'),
destination: z.string().min(3, 'Invalid port code'),
containerType: z.enum(['20DRY', '40DRY', '40HC']),
departureDate: z.string().datetime(),
});
export type SearchFormData = z.infer<typeof searchSchema>;
// components/search/SearchForm.tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { searchSchema, SearchFormData } from '@/lib/validators/search';
export function SearchForm() {
const { register, handleSubmit, formState: { errors } } = useForm<SearchFormData>({
resolver: zodResolver(searchSchema),
});
const onSubmit = (data: SearchFormData) => {
// Handle submission
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* Form fields */}
</form>
);
}
🧪 Testing
Unit Tests (Jest + React Testing Library)
npm test
Example:
// components/ui/Button.test.tsx
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
describe('Button', () => {
it('renders children', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
});
E2E Tests (Playwright)
npm run test:e2e
Example:
// e2e/search.spec.ts
import { test, expect } from '@playwright/test';
test('search for rates', async ({ page }) => {
await page.goto('/search');
await page.fill('[name="origin"]', 'NLRTM');
await page.fill('[name="destination"]', 'CNSHA');
await page.click('button[type="submit"]');
await expect(page.locator('.rate-card')).toBeVisible();
});
🔒 Authentication
Authentication will be handled with:
- JWT tokens from backend
- NextAuth.js (optional)
- Protected routes with middleware
Example (to be implemented):
// middleware.ts
export { default } from 'next-auth/middleware';
export const config = {
matcher: ['/dashboard/:path*', '/bookings/:path*'],
};
📱 Responsive Design
Mobile-first approach with Tailwind breakpoints:
<div className="
flex flex-col // Mobile: column
md:flex-row // Tablet: row
lg:gap-8 // Desktop: larger gap
xl:max-w-7xl // Extra large: max width
">
{/* Content */}
</div>
Breakpoints:
sm: 640pxmd: 768pxlg: 1024pxxl: 1280px2xl: 1536px
🎯 Performance
- Code splitting: Automatic with Next.js App Router
- Image optimization: Using Next.js
<Image>component - React Query caching: Automatic caching of API responses
- Bundle analysis:
npm run buildshows bundle sizes
🌐 Environment Variables
# API
NEXT_PUBLIC_API_URL=http://localhost:4000
NEXT_PUBLIC_API_PREFIX=api/v1
# Auth (NextAuth)
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret
# OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
Note: Variables prefixed with NEXT_PUBLIC_ are exposed to the browser.
📖 Further Reading
🤝 Contributing
- Follow React/Next.js best practices
- Use TypeScript strict mode
- Write tests for components
- Ensure accessibility (WCAG 2.1 AA)
- Format with Prettier
- Lint with ESLint
📝 License
Proprietary - All rights reserved
Built with ❤️ using Next.js 14 and React 18