feat(frontend): init Flutter project with login screen and JWT auth

- Projet Flutter créé manuellement (pubspec.yaml, structure lib/)
- Écran de connexion complet avec validation, gestion erreurs, spinner
- ApiClient Dio avec intercepteur JWT automatique
- AuthProvider (Provider) + AuthService (shared_preferences)
- Routing GoRouter avec redirection auth/non-auth
- DashboardScreen placeholder
- Rapport PFE : ajout Chapitre 5 Frontend (architecture, JWT, login)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 20:15:58 +01:00
co-authored by Claude Sonnet 4.6
parent 3816f8b8f1
commit c1dabb486d
9 changed files with 620 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ApiClient {
static const String baseUrl = 'http://192.168.100.33:8090/api';
static final Dio _dio = Dio(BaseOptions(
baseUrl: baseUrl,
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 15),
headers: {'Content-Type': 'application/json'},
))
..interceptors.add(_AuthInterceptor());
static Dio get instance => _dio;
}
class _AuthInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('jwt_token');
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
handler.next(err);
}
}
+35
View File
@@ -0,0 +1,35 @@
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'api_client.dart';
class AuthService {
static Future<Map<String, dynamic>> login(String username, String password) async {
final response = await ApiClient.instance.post('/auth/signin', data: {
'username': username,
'password': password,
});
return response.data as Map<String, dynamic>;
}
static Future<void> saveToken(String token, String role) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('jwt_token', token);
await prefs.setString('user_role', role);
}
static Future<String?> getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('jwt_token');
}
static Future<String?> getRole() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('user_role');
}
static Future<void> logout() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('jwt_token');
await prefs.remove('user_role');
}
}