Some checks failed
CI / Lint & Format Check (push) Failing after 1m11s
CI / Test Backend (push) Failing after 1m32s
CI / Build Backend (push) Has been skipped
Security Audit / npm audit (push) Failing after 5s
Security Audit / Dependency Review (push) Has been skipped
CI / Test Frontend (push) Failing after 29s
CI / Build Frontend (push) Has been skipped
335 lines
7.2 KiB
Markdown
335 lines
7.2 KiB
Markdown
# Xpeditis Frontend
|
|
|
|
Next.js 14-based frontend for the Xpeditis maritime freight booking platform.
|
|
|
|
## 🏗️ Tech Stack
|
|
|
|
- **Framework**: Next.js 14 (App Router)
|
|
- **Language**: TypeScript 5
|
|
- **Styling**: Tailwind CSS + shadcn/ui
|
|
- **State Management**: TanStack Query (React Query)
|
|
- **Forms**: react-hook-form + zod
|
|
- **HTTP Client**: axios
|
|
- **Icons**: lucide-react
|
|
- **Testing**: Jest + React Testing Library + Playwright
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### Install Dependencies
|
|
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
### Setup Environment
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
Default values work for local development!
|
|
|
|
### Start Development Server
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
Open: **http://localhost:3000**
|
|
|
|
## 📝 Available Scripts
|
|
|
|
### Development
|
|
|
|
- `npm run dev` - Start development server (port 3000)
|
|
- `npm run build` - Build for production
|
|
- `npm run start` - Start production server
|
|
- `npm run lint` - Lint code
|
|
- `npm test` - Run tests
|
|
- `npm run test:watch` - Run tests in watch mode
|
|
- `npm 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**:
|
|
```bash
|
|
npx shadcn-ui@latest add button
|
|
npx shadcn-ui@latest add card
|
|
# etc.
|
|
```
|
|
|
|
## 🔌 API Integration
|
|
|
|
### API Client Setup
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
// 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**:
|
|
|
|
```typescript
|
|
// 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>;
|
|
```
|
|
|
|
```typescript
|
|
// 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)
|
|
|
|
```bash
|
|
npm test
|
|
```
|
|
|
|
**Example**:
|
|
```typescript
|
|
// 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)
|
|
|
|
```bash
|
|
npm run test:e2e
|
|
```
|
|
|
|
**Example**:
|
|
```typescript
|
|
// 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):
|
|
```typescript
|
|
// middleware.ts
|
|
export { default } from 'next-auth/middleware';
|
|
|
|
export const config = {
|
|
matcher: ['/dashboard/:path*', '/bookings/:path*'],
|
|
};
|
|
```
|
|
|
|
## 📱 Responsive Design
|
|
|
|
Mobile-first approach with Tailwind breakpoints:
|
|
|
|
```typescript
|
|
<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`: 640px
|
|
- `md`: 768px
|
|
- `lg`: 1024px
|
|
- `xl`: 1280px
|
|
- `2xl`: 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 build` shows bundle sizes
|
|
|
|
## 🌐 Environment Variables
|
|
|
|
```env
|
|
# 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
|
|
|
|
- [Next.js Documentation](https://nextjs.org/docs)
|
|
- [Tailwind CSS](https://tailwindcss.com/docs)
|
|
- [shadcn/ui](https://ui.shadcn.com/)
|
|
- [TanStack Query](https://tanstack.com/query/latest)
|
|
- [React Hook Form](https://react-hook-form.com/)
|
|
- [Zod](https://zod.dev/)
|
|
|
|
## 🤝 Contributing
|
|
|
|
1. Follow React/Next.js best practices
|
|
2. Use TypeScript strict mode
|
|
3. Write tests for components
|
|
4. Ensure accessibility (WCAG 2.1 AA)
|
|
5. Format with Prettier
|
|
6. Lint with ESLint
|
|
|
|
## 📝 License
|
|
|
|
Proprietary - All rights reserved
|
|
|
|
---
|
|
|
|
Built with ❤️ using Next.js 14 and React 18
|