Documentation

Smart Mobility Predictor - Developer Guide

Quick Start

Prerequisites

  • Node.js 18+
  • npm or yarn
  • Git
  • Code editor (VS Code recommended)

Setup

bash
# Clone repository git clone <repo-url> cd smart-mobility-predictor # Install dependencies npm install # Run development server npm run dev # Open http://localhost:3000

Architecture Overview

Layer Model

┌─────────────────────────────────────┐
│      User Interface (React)          │
│  - Components & Pages                │
│  - Form inputs & Results display     │
└────────────────────┬────────────────┘
                     │
┌────────────────────▼────────────────┐
│   State Management & Context         │
│  - useLanguage (i18n)               │
│  - useTheme (light/dark)            │
│  - useState (form state)            │
└────────────────────┬────────────────┘
                     │
┌────────────────────▼────────────────┐
│      Utilities & Services            │
│  - i18n (translations)              │
│  - currency (TND formatting)        │
│  - ml-engine (predictions)          │
│  - types (TypeScript)               │
└────────────────────┬────────────────┘
                     │
┌────────────────────▼────────────────┐
│       API Routes (Next.js)           │
│  - /api/predict - ML predictions    │
│  - Validation & error handling      │
└────────────────────┬────────────────┘
                     │
┌────────────────────▼────────────────┐
│      External Services               │
│  - Browser localStorage             │
│  - Intl API (formatting)            │
└─────────────────────────────────────┘

Component Development

Creating a New Component

1. Define Types

typescript
// lib/types.ts export interface MyFeature { id: string; name: string; data: Record<string, unknown>; }

2. Create Component

typescript
// components/my-feature.tsx 'use client'; import { MyFeature } from '@/lib/types'; import { useTranslation } from '@/lib/language-context'; import { Card } from '@/components/ui/card'; interface MyFeatureProps { feature: MyFeature; onUpdate: (feature: MyFeature) => void; } export function MyFeature({ feature, onUpdate }: MyFeatureProps) { const t = useTranslation(); return ( <Card className="p-6"> <h2 className="text-lg font-semibold text-foreground"> {t('feature.title')} </h2> <p className="text-sm text-muted-foreground mt-2"> {t('feature.description')} </p> </Card> ); }

3. Add Translations

typescript
// lib/i18n.ts export const translations = { en: { feature: { title: 'My Feature', description: 'Feature description', }, }, fr: { feature: { title: 'Ma Fonctionnalité', description: 'Description de la fonctionnalité', }, }, };

4. Use in Page

typescript
// app/page.tsx import { MyFeature } from '@/components/my-feature'; export default function Home() { return ( <div className="space-y-6"> <MyFeature feature={myData} onUpdate={handleUpdate} /> </div> ); }

i18n (Internationalization) Guide

Supported Languages

  • English (en) - Default
  • French (fr) - Complete translations

Adding New Strings

  1. Open lib/i18n.ts
  2. Add to both EN and FR objects:
typescript
export const translations = { en: { newFeature: { title: 'My Title', description: 'My description', }, }, fr: { newFeature: { titre: 'Mon Titre', description: 'Ma description', }, }, };
  1. Use in component:
typescript
const t = useTranslation(); <h1>{t('newFeature.title')}</h1>

Translation Keys Hierarchy

header          - Page header & navigation
hero            - Hero section
main            - Main content
form            - Form labels & inputs
results         - Results display
footer          - Footer content
messages        - Error & success messages
zones           - Tunis zone names

Best Practices

  • Keep keys short and descriptive
  • Group related keys together
  • Maintain consistent capitalization
  • Don't hard-code user-facing strings

Currency (TND) Guide

Using Currency Functions

Format a Number

typescript
import { formatTND, formatSimpleTND } from '@/lib/currency'; // Full formatting with locale formatTND(150.5); // "د.ت 150.500" (locale-aware) // Simple formatting formatSimpleTND(150.5); // "د.ت 150.500" // Null safe formatTND(null); // "د.ت0.000" formatTND(undefined); // "د.ت0.000"

Calculate Differences

