Merge pull request 'refresh token ability added to project' (#65) from feat_refresh_token into main
Reviewed-on: https://repo.ravanertebat.com/TM/tm_app/pulls/65
This commit is contained in:
@@ -28,7 +28,7 @@ List<SingleChildWidget> get providersRemote {
|
||||
|
||||
List<SingleChildWidget> get cores {
|
||||
return [
|
||||
Provider(create: (context) => NetworkManager()),
|
||||
Provider(create: (context) => NetworkManager(context.read())),
|
||||
ChangeNotifierProvider(create: (context) => ThemeProvider()),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:tm_app/data/services/model/login_response/login_response_model.dart';
|
||||
|
||||
import '../config/app_config.dart';
|
||||
import '../utils/logger.dart';
|
||||
@@ -13,11 +14,14 @@ class NetworkManager {
|
||||
final Dio mainDio;
|
||||
final NetworkConnectivity _connectivity = NetworkConnectivity();
|
||||
bool _interceptorsAdded = false;
|
||||
final SharedPreferences _prefs;
|
||||
|
||||
NetworkManager()
|
||||
NetworkManager(this._prefs)
|
||||
: mainDio = Dio(
|
||||
BaseOptions(
|
||||
baseUrl: AppConfig.apiBaseUrl,
|
||||
connectTimeout: const Duration(seconds: 10),
|
||||
receiveTimeout: const Duration(seconds: 10),
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
@@ -33,7 +37,10 @@ class NetworkManager {
|
||||
final requestInterceptor = InterceptorsWrapper(
|
||||
onRequest: (options, handler) {
|
||||
appLogger.info('🌐 Request: ${options.method} ${options.path}');
|
||||
// appLogger.info('🌐 Headers: ${options.headers}');
|
||||
String? token = _prefs.getString('bearer');
|
||||
if (token != null) {
|
||||
options.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
return handler.next(options);
|
||||
},
|
||||
onResponse: (response, handler) {
|
||||
@@ -43,11 +50,18 @@ class NetworkManager {
|
||||
|
||||
return handler.next(response);
|
||||
},
|
||||
onError: (error, handler) {
|
||||
onError: (error, handler) async {
|
||||
appLogger.error(
|
||||
'❌ Error: ${error.message} - ${error.requestOptions.path}',
|
||||
);
|
||||
appLogger.error('❌ Error type: ${error.type}');
|
||||
if (error.response?.statusCode == 401) {
|
||||
final newAccessToken = await refreshToken();
|
||||
if (newAccessToken != null) {
|
||||
mainDio.options.headers['Authorization'] = 'Bearer $newAccessToken';
|
||||
return handler.resolve(await mainDio.fetch(error.requestOptions));
|
||||
}
|
||||
}
|
||||
return handler.next(error);
|
||||
},
|
||||
);
|
||||
@@ -75,18 +89,12 @@ class NetworkManager {
|
||||
);
|
||||
}
|
||||
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
Dio dioInstance = mainDio;
|
||||
|
||||
Future<Response> makeApiCall(String token) async {
|
||||
final headers =
|
||||
token.isEmpty
|
||||
? <String, String>{}
|
||||
: {'Authorization': 'Bearer $token'};
|
||||
|
||||
final options = Options(
|
||||
headers: headers,
|
||||
validateStatus: (status) => status != null && status < 500,
|
||||
validateStatus:
|
||||
(status) => status != null && status >= 200 && status < 300,
|
||||
);
|
||||
|
||||
switch (method.toUpperCase()) {
|
||||
@@ -133,7 +141,7 @@ class NetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
String? bearerToken = prefs.getString('bearer');
|
||||
String? bearerToken = _prefs.getString('bearer');
|
||||
// String? url = prefs.getString('url');
|
||||
|
||||
// appLogger.info('🔗 Base URL: ${url ?? 'NOT SET'}');
|
||||
@@ -297,4 +305,42 @@ class NetworkManager {
|
||||
|
||||
return 'Unknown error';
|
||||
}
|
||||
|
||||
/// Refresh the access token using the refresh token
|
||||
Future<String?> refreshToken() async {
|
||||
try {
|
||||
final refreshToken = _prefs.getString('refresh_token');
|
||||
if (refreshToken == null) {
|
||||
appLogger.error('❌ No refresh token available');
|
||||
return null;
|
||||
}
|
||||
|
||||
final result = await makeRequest<LoginResponseModel>(
|
||||
'/api/v1/profile/refresh-token',
|
||||
(json) => LoginResponseModel.fromJson(json),
|
||||
method: 'POST',
|
||||
data: {'refresh_token': refreshToken},
|
||||
);
|
||||
|
||||
if (result is Ok<LoginResponseModel>) {
|
||||
final loginResponse = result.value;
|
||||
final newAccessToken = loginResponse.data.accessToken;
|
||||
final newRefreshToken = loginResponse.data.refreshToken;
|
||||
|
||||
if (newAccessToken != null) {
|
||||
await _prefs.setString('bearer', newAccessToken);
|
||||
if (newRefreshToken != null) {
|
||||
await _prefs.setString('refresh_token', newRefreshToken);
|
||||
}
|
||||
appLogger.info('✅ Token refreshed successfully');
|
||||
return newAccessToken;
|
||||
}
|
||||
} else if (result is Error<LoginResponseModel>) {
|
||||
appLogger.error('❌ Token refresh failed: ${result.error}');
|
||||
}
|
||||
} catch (e) {
|
||||
appLogger.error('❌ Token refresh error: $e');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,10 @@ class AuthService {
|
||||
if (result is Ok<LoginResponseModel>) {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final token = result.value.data.accessToken;
|
||||
final refreshToken = result.value.data.refreshToken;
|
||||
|
||||
await prefs.setString('bearer', token!);
|
||||
await prefs.setString('refresh_token', refreshToken!);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+11
-2
@@ -3,6 +3,8 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:provider/single_child_widget.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:tm_app/core/config/dependencies.dart';
|
||||
import 'package:tm_app/core/theme/theme_provider.dart';
|
||||
|
||||
@@ -10,15 +12,22 @@ import 'core/routes/app_routes.dart';
|
||||
import 'core/theme/colors.dart';
|
||||
import 'core/utils/logger.dart';
|
||||
|
||||
void main() {
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
// Initialize the logger
|
||||
appLogger.init();
|
||||
|
||||
// Log app start
|
||||
appLogger.info('🚀 Starting TM App...');
|
||||
// appLogger.logNavigation('Home', 'Login');
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
runApp(MultiProvider(providers: [...providersRemote], child: const MyApp()));
|
||||
List<SingleChildWidget> providers = [
|
||||
Provider(create: (context) => prefs),
|
||||
...providersRemote,
|
||||
];
|
||||
|
||||
runApp(MultiProvider(providers: providers, child: const MyApp()));
|
||||
}
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
|
||||
Reference in New Issue
Block a user