Artikel ini tersedia dalam Bahasa Inggris

🇬🇧 Read in English

6 Mei 2026

🇮🇩 Bahasa Indonesia

Fleet Management Part 2: Membangun Dashboard Real-Time dengan Next.js

Panduan langkah demi langkah membangun dashboard tracking armada real-time dengan Next.js dan TypeScript. SSR, arsitektur komponen, dan optimasi performa.

4 min read

Apa itu Next.js?

Jika Anda baru mengenal Next.js, biar saya jelaskan dengan sederhana. Next.js adalah React dengan kekuatan super. React biasa berjalan sepenuhnya di browser — server mengirim halaman HTML kosong, lalu JavaScript membangun halaman di browser pengguna. Next.js bisa me-render halaman di server sebelum mengirimnya, jadi pengguna melihat konten secara instan.

Mengapa ini penting untuk dashboard armada kita? Operator kita membuka dashboard pertama kali di pagi hari, seringkali dengan WiFi kantor yang lambat. Dengan server-side rendering, mereka langsung melihat peta armada alih-alih menatap spinner loading.

SSR vs CSR vs ISR — Kapan Menggunakan Apa

StrategiCara KerjanyaCocok UntukPenggunaan Kita
SSR (Server-Side Rendering)Halaman di-render di server setiap requestData dinamis yang berubah per-requestHalaman utama dashboard
CSR (Client-Side Rendering)Halaman di-render di browserUI yang sangat interaktifInteraksi peta, update real-time
ISR (Incremental Static Regeneration)Halaman pre-built, di-regenerate berkalaKonten yang jarang berubahLaporan, profil driver

Keputusan Senior: Dashboard kita menggunakan SSR untuk loading awal (ambil data fresh dari API) lalu beralih ke CSR dengan WebSocket untuk update real-time. Ini memberikan yang terbaik dari kedua pendekatan.


Setup Proyek

npx create-next-app@latest fleet-web --typescript --eslint --src-dir
cd fleet-web

TypeScript Strict Mode — Mengapa Penting

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "forceConsistentCasingInFileNames": true
  }
}

Mengapa strict mode? Karena undefined is not a function adalah error paling umum di JavaScript. TypeScript strict menangkap bug ini saat compile time, bukan jam 2 pagi ketika operator tidak bisa melihat truk di peta.


Arsitektur Komponen

Saya mengorganisir komponen ke dalam 4 kategori:

src/ ├── components/ │ ├── ui/ # Primitif UI yang reusable dan stateless │ │ ├── Button.tsx │ │ ├── Card.tsx │ │ └── Badge.tsx │ │ │ ├── features/ # Komponen spesifik fitur dengan logika bisnis │ │ ├── fleet/ │ │ │ ├── FleetMap.tsx │ │ │ ├── VehicleCard.tsx │ │ │ └── VehicleStatusBadge.tsx │ │ └── driver/ │ │ ├── DriverList.tsx │ │ └── DriverProfile.tsx │ │ │ ├── layouts/ # Komponen layout halaman │ │ ├── DashboardLayout.tsx │ │ └── Sidebar.tsx │ │ │ └── providers/ # Context providers │ └── AuthProvider.tsx

Mengapa struktur ini? Ketika developer baru bergabung dan perlu memperbaiki bug di peta armada, mereka tahu harus mencari di components/features/fleet/. Organisasi yang jelas = onboarding lebih cepat.


Membangun Komponen Vehicle Card

Contoh komponen fitur yang terstruktur dengan baik:

// src/components/features/fleet/VehicleCard.tsx
interface Vehicle {
  id: string;
  plateNumber: string;
  driverName: string;
  status: 'active' | 'idle' | 'maintenance' | 'offline';
  fuelLevel: number;
  speed: number;
  lastUpdate: Date;
  location: {
    lat: number;
    lng: number;
    address: string;
  };
}

const STATUS_CONFIG = {
  active:      { label: 'Aktif',       color: 'green' },
  idle:        { label: 'Diam',        color: 'yellow' },
  maintenance: { label: 'Maintenance', color: 'orange' },
  offline:     { label: 'Offline',     color: 'red' },
} as const;

export default function VehicleCard({ vehicle, isSelected, onSelect }: VehicleCardProps) {
  const statusConfig = STATUS_CONFIG[vehicle.status];

  return (
    <div
      className={`vehicle-card ${isSelected ? 'selected' : ''}`}
      onClick={() => onSelect(vehicle.id)}
      role="button"
      tabIndex={0}
      aria-label={`Kendaraan ${vehicle.plateNumber}, status: ${statusConfig.label}`}
    >
      <div className="vehicle-card__header">
        <h3>{vehicle.plateNumber}</h3>
        <Badge color={statusConfig.color}>{statusConfig.label}</Badge>
      </div>
      <p>🧑‍✈️ {vehicle.driverName}</p>
      <p>📍 {vehicle.location.address}</p>
      <p>🚚 {vehicle.speed} km/h</p>
      <FuelGauge level={vehicle.fuelLevel} />
    </div>
  );
}

Perhatikan pola-pola senior di sini:

  1. Tipe TypeScript eksplisit — tidak ada any, tidak menebak
  2. Objek konfigurasi konstanSTATUS_CONFIG alih-alih rantai if/else
  3. Aksesibilitasrole, tabIndex, aria-label pada elemen interaktif

State Management: Kapan Menggunakan Apa

Tipe StateSolusiContoh
State UIuseStateSidebar buka/tutup
State UI bersamaReact ContextTema, user terautentikasi
State serverReact Query / SWRData armada, daftar driver
State real-timeWebSocket + useReducerPosisi kendaraan live

Kesalahan Umum: Menggunakan Redux untuk semua hal. Jika state Anda berasal dari API, gunakan library data-fetching seperti React Query. Library ini menangani caching, re-fetching, dan loading states.

API Service Layer

// src/services/fleet.service.ts
const API_BASE = process.env.NEXT_PUBLIC_API_URL;

export const fleetService = {
  async getVehicles(): Promise<Vehicle[]> {
    const res = await fetch(`${API_BASE}/api/vehicles`);
    if (!res.ok) throw new Error(`Gagal mengambil data kendaraan: ${res.status}`);
    return res.json();
  },
};

Mengapa service layer? Ketika endpoint API berubah, Anda update satu file — bukan 15 komponen.


Tips Optimasi Performa

1. Code Splitting dengan Dynamic Imports

import dynamic from 'next/dynamic';

const FleetMap = dynamic(() => import('@/components/features/fleet/FleetMap'), {
  loading: () => <div>Memuat peta...</div>,
  ssr: false,
});

2. Memoize Komputasi Mahal

const stats = useMemo(() => ({
  total: vehicles.length,
  active: vehicles.filter(v => v.status === 'active').length,
  lowFuel: vehicles.filter(v => v.fuelLevel < 25).length,
}), [vehicles]);

Selanjutnya

Di Part 3, kita akan membangun backend API NestJS — mesin di balik dashboard armada kita. Kita akan membahas module, controller, service, DTO, dan dependency injection.


Ini adalah Part 2 dari seri Fleet Management System. Setiap artikel membangun di atas yang sebelumnya, secara bertahap meningkatkan kompleksitas.

Lanjut Membaca

Previous article thumbnail

← Artikel Sebelumnya

Fleet Management System Part 1: Introduction & System Architecture

Artikel Selanjutnya →

Fleet Management Part 3: Backend API with NestJS

Next article thumbnail