import 'dart:developer'; import 'package:dio/dio.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../../injection.dart'; import '../../../presentation/router/app_router.dart'; import '../../../presentation/router/app_router.gr.dart'; import '../../constant/local_storage_key.dart'; /// Token login ditolak server: HTTP `401`, atau `304` dengan `entity` /// `auth_handler` (ยง2.2). Belum ada refresh token, jadi customer harus login /// ulang. /// /// Bukan `403`: `PIN_NOT_SET` dan `TRANSFER_BLOCKED` juga memakai `403`. bool isTokenRejected(Response response) { if (response.statusCode == 401) return true; final body = response.data; if (body is! Map) return false; final errors = body['errors']; if (errors is! List || errors.isEmpty || errors.first is! Map) return false; final first = errors.first as Map; return first['code']?.toString() == '304' && first['entity'] == 'auth_handler'; } /// Menghapus sesi dan membuka halaman login bila token yang dipakai request /// ditolak. `validateStatus` menerima semua status, jadi pengecekan ada di /// [onResponse], bukan `onError`. class UnauthorizedInterceptor extends Interceptor { @override void onResponse(Response response, ResponseInterceptorHandler handler) async { try { if (isTokenRejected(response)) await _handleTokenRejected(response); } finally { handler.next(response); } } Future _handleTokenRejected(Response response) async { final prefs = getIt(); final token = prefs.getString(LocalStorageKey.token); // Hanya token yang sedang dipakai: abaikan request tanpa login dan jawaban // basi dari token lama setelah customer login lagi. final sentAuthorization = response.requestOptions.headers['Authorization']; if (token == null || sentAuthorization != 'Bearer $token') return; log('token rejected', name: 'UnauthorizedInterceptor'); await prefs.remove(LocalStorageKey.token); await prefs.remove(LocalStorageKey.user); getIt().replaceAll([LoginRoute()]); } }