Lewati ke konten utama

BAB 39. ROUTING

Flutter Routing — GoRouter

TemuBelajar menggunakan GoRouter untuk manajemen navigasi Flutter karena mendukung deep linking, route guard, dan redirect yang mudah diintegrasikan dengan Riverpod.


Struktur Route Flutter

/ → Redirect berdasarkan auth state
├── /login → Halaman Login
├── /change-password → Ganti Password (first login)
├── /dashboard → Dashboard utama (protected)
├── /profile → Profil pengguna
│ └── /profile/edit → Edit profil
├── /request → Daftar request
│ ├── /request/create → Buat request baru
│ └── /request/:id → Detail request
├── /booking → Daftar booking
│ └── /booking/:id → Detail booking
├── /meeting
│ ├── /meeting/check-in → Halaman Check-In
│ └── /meeting/:id → Detail sesi meeting
├── /chat
│ └── /chat/:bookingId → Ruang chat
├── /leaderboard → Halaman leaderboard
├── /teacher → Dashboard guru (role:teacher)
│ └── /teacher/monitor → Monitoring sesi
└── /settings → Pengaturan

Route Guard — Auth & Role

flowchart TD
A["🔗 Navigasi ke Route"] --> B{{"Token ada di\nSecure Storage?"}}
B -->|Tidak| C["➡️ Redirect ke /login"]
B -->|Ya| D{{"must_change_password?"}}
D -->|true| E["➡️ Redirect ke /change-password"]
D -->|false| F{{"Role Check"}}
F -->|student| G["✅ Student Routes"]
F -->|teacher| H["✅ Teacher Routes"]
F -->|admin| I["✅ Admin Routes"]
F -->|Salah role| J["❌ 403 Forbidden Page"]

style C fill:#dc2626,color:#fff
style G fill:#059669,color:#fff
style H fill:#059669,color:#fff
style I fill:#059669,color:#fff

Implementasi GoRouter

// app/router/app_router.dart

final appRouterProvider = Provider<GoRouter>((ref) {
final authState = ref.watch(authStateProvider);

return GoRouter(
initialLocation: '/dashboard',
redirect: (context, state) {
final isLoggedIn = authState.isAuthenticated;
final mustChange = authState.user?.mustChangePassword ?? false;

if (!isLoggedIn) return '/login';
if (mustChange && state.uri.path != '/change-password') {
return '/change-password';
}
return null;
},
routes: [
GoRoute(
path: '/login',
builder: (context, state) => const LoginPage(),
),
GoRoute(
path: '/change-password',
builder: (context, state) => const ChangePasswordPage(),
),
GoRoute(
path: '/dashboard',
builder: (context, state) => const DashboardPage(),
),
GoRoute(
path: '/request',
builder: (context, state) => const RequestListPage(),
routes: [
GoRoute(
path: 'create',
builder: (context, state) => const CreateRequestPage(),
),
GoRoute(
path: ':id',
builder: (context, state) => RequestDetailPage(
id: int.parse(state.pathParameters['id']!),
),
),
],
),
GoRoute(
path: '/chat/:bookingId',
builder: (context, state) => ChatPage(
bookingId: int.parse(state.pathParameters['bookingId']!),
),
),
],
);
});

Laravel API Routing

Routing API dipisah per domain dalam file terpisah, kemudian di-include ke routes/api.php:

routes/
├── api.php # Main router (include semua)
└── api/
├── auth.php # /auth/login, /auth/logout
├── profile.php # /profile, /profile/skills
├── requests.php # /requests CRUD
├── bookings.php # /bookings/accept, /reject
├── meetings.php # /meetings/check-in, /check-out
├── ratings.php # /ratings
├── leaderboard.php # /leaderboard
└── notifications.php # /notifications
// routes/api.php

Route::prefix('v1')->group(function () {
require __DIR__ . '/api/auth.php';

Route::middleware('auth:sanctum')->group(function () {
require __DIR__ . '/api/profile.php';
require __DIR__ . '/api/requests.php';
require __DIR__ . '/api/bookings.php';
require __DIR__ . '/api/meetings.php';
require __DIR__ . '/api/ratings.php';
require __DIR__ . '/api/leaderboard.php';
require __DIR__ . '/api/notifications.php';
});
});

Ringkasan Endpoint per File Route

FileMethodEndpoint
auth.phpPOST/auth/login, /auth/logout, /auth/change-password
profile.phpGET, PUT/profile, /profile/skills
requests.phpGET, POST, PUT, DELETE/requests, /requests/{id}
bookings.phpPOST/bookings/{id}/accept, /reject, /reschedule
meetings.phpPOST/meetings/check-in, /check-out, /{id}/summary
ratings.phpPOST/ratings
leaderboard.phpGET/leaderboard
notifications.phpGET, PUT/notifications, /notifications/{id}/read