typescript
import { calculateSavings } from '@/lib/currency'; const savings = calculateSavings(100, 75); // { difference: 25, percentageSavings: 25 }

Parse Currency Strings

typescript
import { parseTND } from '@/lib/currency'; const amount = parseTND('د.ت 50.500'); // Returns: 50.5

Currency Format Rules

  • Symbol: د.ت (Right-to-left ready)
  • Decimals: Always 3 places
  • Locale: ar-TN (Tunisia)
  • Code: TND

Example Usage in Components

tsx
import { formatTND } from '@/lib/currency'; import { useTranslation } from '@/lib/language-context'; export function PriceDisplay({ price }: { price: number }) { const t = useTranslation(); return ( <div> <p className="text-sm text-muted-foreground"> {t('results.estimatedCost')} </p> <p className="text-2xl font-bold text-foreground"> {formatTND(price)} </p> </div> ); }

ML Engine Development

Understanding the Models

Regression (Travel Time)

typescript
// Input variables - distance: number (km) - weather: WeatherType - traffic: TrafficState - hour: number (0-23) - weather_intensity: number (0-1) // Output - estimatedTime: number (minutes) - confidence: number (0-100) - confidence_interval: { lower, upper }

Classification (Traffic State)

typescript
// Input variables - current_speed: number (km/h) - speed_limit: number (km/h) - vehicle_density: number (cars/km) // Output - state: 'fluide' | 'normal' | 'dense' | 'saturated' - probability: number (0-100) - stateDistribution: { fluide, normal, dense, saturated }

Clustering (Zone Profiling)

typescript
// Input variables - zone_population: number - average_density: number - congestion_pattern: number[] - business_hours_activity: number // Output - clusterId: number - clusterName: string - characteristics: ZoneCharacteristics - silhouetteScore: number (0-1)

Modifying ML Logic

typescript
// lib/ml-engine.ts export function predictTrafficState( currentSpeed: number, speedLimit: number, vehicleDensity: number ): ClassificationPrediction { // Add your logic here const speedRatio = currentSpeed / speedLimit; if (speedRatio > 0.9) return FLUIDE_PREDICTION; if (speedRatio > 0.6) return NORMAL_PREDICTION; if (speedRatio > 0.3) return DENSE_PREDICTION; return SATURATED_PREDICTION; }

API Development

Creating API Routes

Structure

typescript
// app/api/[route]/route.ts import { NextRequest, NextResponse } from 'next/server'; export async function POST(request: NextRequest) { try { const body = await request.json(); // Validate input if (!body.required_field) { return NextResponse.json( { success: false, error: 'Missing required field' }, { status: 400 } ); } // Process request const result = processRequest(body); // Return response return NextResponse.json({ success: true, data: result }); } catch (error) { return NextResponse.json( { success: false, error: error instanceof Error ? error.message : 'Unknown error' }, { status: 500 } ); } }

Testing API Routes

bash
# Using curl curl -X POST http://localhost:3000/api/predict \ -H "Content-Type: application/json" \ -d '{"origin": {...}, "destination": {...}}' # Using fetch in browser console fetch('/api/predict', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ /* data */ }) }) .then(r => r.json()) .then(console.log) .catch(console.error)

Performance Optimization

Code Splitting

typescript
// Lazy load heavy components import dynamic from 'next/dynamic'; const PredictionResults = dynamic( () => import('@/components/prediction-results'), { loading: () => <div>Loading...</div> } );

Memoization

typescript
import React from 'react'; export const MemoizedComponent = React.memo(function Component(props) { return <div>{props.children}</div>; });

Image Optimization

tsx
import Image from 'next/image'; <Image src="/logo.png" alt="Logo" width={40} height={40} priority />

Data Fetching

typescript
// Use SWR for client-side data import useSWR from 'swr'; const { data, error, isLoading } = useSWR('/api/predict', fetcher);

Testing Guide

Unit Tests

typescript
// components/my-component.test.tsx import { render, screen } from '@testing-library/react'; import { MyComponent } from './my-component'; describe('MyComponent', () => { it('renders correctly', () => { render(<MyComponent />); expect(screen.getByText('Expected text')).toBeInTheDocument(); }); });

Integration Tests

typescript
// app/api/predict.test.ts describe('POST /api/predict', () => { it('returns predictions', async () => { const response = await fetch('/api/predict', { method: 'POST', body: JSON.stringify({ /* test data */ }), }); const data = await response.json(); expect(data.success).toBe(true); }); });

Debugging

Debug Console Logs

typescript
// Log with context console.log('[v0] User data received:', userData); console.log('[v0] API call starting with params:', params); console.log('[v0] Component rendered with props:', props); console.log('[v0] Error occurred in function:', error.message);

Browser DevTools

javascript
// Check localStorage localStorage.getItem('smart-mobility-language') // Check API response fetch('/api/predict', { /* ... */ }) .then(r => r.json()) .then(console.log) // Check component state React DevTools in Chrome/Firefox

Network Debugging

javascript
// Monitor fetch requests window.addEventListener('fetch', (event) => { console.log('Fetch:', event.request.url); });

Error Handling

API Error Pattern

typescript
try { const response = await fetch('/api/predict', options); if (!response.ok) { const error = await response.json(); throw new Error(error.message || 'API error'); } return await response.json(); } catch (err) { console.error('[v0] API Error:', err); return null; }

Null Safety Pattern

typescript
// Safe property access const value = obj?.property?.nested?.value ?? defaultValue; // Safe method calls const result = array?.map(item => item.name) ?? []; // Safe numeric operations const fixed = number != null ? number.toFixed(3) : '0.000';

Code Style Guide

TypeScript

typescript
// Use interfaces for object shapes interface User { id: string; name: string; email: string; } // Use enums for fixed values enum Status { PENDING = 'pending', COMPLETE = 'complete', ERROR = 'error', } // Use strict null checks const value: string | null = getData(); if (value !== null) { console.log(value); }

React Components

typescript
// Use named exports export function MyComponent() { /* ... */ } // Define prop interfaces interface MyComponentProps { title: string; onSubmit: (data: Data) => void; } // Use proper hooks order function Component(props: Props) { const state = useState(); const effect = useEffect(() => {}, []); const translation = useTranslation(); return <div>{state}</div>; }

Styling

typescript
// Use Tailwind classes className="flex items-center justify-between p-4 gap-2" // Use semantic naming className="flex items-center gap-2 p-4 rounded-lg border border-primary/20" // Avoid arbitrary values // ❌ className="p-[25px]" // ✅ className="p-6"

Git Workflow

Commit Messages

bash
git commit -m "feat: add language switcher component" git commit -m "fix: null check in currency formatter" git commit -m "docs: add implementation guide" git commit -m "refactor: simplify prediction logic"

Branch Naming

bash
feature/add-currency-support bugfix/fix-language-persistence docs/add-deployment-guide chore/update-dependencies

Deployment Checklist

Before Push

  • Code compiles without errors
  • No TypeScript errors
  • ESLint passes
  • All features tested
  • Commit message is descriptive
  • Documentation updated

After Deployment

  • Verify in production
  • Check analytics
  • Monitor error logs
  • Test in multiple browsers
  • Check mobile responsiveness

Common Patterns

Using Translation Hook

typescript
import { useTranslation } from '@/lib/language-context'; export function MyComponent() { const t = useTranslation(); return <h1>{t('feature.title')}</h1>; }

Using Currency Formatter

typescript
import { formatTND } from '@/lib/currency'; export function Price({ amount }: { amount: number }) { return <p>{formatTND(amount)}</p>; }

API Call Pattern

typescript
const handleSubmit = async (data: Data) => { setLoading(true); try { const response = await fetch('/api/predict', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); const result = await response.json(); if (result.success) { setData(result.data); } else { setError(result.error); } } catch (err) { setError('Network error'); } finally { setLoading(false); } };

Resources


Support

Need help? Check:

  1. Implementation Guide: /docs/IMPLEMENTATION_GUIDE.md
  2. Code comments
  3. Type definitions in lib/types.ts
  4. Existing component examples

Last Updated: January 23, 2026
Version: 1.0.0