From ace087a2a833fb16d43622dfaff02aff016b883e Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 21 May 2024 16:50:05 +0200 Subject: [PATCH 1/9] :construction: show pdf card --- .../users/repositories/user_repository.dart | 6 +---- .../views/forms/link_account_form.dart | 12 ++++----- .../school_space/views/school_space_page.dart | 4 +++ .../lib/users/cubit/user_cubit.dart | 26 +++++++++++++++---- .../lib/users/cubit/user_state.dart | 14 ++++++++++ frontend/app_student/lib/utils/global.dart | 6 ++--- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/frontend/app_student/lib/api/users/repositories/user_repository.dart b/frontend/app_student/lib/api/users/repositories/user_repository.dart index 4e7a058..185c57a 100644 --- a/frontend/app_student/lib/api/users/repositories/user_repository.dart +++ b/frontend/app_student/lib/api/users/repositories/user_repository.dart @@ -17,7 +17,7 @@ class UserRepository { Future getUser() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); - String? name = prefs.getString('name'); + String name = prefs.getString('name')!; String? className = prefs.getString('className'); String? ine = prefs.getString('ine'); String? birthDate = prefs.getString('birthDate'); @@ -31,10 +31,6 @@ class UserRepository { absencesFile = await getAbsences(studentId); } - if (name == null) { - throw Exception('User name not found'); - } - DateTime bd = DateTime.now(); if (birthDate != null) { bd = DateFormat('dd/MM/yyyy').parse(birthDate); diff --git a/frontend/app_student/lib/school_space/views/forms/link_account_form.dart b/frontend/app_student/lib/school_space/views/forms/link_account_form.dart index 842762d..abc24aa 100644 --- a/frontend/app_student/lib/school_space/views/forms/link_account_form.dart +++ b/frontend/app_student/lib/school_space/views/forms/link_account_form.dart @@ -15,9 +15,10 @@ class LinkAccountForm extends StatelessWidget { @override Widget build(BuildContext context) { final formKey = GlobalKey(); - String ine = ''; - String birthDate = ''; - final birthDateController = TextEditingController(); + String ine = '050223219JD'; + String birthDate = '07/12/2002'; // Set your default birth date here + final birthDateController = TextEditingController(text: birthDate); + final ineController = TextEditingController(text: ine); return CustomLayout( appBar: HeaderLogo(appBarHeight: Global.screenHeight * 0.3), @@ -29,6 +30,7 @@ class LinkAccountForm extends StatelessWidget { child: Column( children: [ TextFormField( + controller: ineController, decoration: const InputDecoration(labelText: 'INE'), validator: (value) { if (value == null || value.isEmpty) { @@ -41,6 +43,7 @@ class LinkAccountForm extends StatelessWidget { }, ), TextFormField( + controller: birthDateController, decoration: InputDecoration( labelText: 'Birth Date', suffixIcon: IconButton( @@ -70,7 +73,6 @@ class LinkAccountForm extends StatelessWidget { onSaved: (value) { birthDate = value!; }, - controller: birthDateController, ), ], ), @@ -87,8 +89,6 @@ class LinkAccountForm extends StatelessWidget { } }, ), - // Add your bottomBar here if you have one - // bottomBar: YourBottomBar(), ); } } diff --git a/frontend/app_student/lib/school_space/views/school_space_page.dart b/frontend/app_student/lib/school_space/views/school_space_page.dart index bfb4da3..aad257a 100644 --- a/frontend/app_student/lib/school_space/views/school_space_page.dart +++ b/frontend/app_student/lib/school_space/views/school_space_page.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import '../../api/users/models/user_model.dart'; import '../../menu/menu_view.dart'; import '../../shared_components/header_logo.dart'; import '../../shared_components/header_title.dart'; @@ -22,11 +23,13 @@ class SchoolSpacePage extends StatefulWidget { class SchoolSpacePageState extends State { late final UserCubit userCubit; + late final UserModel user; @override void initState() { super.initState(); userCubit = context.read(); + userCubit.fetchUser(); } @override @@ -35,6 +38,7 @@ class SchoolSpacePageState extends State { appBar: HeaderLogo(appBarHeight: Global.screenHeight * 0.3), body: BlocBuilder( builder: (context, state) { + print(state); if (state is UserLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is UserLoggedIn) { diff --git a/frontend/app_student/lib/users/cubit/user_cubit.dart b/frontend/app_student/lib/users/cubit/user_cubit.dart index d1f3c30..f1908e0 100644 --- a/frontend/app_student/lib/users/cubit/user_cubit.dart +++ b/frontend/app_student/lib/users/cubit/user_cubit.dart @@ -4,6 +4,7 @@ import 'package:app_student/api/class_groups/models/class_group_model.dart'; import 'package:app_student/api/users/models/user_model.dart'; import 'package:bloc/bloc.dart'; import 'package:flutter/foundation.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import '../../api/users/repositories/user_repository.dart'; import '../../utils/global.dart'; @@ -26,7 +27,7 @@ class UserCubit extends Cubit { user.ine!.isNotEmpty && user.birthDate != null && user.studentId != null) { - emit(UserLoaded(user)); + emit(UserLoggedIn(user)); } else if (user.ine == null || (user.ine != null && user.ine!.isEmpty) || user.birthDate == null) { @@ -60,9 +61,10 @@ class UserCubit extends Cubit { emit(UserLoading()); try { final studentId = await userRepository.login(username, password); - Global.setIne(username); - Global.setBirthDate(password); - Global.setStudentId(studentId); + + await Global.setStudentId(studentId); + await Global.setIne(username); + await Global.setBirthDate(password); final user = await userRepository.getUser(); emit(UserLoggedIn(user)); } catch (e) { @@ -79,11 +81,25 @@ class UserCubit extends Cubit { if (kDebugMode) { print(marks.path); } + emit(UserMarksLoaded(user, marks)); + } else { + throw Exception('No student ID found in SharedPreferences'); + } + } catch (e) { + emit(UserError(e.toString())); + } + } + + Future fetchAbsences() async { + emit(UserLoading()); + try { + final user = await userRepository.getUser(); + if (user.studentId != null) { final File absences = await userRepository.getAbsences(user.studentId!); if (kDebugMode) { print(absences.path); } - emit(UserLoaded(user)); + emit(UserAbsencesLoaded(user, absences)); } else { throw Exception('No student ID found in SharedPreferences'); } diff --git a/frontend/app_student/lib/users/cubit/user_state.dart b/frontend/app_student/lib/users/cubit/user_state.dart index 905c622..86c453d 100644 --- a/frontend/app_student/lib/users/cubit/user_state.dart +++ b/frontend/app_student/lib/users/cubit/user_state.dart @@ -38,3 +38,17 @@ class UserLoggedIn extends UserState { UserLoggedIn(this.user); } + +class UserMarksLoaded extends UserState { + final UserModel user; + final File marks; + + UserMarksLoaded(this.user, this.marks); +} + +class UserAbsencesLoaded extends UserState { + final UserModel user; + final File absences; + + UserAbsencesLoaded(this.user, this.absences); +} diff --git a/frontend/app_student/lib/utils/global.dart b/frontend/app_student/lib/utils/global.dart index 5661e67..b7fc80e 100644 --- a/frontend/app_student/lib/utils/global.dart +++ b/frontend/app_student/lib/utils/global.dart @@ -14,7 +14,7 @@ class Global { return await SharedPreferences.getInstance(); } - static Future get studentId async { + static Future get getStudentId async { final prefs = await SharedPreferences.getInstance(); return prefs.getInt('studentId'); } @@ -24,7 +24,7 @@ class Global { prefs.setInt('studentId', value); } - static Future get ine async { + static Future get getIne async { final prefs = await SharedPreferences.getInstance(); return prefs.getString('ine') ?? ''; } @@ -34,7 +34,7 @@ class Global { prefs.setString('ine', value); } - static Future get birthDate async { + static Future get getBirthdate async { final prefs = await SharedPreferences.getInstance(); return prefs.getString('birthDate') ?? ''; } From 461a803cac2d6476660205bb24a72d0229c76f17 Mon Sep 17 00:00:00 2001 From: jules Date: Wed, 22 May 2024 17:08:44 +0200 Subject: [PATCH 2/9] :construction: refactor user/ added documents --- .../repositories/account_repository.dart | 64 ------- .../documents/entities/document_entity.dart | 20 +++ .../api/documents/models/document_model.dart | 25 +++ .../lib/api/users/entities/user_entity.dart | 46 +++-- .../lib/api/users/models/user_model.dart | 41 ++++- .../users/repositories/user_repository.dart | 164 +++++++----------- .../class_groups/views/class_group_page.dart | 92 +++++----- .../lib/login/cubit/login_cubit.dart | 17 +- frontend/app_student/lib/main.dart | 28 ++- frontend/app_student/lib/main_dev.dart | 41 ++++- frontend/app_student/lib/menu/menu_view.dart | 2 +- .../lib/profil/views/profil_page.dart | 15 +- frontend/app_student/lib/routes.dart | 124 ++++--------- .../views/forms/link_account_form.dart | 7 +- .../lib/school_space/views/pdf_view_page.dart | 4 +- .../school_space/views/school_space_page.dart | 38 +--- .../lib/users/cubit/user_cubit.dart | 69 +++----- .../lib/users/cubit/user_state.dart | 12 +- frontend/app_student/lib/utils/global.dart | 36 ++-- .../views/week_schedule_page.dart | 97 ++++------- 20 files changed, 423 insertions(+), 519 deletions(-) delete mode 100644 frontend/app_student/lib/api/account/repositories/account_repository.dart create mode 100644 frontend/app_student/lib/api/documents/entities/document_entity.dart create mode 100644 frontend/app_student/lib/api/documents/models/document_model.dart diff --git a/frontend/app_student/lib/api/account/repositories/account_repository.dart b/frontend/app_student/lib/api/account/repositories/account_repository.dart deleted file mode 100644 index 0fc90e4..0000000 --- a/frontend/app_student/lib/api/account/repositories/account_repository.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'dart:io'; -import 'package:app_student/api/api_service.dart'; -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:path_provider/path_provider.dart'; - -import '../../../utils/global.dart'; - -class AccountRepository { - final ApiService apiService; - - AccountRepository({required this.apiService}); - - Future login(String username, String password) async { - final response = await http.post( - Uri.parse('${apiService.apiUrl}/api/student/login'), - body: {'username': username, 'password': password}, - ); - - if (response.statusCode == 200) { - final data = jsonDecode(response.body); - final studentId = (data['studentId']); - Global.setStudentId(studentId); - return studentId; - } else { - throw Exception('Failed to login'); - } - } - - Future getMarks(int studentId) async { - final response = await http.get( - Uri.parse('${apiService.apiUrl}/api/student/marks/$studentId'), - ); - - if (response.statusCode == 200) { - return _savePdfFile(response.bodyBytes, 'marks.pdf'); - } else { - throw Exception('Failed to get marks'); - } - } - - Future getAbsences(int studentId) async { - final response = await http.get( - Uri.parse('${apiService.apiUrl}/api/student/absences/$studentId'), - ); - - if (response.statusCode == 200) { - return _savePdfFile(response.bodyBytes, 'absences.pdf'); - } else { - throw Exception('Failed to get absences'); - } - } - - Future _savePdfFile(List bytes, String filename) async { - final directory = await getApplicationDocumentsDirectory(); - final path = directory.path; - final file = File('$path/$filename'); - - // Écrire les bytes de la réponse dans le fichier - await file.writeAsBytes(bytes); - - return file; - } -} diff --git a/frontend/app_student/lib/api/documents/entities/document_entity.dart b/frontend/app_student/lib/api/documents/entities/document_entity.dart new file mode 100644 index 0000000..e8bc267 --- /dev/null +++ b/frontend/app_student/lib/api/documents/entities/document_entity.dart @@ -0,0 +1,20 @@ +import 'dart:io'; + +class DocumentEntity { + final String title; + final File? file; + + DocumentEntity({required this.title, required this.file}); + + Map toJson() => { + 'title': title, + 'file': file!.path, + }; + + factory DocumentEntity.fromJson(Map json) { + return DocumentEntity( + title: json['title'], + file: File(json['file']), + ); + } +} diff --git a/frontend/app_student/lib/api/documents/models/document_model.dart b/frontend/app_student/lib/api/documents/models/document_model.dart new file mode 100644 index 0000000..d5added --- /dev/null +++ b/frontend/app_student/lib/api/documents/models/document_model.dart @@ -0,0 +1,25 @@ +import 'dart:io'; +import 'package:app_student/api/documents/entities/document_entity.dart'; + +class DocumentModel { + final DocumentEntity entity; + + DocumentModel({required this.entity}); + + String get title => entity.title; + + File? get file => entity.file; + + factory DocumentModel.fromEntity(DocumentEntity entity) { + return DocumentModel( + entity: entity, + ); + } + + DocumentEntity toEntity() { + return DocumentEntity( + title: title, + file: file, + ); + } +} diff --git a/frontend/app_student/lib/api/users/entities/user_entity.dart b/frontend/app_student/lib/api/users/entities/user_entity.dart index 38d03a7..ffcecbe 100644 --- a/frontend/app_student/lib/api/users/entities/user_entity.dart +++ b/frontend/app_student/lib/api/users/entities/user_entity.dart @@ -1,20 +1,40 @@ -import 'dart:io'; +import '../../documents/entities/document_entity.dart'; class UserEntity { - final String? ine; - final String firstName; - final DateTime? birthDate; - final String? className; - final int? studentId; - final File? marksFile; - final File? absencesFile; + String? ine; + String? firstName; + DateTime? birthDate; + String? className; + int? studentId; + List? documents; UserEntity( - {required this.ine, - required this.firstName, - required this.birthDate, + {this.ine, + this.firstName, + this.birthDate, this.className, this.studentId, - this.marksFile, - this.absencesFile}); + this.documents}); + + Map toJson() => { + 'firstName': firstName, + 'className': className, + 'ine': ine, + 'birthDate': birthDate?.toIso8601String(), + 'studentId': studentId, + 'documents': documents?.map((doc) => doc.toJson()).toList(), + }; + + factory UserEntity.fromJson(Map json) => UserEntity( + firstName: json['firstName'], + className: json['className'], + ine: json['ine'], + birthDate: json['birthDate'] != null + ? DateTime.parse(json['birthDate']) + : null, + studentId: json['studentId'], + documents: (json['documents'] as List?) + ?.map((doc) => DocumentEntity.fromJson(doc)) + .toList(), + ); } diff --git a/frontend/app_student/lib/api/users/models/user_model.dart b/frontend/app_student/lib/api/users/models/user_model.dart index 35a925d..e7d3d7e 100644 --- a/frontend/app_student/lib/api/users/models/user_model.dart +++ b/frontend/app_student/lib/api/users/models/user_model.dart @@ -1,25 +1,52 @@ -import 'dart:io'; - +import 'package:app_student/api/documents/models/document_model.dart'; import 'package:app_student/api/users/entities/user_entity.dart'; class UserModel { - final UserEntity entity; + UserEntity entity; UserModel({required this.entity}); - String get firstName => entity.firstName; + String? get firstName => entity.firstName; - String get name => entity.firstName; + set firstName(String? value) => entity.firstName = value; DateTime? get birthDate => entity.birthDate; + set birthDate(DateTime? value) => entity.birthDate = value; + String? get className => entity.className; + set className(String? value) => entity.className = value; + String? get ine => entity.ine; + set ine(String? value) => entity.ine = value; + int? get studentId => entity.studentId; - File? get marksFile => entity.marksFile; + set studentId(int? value) => entity.studentId = value; + + List? get documents => entity.documents + ?.map((documentEntity) => DocumentModel.fromEntity(documentEntity)) + .toList(); + + set documents(List? value) { + entity.documents = value?.map((model) => model.toEntity()).toList(); + } + + Map toJson() => { + 'entity': entity.toJson(), + }; + + factory UserModel.fromJson(Map json) => UserModel( + entity: json['entity'] != null + ? UserEntity.fromJson(json['entity']) + : UserEntity(), + ); - File? get absencesFile => entity.absencesFile; + // fait un tostring de user custom genre User : {firstName: 'toto', birthDate: '2022-01-01', className: '3A', ine: '123456789 + @override + String toString() { + return 'User : {firstName: $firstName, birthDate: $birthDate, className: $className, ine: $ine, studentId: $studentId, documents: $documents}'; + } } diff --git a/frontend/app_student/lib/api/users/repositories/user_repository.dart b/frontend/app_student/lib/api/users/repositories/user_repository.dart index 185c57a..518b014 100644 --- a/frontend/app_student/lib/api/users/repositories/user_repository.dart +++ b/frontend/app_student/lib/api/users/repositories/user_repository.dart @@ -1,11 +1,10 @@ import 'dart:convert'; import 'dart:io'; import 'package:app_student/api/users/models/user_model.dart'; -import 'package:intl/intl.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import '../../../utils/global.dart'; import '../../api_service.dart'; +import '../../documents/entities/document_entity.dart'; import '../entities/user_entity.dart'; import 'package:http/http.dart' as http; @@ -14,83 +13,29 @@ class UserRepository { UserRepository({required this.apiService}); - Future getUser() async { - final SharedPreferences prefs = await SharedPreferences.getInstance(); - - String name = prefs.getString('name')!; - String? className = prefs.getString('className'); - String? ine = prefs.getString('ine'); - String? birthDate = prefs.getString('birthDate'); - int? studentId = prefs.getInt('studentId'); - - File marksFile = File(''); - File absencesFile = File(''); - - if (studentId != null) { - marksFile = await getMarks(studentId); - absencesFile = await getAbsences(studentId); - } - - DateTime bd = DateTime.now(); - if (birthDate != null) { - bd = DateFormat('dd/MM/yyyy').parse(birthDate); - } + Future saveUserDetails(UserModel user) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String userJson = jsonEncode(user.toJson()); + await prefs.setString('user', userJson); - return UserModel( - entity: UserEntity( - firstName: name, - className: className, - ine: ine, - birthDate: bd, - studentId: studentId, - marksFile: marksFile, - absencesFile: absencesFile), - ); } - Future saveUserDetails(String name, String? className, - {String? ine, String? birthDate}) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - UserModel( - entity: UserEntity( - firstName: name, - className: className, - ine: ine, - birthDate: birthDate != null ? DateTime.parse(birthDate) : null, - ), - ); - await prefs.setString('name', name); - if (className != null) { - await prefs.setString('className', className); - } - if (ine != null) { - await prefs.setString('ine', ine); - } - if (birthDate != null) { - await prefs.setString('birthDate', birthDate); - } - } + Future getUser() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + String? userJson = prefs.getString('user'); - Future deleteUser() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - await prefs.remove('ine'); - await prefs.remove('name'); - await prefs.remove('birthDate'); - await prefs.remove('className'); - } + if (userJson != null) { + Map userMap = jsonDecode(userJson); - Future saveUserClass(String className) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - await prefs.setString('className', className); + return UserModel.fromJson(userMap); + } else { + throw Exception('No user found in cache'); + } } Future delete() async { SharedPreferences prefs = await SharedPreferences.getInstance(); - await prefs.remove('ine'); - await prefs.remove('name'); - await prefs.remove('birthDate'); - await prefs.remove('className'); - await prefs.remove('studentId'); + await prefs.remove('user'); } Future clearClass() async { @@ -98,7 +43,7 @@ class UserRepository { await prefs.remove('className'); } - Future login(String username, String password) async { + Future login(String username, String password) async { final response = await http.post( Uri.parse('${apiService.apiUrl}/api/student/login'), body: {'username': username, 'password': password}, @@ -107,45 +52,64 @@ class UserRepository { if (response.statusCode == 200) { final data = jsonDecode(response.body); final studentId = (data['studentId']); - Global.setStudentId(studentId); - return studentId; + + File? marksFile; + File? absencesFile; + + print('studentId'); + print(studentId); + if (studentId != null) { + marksFile = await downloadFile( + 'https://api-dev.lukasvalois.com/api/student/marks/$studentId', + 'marks.pdf'); + print(marksFile); + absencesFile = await downloadFile( + 'https://api-dev.lukasvalois.com/api/student/absences/$studentId', + 'absences.pdf'); + } + + final marksDocument = DocumentEntity(title: 'Marks', file: marksFile!); + print(marksDocument); + final absencesDocument = + DocumentEntity(title: 'Absences', file: absencesFile!); + + final user = UserModel( + entity: UserEntity( + firstName: data['firstName'] ?? '', + ine: data['ine'] ?? '', + birthDate: data['birthDate'] != null + ? DateTime.parse(data['birthDate']) + : null, + className: data['className'] ?? '', + studentId: studentId ?? '', + documents: [marksDocument, absencesDocument], + ), + ); + + // Save the user details in the cache + await saveUserDetails(user); + + return user; } else { throw Exception('Failed to login'); } } - Future getMarks(int studentId) async { - final response = await http.get( - Uri.parse('${apiService.apiUrl}/api/student/marks/$studentId'), - ); + Future downloadFile(String url, String filename) async { + print('URL: $url'); + print('Filename: $filename'); + final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { - return _savePdfFile(response.bodyBytes, 'marks.pdf'); - } else { - throw Exception('Failed to get marks'); - } - } + print('Response body bytes: ${response.bodyBytes}'); + final directory = await getTemporaryDirectory(); + final file = File('${directory.path}/$filename'); - Future getAbsences(int studentId) async { - final response = await http.get( - Uri.parse('${apiService.apiUrl}/api/student/absences/$studentId'), - ); + await file.writeAsBytes(response.bodyBytes); - if (response.statusCode == 200) { - return _savePdfFile(response.bodyBytes, 'absences.pdf'); + return file; } else { - throw Exception('Failed to get absences'); + throw Exception('Failed to download file'); } } - - Future _savePdfFile(List bytes, String filename) async { - final directory = await getApplicationDocumentsDirectory(); - final path = directory.path; - final file = File('$path/$filename'); - - // Écrire les bytes de la réponse dans le fichier - await file.writeAsBytes(bytes); - - return file; - } } diff --git a/frontend/app_student/lib/class_groups/views/class_group_page.dart b/frontend/app_student/lib/class_groups/views/class_group_page.dart index 250275e..64374e4 100644 --- a/frontend/app_student/lib/class_groups/views/class_group_page.dart +++ b/frontend/app_student/lib/class_groups/views/class_group_page.dart @@ -1,4 +1,3 @@ -import 'package:app_student/api/class_groups/repositories/class_group_repository.dart'; import 'package:app_student/class_groups/cubit/class_group_cubit.dart'; import 'package:app_student/class_groups/views/widgets/card_list.dart'; import 'package:app_student/users/cubit/user_cubit.dart'; @@ -7,7 +6,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:go_router/go_router.dart'; -import '../../api/users/repositories/user_repository.dart'; import '../../shared_components/app_bar.dart'; import '../../shared_components/header_subtitle.dart'; import '../../shared_components/header_title.dart'; @@ -19,57 +17,45 @@ class ClassGroupPage extends StatelessWidget { @override Widget build(BuildContext context) { - final classRepository = - RepositoryProvider.of(context); - final userRepository = RepositoryProvider.of(context); - final classCubit = ClassGroupCubit(classRepository: classRepository) - ..fetchClasses(); - final userCubit = UserCubit(userRepository: userRepository)..fetchUser(); - - return MultiBlocProvider( - providers: [ - BlocProvider(create: (context) => classCubit), - BlocProvider(create: (context) => userCubit), - ], - child: CustomLayout( - appBar: const CustomAppBar(), - body: BlocBuilder( - builder: (context, userState) { - if (userState is UserClassesSelected) { - WidgetsBinding.instance.addPostFrameCallback((_) { - context.go('/schedule'); - }); - return const Center(child: CircularProgressIndicator()); - } else if (userState is UserLoading) { - return const Center(child: CircularProgressIndicator()); - } else if (userState is UserWithoutClass) { - final user = userState.user; - return BlocBuilder( - builder: (context, classState) { - if (classState is ClassGroupLoading) { - return const Center(child: CircularProgressIndicator()); - } else if (classState is ClassGroupLoaded) { - return Column( - children: [ - HeaderTitle(AppLocalizations.of(context)! - .classSelectionTitle(user.name)), - HeaderSubtitle(AppLocalizations.of(context)! - .classSelectionSubtitle), - CardList(classesList: classState.classes), - ], - ); - } else if (classState is ClassGroupError) { - return const NetworkError(); - } else { - return const Center(child: CircularProgressIndicator()); - } - }, - ); - } else { - return const Center(child: CircularProgressIndicator()); - } - }, - ), + return CustomLayout( + appBar: const CustomAppBar(), + body: BlocBuilder( + builder: (context, userState) { + print(userState); + if (userState is UserClassesSelected) { + WidgetsBinding.instance.addPostFrameCallback((_) { + context.go('/schedule'); + }); + return const Center(child: CircularProgressIndicator()); + } else if (userState is UserLoading) { + return const Center(child: CircularProgressIndicator()); + } else if (userState is UserWithoutClass) { + final user = userState.user; + return BlocBuilder( + builder: (context, classState) { + if (classState is ClassGroupLoading) { + return const Center(child: CircularProgressIndicator()); + } else if (classState is ClassGroupLoaded) { + return Column( + children: [ + HeaderTitle(AppLocalizations.of(context)! + .classSelectionTitle(user.firstName!)), + HeaderSubtitle( + AppLocalizations.of(context)!.classSelectionSubtitle), + CardList(classesList: classState.classes), + ], + ); + } else if (classState is ClassGroupError) { + return const NetworkError(); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ); + } else { + return const Text('error'); + } + }, ), ); } diff --git a/frontend/app_student/lib/login/cubit/login_cubit.dart b/frontend/app_student/lib/login/cubit/login_cubit.dart index eca525b..9ef802f 100644 --- a/frontend/app_student/lib/login/cubit/login_cubit.dart +++ b/frontend/app_student/lib/login/cubit/login_cubit.dart @@ -2,6 +2,9 @@ import 'package:app_student/api/users/repositories/user_repository.dart'; import 'package:bloc/bloc.dart'; import 'package:meta/meta.dart'; +import '../../api/users/entities/user_entity.dart'; +import '../../api/users/models/user_model.dart'; + part 'login_state.dart'; class LoginCubit extends Cubit { @@ -23,7 +26,19 @@ class LoginCubit extends Cubit { emit(LoginFieldError()); return; } - await userRepository.saveUserDetails(name, '', ine: null, birthDate: null); + + UserModel user = UserModel( + entity: UserEntity( + firstName: name, + className: '', + ine: null, + birthDate: null, + studentId: null, + documents: null, + ), + ); + + await userRepository.saveUserDetails(user); emit(RedirectToClassSelection()); } diff --git a/frontend/app_student/lib/main.dart b/frontend/app_student/lib/main.dart index 6b98c68..28135c2 100644 --- a/frontend/app_student/lib/main.dart +++ b/frontend/app_student/lib/main.dart @@ -1,13 +1,16 @@ import 'package:app_student/routes.dart'; +import 'package:app_student/users/cubit/user_cubit.dart'; import 'package:app_student/utils/custom_theme.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/date_symbol_data_local.dart'; -import 'package:provider/provider.dart'; +import 'api/api_service.dart'; +import 'api/users/repositories/user_repository.dart'; import 'config/config.dart'; import 'config/prod_config.dart'; import 'utils/global.dart'; @@ -17,9 +20,26 @@ void main() async { initializeDateFormatting('fr_FR', null).then((_) { runApp( - Provider( - create: (_) => ProdConfig(), - child: const MyApp(), + MultiRepositoryProvider( + providers: [ + RepositoryProvider( + create: (_) => ProdConfig(), + ), + RepositoryProvider( + create: (context) => UserRepository( + apiService: ApiService(apiUrl: context.read().apiUrl), + ), + ), + ], + child: MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => UserCubit( + userRepository: context.read(), + )..fetchUser()), + ], + child: const MyApp(), + ), ), ); }); diff --git a/frontend/app_student/lib/main_dev.dart b/frontend/app_student/lib/main_dev.dart index 980aab9..ec7a695 100644 --- a/frontend/app_student/lib/main_dev.dart +++ b/frontend/app_student/lib/main_dev.dart @@ -1,14 +1,17 @@ import 'package:app_student/config/dev_config.dart'; import 'package:app_student/routes.dart'; +import 'package:app_student/users/cubit/user_cubit.dart'; import 'package:app_student/utils/custom_theme.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/date_symbol_data_local.dart'; -import 'package:provider/provider.dart'; +import 'api/api_service.dart'; +import 'api/users/repositories/user_repository.dart'; import 'config/config.dart'; import 'utils/global.dart'; @@ -17,9 +20,27 @@ void main() async { initializeDateFormatting('fr_FR', null).then((_) { runApp( - Provider( - create: (_) => DevConfig(), - child: const MyApp(), + MultiRepositoryProvider( + providers: [ + RepositoryProvider( + create: (_) => DevConfig(), + ), + RepositoryProvider( + create: (context) => UserRepository( + apiService: ApiService(apiUrl: context.read().apiUrl), + ), + ), + ], + child: MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => UserCubit( + userRepository: context.read(), + )..fetchUser(), + ), + ], + child: const MyApp(), + ), ), ); }); @@ -47,8 +68,16 @@ class MyApp extends StatelessWidget { return MaterialApp.router( debugShowCheckedModeBanner: false, - title: '3iL Student App', - theme: CustomTheme.theme, + title: 'my3iL', + theme: ThemeData( + primarySwatch: Colors.blue, + // Orange 3IL + focusColor: CustomTheme.secondaryColor, + primaryColor: CustomTheme.primaryColor, + // Bleu 3IL + secondaryHeaderColor: CustomTheme.primaryColor, + fontFamily: 'Arial', + ), localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, diff --git a/frontend/app_student/lib/menu/menu_view.dart b/frontend/app_student/lib/menu/menu_view.dart index cf1669a..27f72ca 100644 --- a/frontend/app_student/lib/menu/menu_view.dart +++ b/frontend/app_student/lib/menu/menu_view.dart @@ -40,7 +40,7 @@ class MenuBarViewState extends State { switch (index) { case 0: - GoRouter.of(context).go(AppRoutes.accountPage); + GoRouter.of(context).go(AppRoutes.school_space); break; case 1: GoRouter.of(context).go(AppRoutes.schedulePage); diff --git a/frontend/app_student/lib/profil/views/profil_page.dart b/frontend/app_student/lib/profil/views/profil_page.dart index bb6ef3d..405a4a8 100644 --- a/frontend/app_student/lib/profil/views/profil_page.dart +++ b/frontend/app_student/lib/profil/views/profil_page.dart @@ -25,7 +25,9 @@ class ProfilPage extends StatelessWidget { appBar: HeaderLogo(appBarHeight: Global.screenHeight * 0.3), body: BlocBuilder( builder: (context, state) { + print('profil state: $state'); if (state is UserLoading) { + print('coucou'); return Container(); } else if (state is UserNameLoaded) { final user = state.user; @@ -35,12 +37,12 @@ class ProfilPage extends StatelessWidget { padding: const EdgeInsets.only(left: 10.0), child: HeaderTitle( AppLocalizations.of(context)! - .profilMessageTitle(user.firstName), + .profilMessageTitle(user.firstName!), ), ), UserClassCard( className: user.className!, - firstName: user.firstName, + firstName: user.firstName!, onTap: () { context.read().clearUserClass(); GoRouter.of(context).go(AppRoutes.classListPage); @@ -48,7 +50,7 @@ class ProfilPage extends StatelessWidget { ), ], ); - } else if (state is UserLoaded) { + } else if (state is UserLoggedIn) { final user = state.user; final birthDateString = @@ -60,12 +62,12 @@ class ProfilPage extends StatelessWidget { padding: const EdgeInsets.only(left: 10.0), child: HeaderTitle( AppLocalizations.of(context)! - .profilMessageTitle(user.firstName), + .profilMessageTitle(user.firstName!), ), ), UserClassCard( className: user.className!, - firstName: user.firstName, + firstName: user.firstName!, onTap: () { context.read().clearUserClass(); GoRouter.of(context).go(AppRoutes.classListPage); @@ -82,7 +84,8 @@ class ProfilPage extends StatelessWidget { bottomContent: BlocBuilder( builder: (context, state) { if (state is UserLoading) { - return const Center(child: CircularProgressIndicator()); + // return const Center(child: CircularProgressIndicator()); + return const Text('Loading'); } else { return CustomButton( text: AppLocalizations.of(context)!.disconnect, diff --git a/frontend/app_student/lib/routes.dart b/frontend/app_student/lib/routes.dart index 6972c21..975281f 100644 --- a/frontend/app_student/lib/routes.dart +++ b/frontend/app_student/lib/routes.dart @@ -6,6 +6,7 @@ import 'package:app_student/api/week_schedule/repositories/week_schedule_reposit import 'package:app_student/class_groups/cubit/class_group_cubit.dart'; import 'package:app_student/config/config.dart'; import 'package:app_student/profil/views/profil_page.dart'; +import 'package:app_student/school_space/views/forms/link_account_form.dart'; import 'package:app_student/school_space/views/school_space_page.dart'; import 'package:app_student/users/cubit/user_cubit.dart'; import 'package:app_student/week_schedule/cubit/week_schedule_cubit.dart'; @@ -22,7 +23,8 @@ class AppRoutes { static const loginPage = '/login'; static const schedulePage = '/schedule'; static const profilPage = '/profil'; - static const accountPage = '/account'; + static const school_space = '/school_space'; + static const linkAccountFormPage = '/linkAccountForm'; static final routes = [ GoRoute( @@ -35,10 +37,6 @@ class AppRoutes { create: (context) => ClassGroupRepository( apiService: ApiService(apiUrl: context.read().apiUrl))), - RepositoryProvider( - create: (context) => UserRepository( - apiService: - ApiService(apiUrl: context.read().apiUrl))), ], child: MultiBlocProvider(providers: [ BlocProvider( @@ -46,11 +44,6 @@ class AppRoutes { classRepository: context.read(), )..fetchClasses(), ), - BlocProvider( - create: (context) => - UserCubit(userRepository: context.read()) - ..fetchUser(), - ), ], child: const ClassGroupPage()), ), ), @@ -59,108 +52,63 @@ class AppRoutes { path: loginPage, pageBuilder: (context, state) => MaterialPage( key: state.pageKey, - child: MultiRepositoryProvider( + child: MultiBlocProvider( providers: [ - RepositoryProvider( - create: (context) => UserRepository( - apiService: - ApiService(apiUrl: context.read().apiUrl))), + BlocProvider( + create: (context) => LoginCubit(context.read()), + ), ], - child: MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => LoginCubit(context.read()), - ), - BlocProvider( - create: (context) => - UserCubit(userRepository: context.read()) - ..fetchUser(), - ), - ], - child: const LoginPage(), - ), + child: const LoginPage(), ), ), ), GoRoute( - path: schedulePage, - pageBuilder: (context, state) => MaterialPage( - key: state.pageKey, - child: MultiRepositoryProvider( - providers: [ - RepositoryProvider( - create: (context) => WeekScheduleRepository( - apiService: - ApiService(apiUrl: context.read().apiUrl))), - RepositoryProvider( - create: (context) => UserRepository( - apiService: - ApiService(apiUrl: context.read().apiUrl))), - ], - child: MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => WeekScheduleCubit( - weekScheduleRepository: WeekScheduleRepository( - apiService: ApiService( - apiUrl: context.read().apiUrl)), - initialDate: DateTime.now(), - userCubit: context.read()), - ), - BlocProvider( - create: (context) => UserCubit( - userRepository: context.read()) - ..fetchUser(), - ), - ], - child: const WeekSchedulePage(), - ), - ))), - GoRoute( - path: profilPage, + path: schedulePage, pageBuilder: (context, state) => MaterialPage( key: state.pageKey, child: MultiRepositoryProvider( providers: [ RepositoryProvider( - create: (context) => UserRepository( - apiService: - ApiService(apiUrl: context.read().apiUrl))), + create: (context) => WeekScheduleRepository( + apiService: ApiService(apiUrl: context.read().apiUrl), + ), + ), ], child: MultiBlocProvider( providers: [ BlocProvider( - create: (context) => - UserCubit(userRepository: context.read()) - ..fetchUser(), + create: (context) => WeekScheduleCubit( + weekScheduleRepository: + context.read(), + userCubit: context.read(), + initialDate: DateTime.now(), + )..fetchUserAndSchedule(), ), ], - child: const ProfilPage(), + child: const WeekSchedulePage(), ), ), ), ), GoRoute( - path: accountPage, + path: profilPage, pageBuilder: (context, state) => MaterialPage( key: state.pageKey, - child: MultiRepositoryProvider( - providers: [ - RepositoryProvider( - create: (context) => UserRepository( - apiService: - ApiService(apiUrl: context.read().apiUrl))), - ], - child: MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => - UserCubit(userRepository: context.read()), - ), - ], - child: const SchoolSpacePage(), - ), - ), + child: const ProfilPage(), + ), + ), + GoRoute( + path: school_space, + pageBuilder: (context, state) => MaterialPage( + key: state.pageKey, + child: const SchoolSpacePage(), + ), + ), + GoRoute( + path: linkAccountFormPage, // Use the new constant here + pageBuilder: (context, state) => MaterialPage( + key: state.pageKey, + child: const LinkAccountForm(), // Use the LinkAccountForm here ), ), ]; diff --git a/frontend/app_student/lib/school_space/views/forms/link_account_form.dart b/frontend/app_student/lib/school_space/views/forms/link_account_form.dart index abc24aa..b440cc6 100644 --- a/frontend/app_student/lib/school_space/views/forms/link_account_form.dart +++ b/frontend/app_student/lib/school_space/views/forms/link_account_form.dart @@ -5,12 +5,11 @@ import 'package:app_student/utils/custom_button.dart'; import 'package:app_student/utils/custom_layout.dart'; import 'package:app_student/utils/global.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; class LinkAccountForm extends StatelessWidget { - final UserCubit userCubit; - - const LinkAccountForm({super.key, required this.userCubit}); + const LinkAccountForm({super.key}); @override Widget build(BuildContext context) { @@ -84,7 +83,7 @@ class LinkAccountForm extends StatelessWidget { onPressed: () { if (formKey.currentState!.validate()) { formKey.currentState!.save(); - userCubit.loginAndSaveId(ine, birthDate); + context.read().loginAndSaveId(ine, birthDate); Navigator.of(context).pop(); } }, diff --git a/frontend/app_student/lib/school_space/views/pdf_view_page.dart b/frontend/app_student/lib/school_space/views/pdf_view_page.dart index d6c873b..415107c 100644 --- a/frontend/app_student/lib/school_space/views/pdf_view_page.dart +++ b/frontend/app_student/lib/school_space/views/pdf_view_page.dart @@ -21,7 +21,9 @@ class PdfViewPage extends StatelessWidget { ), ], ), - body: PDFView(filePath: filePath), + body: Expanded( + child: PDFView(filePath: filePath), + ), ); } } diff --git a/frontend/app_student/lib/school_space/views/school_space_page.dart b/frontend/app_student/lib/school_space/views/school_space_page.dart index aad257a..bc35e5e 100644 --- a/frontend/app_student/lib/school_space/views/school_space_page.dart +++ b/frontend/app_student/lib/school_space/views/school_space_page.dart @@ -4,14 +4,12 @@ import 'package:app_student/utils/custom_theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - -import '../../api/users/models/user_model.dart'; +import 'package:go_router/go_router.dart'; import '../../menu/menu_view.dart'; import '../../shared_components/header_logo.dart'; import '../../shared_components/header_title.dart'; import '../../utils/custom_layout.dart'; import '../../utils/global.dart'; -import 'forms/link_account_form.dart'; import 'widgets/pdf_card.dart'; class SchoolSpacePage extends StatefulWidget { @@ -22,16 +20,6 @@ class SchoolSpacePage extends StatefulWidget { } class SchoolSpacePageState extends State { - late final UserCubit userCubit; - late final UserModel user; - - @override - void initState() { - super.initState(); - userCubit = context.read(); - userCubit.fetchUser(); - } - @override Widget build(BuildContext context) { return CustomLayout( @@ -40,7 +28,8 @@ class SchoolSpacePageState extends State { builder: (context, state) { print(state); if (state is UserLoading) { - return const Center(child: CircularProgressIndicator()); + print(state); + return const Text('Loading'); } else if (state is UserLoggedIn) { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -61,16 +50,13 @@ class SchoolSpacePageState extends State { ), ), const SizedBox(height: 40), - PdfCard( - filePath: state.user.marksFile!.path, - title: 'Relevé de notes'), - const SizedBox(height: 20), - PdfCard( - filePath: state.user.absencesFile!.path, - title: "Relevé d'absences"), + ...?state.user.documents?.map((doc) => PdfCard( + filePath: doc.file!.path, + title: doc.title, + )), ], ); - } else if (state is UserInitial) { + } else if (state is UserWihtoutLink) { return Column( children: [ const Padding( @@ -95,13 +81,7 @@ class SchoolSpacePageState extends State { CustomButton( text: 'Relier mon compte', onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - LinkAccountForm(userCubit: userCubit), - ), - ); + context.push('/linkAccountForm'); }, ), ], diff --git a/frontend/app_student/lib/users/cubit/user_cubit.dart b/frontend/app_student/lib/users/cubit/user_cubit.dart index f1908e0..da2fc4f 100644 --- a/frontend/app_student/lib/users/cubit/user_cubit.dart +++ b/frontend/app_student/lib/users/cubit/user_cubit.dart @@ -1,10 +1,8 @@ -import 'dart:io'; import 'package:app_student/api/class_groups/models/class_group_model.dart'; import 'package:app_student/api/users/models/user_model.dart'; import 'package:bloc/bloc.dart'; import 'package:flutter/foundation.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import '../../api/users/repositories/user_repository.dart'; import '../../utils/global.dart'; @@ -19,21 +17,26 @@ class UserCubit extends Cubit { Future fetchUser() async { try { emit(UserLoading()); + print('fetchUser'); final user = await userRepository.getUser(); + print('fetchUser completed'); - if (user.className == null || user.className!.isEmpty) { + // print all user data to console + print(user.toString()); + + //user avec className et firstname uniquement et tout le reste vide ou null + if (user.firstName != null && user.className != null) { + emit(UserWihtoutLink(user)); + } else if (user.className == null || user.className!.isEmpty) { emit(UserWithoutClass(user)); } else if (user.ine != null && user.ine!.isNotEmpty && user.birthDate != null && user.studentId != null) { emit(UserLoggedIn(user)); - } else if (user.ine == null || - (user.ine != null && user.ine!.isEmpty) || - user.birthDate == null) { - emit(UserNameLoaded(user)); } } catch (e) { + print('fetchUser failed: $e'); if (!isClosed) { emit(UserError(e.toString())); } @@ -45,7 +48,11 @@ class UserCubit extends Cubit { } Future saveUserClass(ClassGroupModel classGroup) async { - await userRepository.saveUserClass(classGroup.name.toString()); + UserModel user = await userRepository.getUser(); + user.entity.className = classGroup.name; + + await userRepository.saveUserDetails(user); + emit(UserClassesSelected()); } @@ -59,51 +66,15 @@ class UserCubit extends Cubit { Future loginAndSaveId(String username, String password) async { emit(UserLoading()); + print('loginAndSaveId started'); try { - final studentId = await userRepository.login(username, password); + final user = await userRepository.login(username, password); + print('loginAndSaveId completed'); + await Global.setUser(user); - await Global.setStudentId(studentId); - await Global.setIne(username); - await Global.setBirthDate(password); - final user = await userRepository.getUser(); emit(UserLoggedIn(user)); } catch (e) { - emit(UserError(e.toString())); - } - } - - Future fetchMarks() async { - emit(UserLoading()); - try { - final user = await userRepository.getUser(); - if (user.studentId != null) { - final File marks = await userRepository.getMarks(user.studentId!); - if (kDebugMode) { - print(marks.path); - } - emit(UserMarksLoaded(user, marks)); - } else { - throw Exception('No student ID found in SharedPreferences'); - } - } catch (e) { - emit(UserError(e.toString())); - } - } - - Future fetchAbsences() async { - emit(UserLoading()); - try { - final user = await userRepository.getUser(); - if (user.studentId != null) { - final File absences = await userRepository.getAbsences(user.studentId!); - if (kDebugMode) { - print(absences.path); - } - emit(UserAbsencesLoaded(user, absences)); - } else { - throw Exception('No student ID found in SharedPreferences'); - } - } catch (e) { + print('loginAndSaveId failed: $e'); emit(UserError(e.toString())); } } diff --git a/frontend/app_student/lib/users/cubit/user_state.dart b/frontend/app_student/lib/users/cubit/user_state.dart index 86c453d..d19d44c 100644 --- a/frontend/app_student/lib/users/cubit/user_state.dart +++ b/frontend/app_student/lib/users/cubit/user_state.dart @@ -39,16 +39,8 @@ class UserLoggedIn extends UserState { UserLoggedIn(this.user); } -class UserMarksLoaded extends UserState { +class UserWihtoutLink extends UserState { final UserModel user; - final File marks; - UserMarksLoaded(this.user, this.marks); -} - -class UserAbsencesLoaded extends UserState { - final UserModel user; - final File absences; - - UserAbsencesLoaded(this.user, this.absences); + UserWihtoutLink(this.user); } diff --git a/frontend/app_student/lib/utils/global.dart b/frontend/app_student/lib/utils/global.dart index b7fc80e..4492b07 100644 --- a/frontend/app_student/lib/utils/global.dart +++ b/frontend/app_student/lib/utils/global.dart @@ -1,5 +1,7 @@ +import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:app_student/api/users/models/user_model.dart'; class Global { static late double screenWidth; @@ -14,33 +16,19 @@ class Global { return await SharedPreferences.getInstance(); } - static Future get getStudentId async { + static Future setUser(UserModel user) async { final prefs = await SharedPreferences.getInstance(); - return prefs.getInt('studentId'); + String userJson = jsonEncode(user.toJson()); + prefs.setString('user', userJson); } - static Future setStudentId(int value) async { + static Future getUser() async { final prefs = await SharedPreferences.getInstance(); - prefs.setInt('studentId', value); - } - - static Future get getIne async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getString('ine') ?? ''; - } - - static Future setIne(String value) async { - final prefs = await SharedPreferences.getInstance(); - prefs.setString('ine', value); - } - - static Future get getBirthdate async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getString('birthDate') ?? ''; - } - - static Future setBirthDate(String value) async { - final prefs = await SharedPreferences.getInstance(); - prefs.setString('birthDate', value); + String? userJson = prefs.getString('user'); + if (userJson != null) { + return UserModel.fromJson(jsonDecode(userJson)); + } else { + return null; + } } } diff --git a/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart b/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart index 324e372..c732f3e 100644 --- a/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart +++ b/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart @@ -1,13 +1,9 @@ -import 'package:app_student/api/week_schedule/repositories/week_schedule_repository.dart'; import 'package:app_student/shared_components/network_error.dart'; -import 'package:app_student/users/cubit/user_cubit.dart'; import 'package:app_student/week_schedule/cubit/week_schedule_cubit.dart'; import 'package:app_student/week_schedule/views/widgets/datepicker_button.dart'; import 'package:app_student/week_schedule/views/widgets/day_schedule_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; - -import '../../api/users/repositories/user_repository.dart'; import '../../menu/menu_view.dart'; import '../../shared_components/app_bar.dart'; import '../../utils/custom_layout.dart'; @@ -19,63 +15,46 @@ class WeekSchedulePage extends StatelessWidget { @override Widget build(BuildContext context) { - final weekScheduleRepository = - RepositoryProvider.of(context); - final userRepository = RepositoryProvider.of(context); - final weekScheduleCubit = WeekScheduleCubit( - userCubit: context.read(), - weekScheduleRepository: weekScheduleRepository, - initialDate: initialDate); - - return BlocProvider( - create: (context) => weekScheduleCubit..fetchUserAndSchedule(), - child: BlocProvider( - create: (context) => - UserCubit(userRepository: userRepository)..fetchUser(), - child: CustomLayout( - appBar: const CustomAppBar(widget: DatePickerButton()), - body: BlocBuilder( - builder: (context, state) { - final pageController = PageController( - initialPage: - state is WeekScheduleLoaded && state.todayIndex != -1 - ? state.todayIndex - : 0, - ); - if (state is WeekScheduleLoading) { - return const Center(child: CircularProgressIndicator()); - } else if (state is WeekScheduleLoaded) { - final allEvents = state.weekSchedule - .expand((week) => week.daySchedules) - .toList(); + return CustomLayout( + appBar: const CustomAppBar(widget: DatePickerButton()), + body: BlocBuilder( + builder: (context, state) { + final pageController = PageController( + initialPage: state is WeekScheduleLoaded && state.todayIndex != -1 + ? state.todayIndex + : 0, + ); + if (state is WeekScheduleLoading) { + return const Center(child: CircularProgressIndicator()); + } else if (state is WeekScheduleLoaded) { + final allEvents = + state.weekSchedule.expand((week) => week.daySchedules).toList(); - return Padding( - padding: const EdgeInsets.only(top: 20.0), - child: SizedBox( - height: MediaQuery.of(context).size.height, - child: PageView.builder( - controller: pageController, - itemCount: allEvents.length, - itemBuilder: (context, index) { - final daySchedule = allEvents[index]; - return DayScheduleWidget( - daySchedule: daySchedule, - pageController: pageController, - ); - }, - ), - ), - ); - } else if (state is WeekScheduleError) { - return const NetworkError(); - } else { - return const SizedBox.shrink(); - } - }, - ), - bottomBar: const MenuBarView(), - ), + return Padding( + padding: const EdgeInsets.only(top: 20.0), + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: PageView.builder( + controller: pageController, + itemCount: allEvents.length, + itemBuilder: (context, index) { + final daySchedule = allEvents[index]; + return DayScheduleWidget( + daySchedule: daySchedule, + pageController: pageController, + ); + }, + ), + ), + ); + } else if (state is WeekScheduleError) { + return const NetworkError(); + } else { + return const SizedBox.shrink(); + } + }, ), + bottomBar: const MenuBarView(), ); } } From 1fa3923660c183bede221746829bf786e083e4b0 Mon Sep 17 00:00:00 2001 From: jules Date: Sun, 26 May 2024 20:18:00 +0200 Subject: [PATCH 3/9] :construction: authentication system --- .../lib/api/users/models/user_model.dart | 29 +++++++++++++- .../users/repositories/user_repository.dart | 35 +++++++++------- .../class_groups/views/class_group_page.dart | 15 ++++++- .../lib/login/cubit/login_cubit.dart | 19 ++++++--- .../lib/login/views/login_page.dart | 1 + frontend/app_student/lib/main.dart | 3 +- frontend/app_student/lib/main_dev.dart | 7 +++- .../lib/profil/views/profil_page.dart | 7 ++-- frontend/app_student/lib/routes.dart | 22 ++++++++-- .../lib/school_space/views/pdf_view_page.dart | 17 +------- .../school_space/views/school_space_page.dart | 1 + .../lib/users/cubit/user_cubit.dart | 40 ++++++++++++------- .../lib/users/cubit/user_state.dart | 3 ++ .../views/week_schedule_page.dart | 1 + 14 files changed, 141 insertions(+), 59 deletions(-) diff --git a/frontend/app_student/lib/api/users/models/user_model.dart b/frontend/app_student/lib/api/users/models/user_model.dart index e7d3d7e..9a39fc5 100644 --- a/frontend/app_student/lib/api/users/models/user_model.dart +++ b/frontend/app_student/lib/api/users/models/user_model.dart @@ -44,9 +44,36 @@ class UserModel { : UserEntity(), ); - // fait un tostring de user custom genre User : {firstName: 'toto', birthDate: '2022-01-01', className: '3A', ine: '123456789 @override String toString() { return 'User : {firstName: $firstName, birthDate: $birthDate, className: $className, ine: $ine, studentId: $studentId, documents: $documents}'; } + + bool get isEmpty { + return firstName == null || firstName!.isEmpty; + } + + bool get hasFirstName { + return firstName != null && firstName!.isNotEmpty; + } + + bool get hasBirthDate { + return birthDate != null; + } + + bool get hasClassName { + return className != null && className!.isNotEmpty; + } + + bool get hasIne { + return ine != null && ine!.isNotEmpty; + } + + bool get hasStudentId { + return studentId != null; + } + + bool get hasDocuments { + return documents != null && documents!.isNotEmpty; + } } diff --git a/frontend/app_student/lib/api/users/repositories/user_repository.dart b/frontend/app_student/lib/api/users/repositories/user_repository.dart index 518b014..eb2044d 100644 --- a/frontend/app_student/lib/api/users/repositories/user_repository.dart +++ b/frontend/app_student/lib/api/users/repositories/user_repository.dart @@ -17,6 +17,8 @@ class UserRepository { SharedPreferences prefs = await SharedPreferences.getInstance(); String userJson = jsonEncode(user.toJson()); await prefs.setString('user', userJson); + print('User saved in cache'); + print(userJson); } @@ -71,20 +73,25 @@ class UserRepository { final marksDocument = DocumentEntity(title: 'Marks', file: marksFile!); print(marksDocument); final absencesDocument = - DocumentEntity(title: 'Absences', file: absencesFile!); - - final user = UserModel( - entity: UserEntity( - firstName: data['firstName'] ?? '', - ine: data['ine'] ?? '', - birthDate: data['birthDate'] != null - ? DateTime.parse(data['birthDate']) - : null, - className: data['className'] ?? '', - studentId: studentId ?? '', - documents: [marksDocument, absencesDocument], - ), - ); + DocumentEntity(title: 'Absences', file: absencesFile!); + + // Get the current user from the cache + UserModel user; + try { + user = await getUser(); + } catch (e) { + user = UserModel(entity: UserEntity()); + } + + // Update the user data + user.entity.firstName = data['firstName']; + user.entity.ine = data['ine']; + user.entity.birthDate = data['birthDate'] != null + ? DateTime.parse(data['birthDate']) + : null; + user.entity.className = data['className'] ?? ''; + user.entity.studentId = studentId ?? ''; + user.entity.documents = [marksDocument, absencesDocument]; // Save the user details in the cache await saveUserDetails(user); diff --git a/frontend/app_student/lib/class_groups/views/class_group_page.dart b/frontend/app_student/lib/class_groups/views/class_group_page.dart index 64374e4..f7932a8 100644 --- a/frontend/app_student/lib/class_groups/views/class_group_page.dart +++ b/frontend/app_student/lib/class_groups/views/class_group_page.dart @@ -21,8 +21,21 @@ class ClassGroupPage extends StatelessWidget { appBar: const CustomAppBar(), body: BlocBuilder( builder: (context, userState) { + print("quoi"); print(userState); - if (userState is UserClassesSelected) { + if (userState is UserInitial) { + return const Center(child: CircularProgressIndicator()); + } else + if (userState is UserError) { + print(userState.message); + return const NetworkError(); + } else if (userState is UserLoggedIn) { + WidgetsBinding.instance.addPostFrameCallback((_) { + context.go('/school_space'); + }); + return const Center(child: CircularProgressIndicator()); + } else + if (userState is UserWihtoutLink) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go('/schedule'); }); diff --git a/frontend/app_student/lib/login/cubit/login_cubit.dart b/frontend/app_student/lib/login/cubit/login_cubit.dart index 9ef802f..bae945e 100644 --- a/frontend/app_student/lib/login/cubit/login_cubit.dart +++ b/frontend/app_student/lib/login/cubit/login_cubit.dart @@ -4,13 +4,15 @@ import 'package:meta/meta.dart'; import '../../api/users/entities/user_entity.dart'; import '../../api/users/models/user_model.dart'; +import '../../users/cubit/user_cubit.dart'; part 'login_state.dart'; class LoginCubit extends Cubit { final UserRepository userRepository; + final UserCubit userCubit; - LoginCubit(this.userRepository) : super(LoginInitial()) { + LoginCubit(this.userRepository, this.userCubit) : super(LoginInitial()) { checkUserAuthentication(); } @@ -30,7 +32,7 @@ class LoginCubit extends Cubit { UserModel user = UserModel( entity: UserEntity( firstName: name, - className: '', + className: null, ine: null, birthDate: null, studentId: null, @@ -40,13 +42,15 @@ class LoginCubit extends Cubit { await userRepository.saveUserDetails(user); emit(RedirectToClassSelection()); + userCubit.emit(UserWithoutClass(user)); } Future checkUserAuthentication() async { try { + print('checkUserAuthentication'); var user = await userRepository.getUser(); - // Si la classe est vide - if (user.className == '') { + print(user.toString()); + if (user.hasClassName == false || user.isEmpty) { emit(LoginInitial()); return false; } @@ -57,4 +61,9 @@ class LoginCubit extends Cubit { return false; } } -} + + Future logout() async { + await userCubit.logout(); + emit(LoginInitial()); + } +} \ No newline at end of file diff --git a/frontend/app_student/lib/login/views/login_page.dart b/frontend/app_student/lib/login/views/login_page.dart index b82f8f2..b26f19e 100644 --- a/frontend/app_student/lib/login/views/login_page.dart +++ b/frontend/app_student/lib/login/views/login_page.dart @@ -15,6 +15,7 @@ class LoginPage extends StatelessWidget { return BlocConsumer( listener: (context, state) {}, builder: (context, state) { + print('login state: $state'); return BlocBuilder( builder: (context, userState) { if (state is RedirectToClassSelection) { diff --git a/frontend/app_student/lib/main.dart b/frontend/app_student/lib/main.dart index 28135c2..e3e1ed4 100644 --- a/frontend/app_student/lib/main.dart +++ b/frontend/app_student/lib/main.dart @@ -13,6 +13,7 @@ import 'api/api_service.dart'; import 'api/users/repositories/user_repository.dart'; import 'config/config.dart'; import 'config/prod_config.dart'; +import 'login/cubit/login_cubit.dart'; import 'utils/global.dart'; void main() async { @@ -35,7 +36,7 @@ void main() async { providers: [ BlocProvider( create: (context) => UserCubit( - userRepository: context.read(), + userRepository: context.read(), loginCubit: context.read(), )..fetchUser()), ], child: const MyApp(), diff --git a/frontend/app_student/lib/main_dev.dart b/frontend/app_student/lib/main_dev.dart index ec7a695..4c28dae 100644 --- a/frontend/app_student/lib/main_dev.dart +++ b/frontend/app_student/lib/main_dev.dart @@ -13,6 +13,7 @@ import 'package:intl/date_symbol_data_local.dart'; import 'api/api_service.dart'; import 'api/users/repositories/user_repository.dart'; import 'config/config.dart'; +import 'login/cubit/login_cubit.dart'; import 'utils/global.dart'; void main() async { @@ -33,9 +34,13 @@ void main() async { ], child: MultiBlocProvider( providers: [ + BlocProvider( + create: (context) => LoginCubit( + context.read(), context.read()), + ), BlocProvider( create: (context) => UserCubit( - userRepository: context.read(), + userRepository: context.read(), loginCubit: context.read(), )..fetchUser(), ), ], diff --git a/frontend/app_student/lib/profil/views/profil_page.dart b/frontend/app_student/lib/profil/views/profil_page.dart index 405a4a8..cd42bc9 100644 --- a/frontend/app_student/lib/profil/views/profil_page.dart +++ b/frontend/app_student/lib/profil/views/profil_page.dart @@ -1,3 +1,4 @@ +import 'package:app_student/login/cubit/login_cubit.dart'; import 'package:app_student/menu/menu_view.dart'; import 'package:app_student/profil/views/widgets/user_class_card.dart'; import 'package:app_student/routes.dart'; @@ -29,7 +30,7 @@ class ProfilPage extends StatelessWidget { if (state is UserLoading) { print('coucou'); return Container(); - } else if (state is UserNameLoaded) { + } else if (state is UserWihtoutLink) { final user = state.user; return Column( children: [ @@ -54,7 +55,7 @@ class ProfilPage extends StatelessWidget { final user = state.user; final birthDateString = - DateFormat('dd/MM/yyyy').format(user.birthDate!); + DateFormat('dd/MM/yyyy').format(user.birthDate ?? DateTime.now()); return Column( children: [ @@ -91,7 +92,7 @@ class ProfilPage extends StatelessWidget { text: AppLocalizations.of(context)!.disconnect, onPressed: () async { final goRouter = GoRouter.of(context); - await context.read().deleteUser(); + await context.read().logout(); goRouter.go(AppRoutes.loginPage); WidgetsBinding.instance.addPostFrameCallback((_) { Fluttertoast.showToast( diff --git a/frontend/app_student/lib/routes.dart b/frontend/app_student/lib/routes.dart index 975281f..7f91ea7 100644 --- a/frontend/app_student/lib/routes.dart +++ b/frontend/app_student/lib/routes.dart @@ -36,7 +36,7 @@ class AppRoutes { RepositoryProvider( create: (context) => ClassGroupRepository( apiService: - ApiService(apiUrl: context.read().apiUrl))), + ApiService(apiUrl: context.read().apiUrl))), ], child: MultiBlocProvider(providers: [ BlocProvider( @@ -47,6 +47,13 @@ class AppRoutes { ], child: const ClassGroupPage()), ), ), + redirect: (context, state) { + final loginCubit = context.read(); + if (loginCubit.state is RedirectToClassSelection) { + return classListPage; + } + return null; + }, ), GoRoute( path: loginPage, @@ -55,7 +62,7 @@ class AppRoutes { child: MultiBlocProvider( providers: [ BlocProvider( - create: (context) => LoginCubit(context.read()), + create: (context) => LoginCubit(context.read(), context.read()), ), ], child: const LoginPage(), @@ -79,7 +86,7 @@ class AppRoutes { BlocProvider( create: (context) => WeekScheduleCubit( weekScheduleRepository: - context.read(), + context.read(), userCubit: context.read(), initialDate: DateTime.now(), )..fetchUserAndSchedule(), @@ -89,6 +96,13 @@ class AppRoutes { ), ), ), + redirect: (context, state) { + final loginCubit = context.read(); + if (loginCubit.state is LoginAuthenticated) { + return schedulePage; + } + return null; + }, ), GoRoute( path: profilPage, @@ -112,4 +126,4 @@ class AppRoutes { ), ), ]; -} +} \ No newline at end of file diff --git a/frontend/app_student/lib/school_space/views/pdf_view_page.dart b/frontend/app_student/lib/school_space/views/pdf_view_page.dart index 415107c..6d2733f 100644 --- a/frontend/app_student/lib/school_space/views/pdf_view_page.dart +++ b/frontend/app_student/lib/school_space/views/pdf_view_page.dart @@ -9,21 +9,8 @@ class PdfViewPage extends StatelessWidget { @override Widget build(BuildContext context) { - return CustomLayout( - appBar: AppBar( - title: const Text('PDF View'), - actions: [ - IconButton( - icon: const Icon(Icons.download), - onPressed: () { - // Implement your download functionality here - }, - ), - ], - ), - body: Expanded( - child: PDFView(filePath: filePath), - ), + return Scaffold( + body: PDFView(filePath: filePath), ); } } diff --git a/frontend/app_student/lib/school_space/views/school_space_page.dart b/frontend/app_student/lib/school_space/views/school_space_page.dart index bc35e5e..6a4029f 100644 --- a/frontend/app_student/lib/school_space/views/school_space_page.dart +++ b/frontend/app_student/lib/school_space/views/school_space_page.dart @@ -26,6 +26,7 @@ class SchoolSpacePageState extends State { appBar: HeaderLogo(appBarHeight: Global.screenHeight * 0.3), body: BlocBuilder( builder: (context, state) { + print("cc"); print(state); if (state is UserLoading) { print(state); diff --git a/frontend/app_student/lib/users/cubit/user_cubit.dart b/frontend/app_student/lib/users/cubit/user_cubit.dart index da2fc4f..43e2762 100644 --- a/frontend/app_student/lib/users/cubit/user_cubit.dart +++ b/frontend/app_student/lib/users/cubit/user_cubit.dart @@ -1,18 +1,20 @@ - import 'package:app_student/api/class_groups/models/class_group_model.dart'; import 'package:app_student/api/users/models/user_model.dart'; import 'package:bloc/bloc.dart'; import 'package:flutter/foundation.dart'; import '../../api/users/repositories/user_repository.dart'; +import '../../login/cubit/login_cubit.dart'; import '../../utils/global.dart'; part 'user_state.dart'; class UserCubit extends Cubit { final UserRepository userRepository; + final LoginCubit loginCubit; - UserCubit({required this.userRepository}) : super(UserInitial()); + UserCubit({required this.userRepository, required this.loginCubit}) + : super(UserInitial()); Future fetchUser() async { try { @@ -24,21 +26,26 @@ class UserCubit extends Cubit { // print all user data to console print(user.toString()); - //user avec className et firstname uniquement et tout le reste vide ou null - if (user.firstName != null && user.className != null) { - emit(UserWihtoutLink(user)); - } else if (user.className == null || user.className!.isEmpty) { - emit(UserWithoutClass(user)); - } else if (user.ine != null && - user.ine!.isNotEmpty && - user.birthDate != null && - user.studentId != null) { - emit(UserLoggedIn(user)); + if (user.isEmpty) { + print(user.toString()); + emit(UserInitial()); + } else if (user.hasFirstName) { + if (user.hasClassName == false) { + emit(UserWithoutClass(user)); + } else if (user.hasIne && user.hasBirthDate && user.hasStudentId) { + emit(UserLoggedIn(user)); + } else { + emit(UserWihtoutLink(user)); + } } } catch (e) { print('fetchUser failed: $e'); if (!isClosed) { - emit(UserError(e.toString())); + if (e.toString() == 'Exception: No user found in cache') { + emit(UserInitial()); + } else { + emit(UserError(e.toString())); + } } } } @@ -53,13 +60,18 @@ class UserCubit extends Cubit { await userRepository.saveUserDetails(user); - emit(UserClassesSelected()); + emit(UserWihtoutLink(user)); } Future deleteUser() async { await userRepository.delete(); } + Future logout() async { + await deleteUser(); + await loginCubit.logout(); + } + Future clearUserClass() async { await userRepository.clearClass(); } diff --git a/frontend/app_student/lib/users/cubit/user_state.dart b/frontend/app_student/lib/users/cubit/user_state.dart index d19d44c..cb4433b 100644 --- a/frontend/app_student/lib/users/cubit/user_state.dart +++ b/frontend/app_student/lib/users/cubit/user_state.dart @@ -7,6 +7,7 @@ class UserInitial extends UserState {} class UserLoading extends UserState {} + class UserLoaded extends UserState { final UserModel user; @@ -44,3 +45,5 @@ class UserWihtoutLink extends UserState { UserWihtoutLink(this.user); } + + diff --git a/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart b/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart index c732f3e..507175e 100644 --- a/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart +++ b/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart @@ -48,6 +48,7 @@ class WeekSchedulePage extends StatelessWidget { ), ); } else if (state is WeekScheduleError) { + print(state.message); return const NetworkError(); } else { return const SizedBox.shrink(); From 5a4dfd788f3bc04293dcee82ec94c22fb1f51b47 Mon Sep 17 00:00:00 2001 From: Jules Artaud Date: Mon, 27 May 2024 11:42:42 +0200 Subject: [PATCH 4/9] :sparkles: get pdf from api and refactor user model --- .../api/documents/models/document_model.dart | 5 ++ .../lib/api/users/models/user_model.dart | 2 +- .../users/repositories/user_repository.dart | 25 +++------- .../class_groups/views/class_group_page.dart | 9 +--- .../lib/login/cubit/login_cubit.dart | 11 +--- .../lib/login/views/login_page.dart | 1 - .../views/widgets/form/submit_button.dart | 7 ++- frontend/app_student/lib/main.dart | 3 +- frontend/app_student/lib/main_dev.dart | 14 +++--- frontend/app_student/lib/menu/menu_view.dart | 2 +- .../lib/profil/views/profil_page.dart | 9 ++-- frontend/app_student/lib/routes.dart | 50 ++++++++++++------- .../lib/school_space/views/pdf_view_page.dart | 3 +- .../school_space/views/school_space_page.dart | 3 -- .../lib/users/cubit/user_cubit.dart | 19 ++----- .../lib/users/cubit/user_state.dart | 3 +- .../views/week_schedule_page.dart | 1 - 17 files changed, 72 insertions(+), 95 deletions(-) diff --git a/frontend/app_student/lib/api/documents/models/document_model.dart b/frontend/app_student/lib/api/documents/models/document_model.dart index d5added..6a444b5 100644 --- a/frontend/app_student/lib/api/documents/models/document_model.dart +++ b/frontend/app_student/lib/api/documents/models/document_model.dart @@ -22,4 +22,9 @@ class DocumentModel { file: file, ); } + + @override + String toString() { + return 'DocumentModel: {title: $title, file: ${file?.path}}'; + } } diff --git a/frontend/app_student/lib/api/users/models/user_model.dart b/frontend/app_student/lib/api/users/models/user_model.dart index 9a39fc5..409f075 100644 --- a/frontend/app_student/lib/api/users/models/user_model.dart +++ b/frontend/app_student/lib/api/users/models/user_model.dart @@ -46,7 +46,7 @@ class UserModel { @override String toString() { - return 'User : {firstName: $firstName, birthDate: $birthDate, className: $className, ine: $ine, studentId: $studentId, documents: $documents}'; + return 'User : {firstName: $firstName, birthDate: $birthDate, className: $className, ine: $ine, studentId: $studentId, documents: ${documents?.map((doc) => doc.toString()).join(', ')}}'; } bool get isEmpty { diff --git a/frontend/app_student/lib/api/users/repositories/user_repository.dart b/frontend/app_student/lib/api/users/repositories/user_repository.dart index eb2044d..48f2db6 100644 --- a/frontend/app_student/lib/api/users/repositories/user_repository.dart +++ b/frontend/app_student/lib/api/users/repositories/user_repository.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:app_student/api/users/models/user_model.dart'; +import 'package:intl/intl.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../api_service.dart'; @@ -17,9 +18,6 @@ class UserRepository { SharedPreferences prefs = await SharedPreferences.getInstance(); String userJson = jsonEncode(user.toJson()); await prefs.setString('user', userJson); - print('User saved in cache'); - print(userJson); - } Future getUser() async { @@ -58,22 +56,19 @@ class UserRepository { File? marksFile; File? absencesFile; - print('studentId'); - print(studentId); if (studentId != null) { marksFile = await downloadFile( 'https://api-dev.lukasvalois.com/api/student/marks/$studentId', 'marks.pdf'); - print(marksFile); absencesFile = await downloadFile( 'https://api-dev.lukasvalois.com/api/student/absences/$studentId', 'absences.pdf'); } final marksDocument = DocumentEntity(title: 'Marks', file: marksFile!); - print(marksDocument); + final absencesDocument = - DocumentEntity(title: 'Absences', file: absencesFile!); + DocumentEntity(title: 'Absences', file: absencesFile!); // Get the current user from the cache UserModel user; @@ -84,12 +79,11 @@ class UserRepository { } // Update the user data - user.entity.firstName = data['firstName']; - user.entity.ine = data['ine']; - user.entity.birthDate = data['birthDate'] != null - ? DateTime.parse(data['birthDate']) - : null; - user.entity.className = data['className'] ?? ''; + user.entity.firstName = user.entity.firstName; + user.entity.ine = username; + DateFormat format = DateFormat('dd/MM/yyyy'); + user.entity.birthDate = format.parse(password); + user.entity.className = user.entity.className; user.entity.studentId = studentId ?? ''; user.entity.documents = [marksDocument, absencesDocument]; @@ -103,12 +97,9 @@ class UserRepository { } Future downloadFile(String url, String filename) async { - print('URL: $url'); - print('Filename: $filename'); final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { - print('Response body bytes: ${response.bodyBytes}'); final directory = await getTemporaryDirectory(); final file = File('${directory.path}/$filename'); diff --git a/frontend/app_student/lib/class_groups/views/class_group_page.dart b/frontend/app_student/lib/class_groups/views/class_group_page.dart index f7932a8..91ed844 100644 --- a/frontend/app_student/lib/class_groups/views/class_group_page.dart +++ b/frontend/app_student/lib/class_groups/views/class_group_page.dart @@ -21,21 +21,16 @@ class ClassGroupPage extends StatelessWidget { appBar: const CustomAppBar(), body: BlocBuilder( builder: (context, userState) { - print("quoi"); - print(userState); if (userState is UserInitial) { return const Center(child: CircularProgressIndicator()); - } else - if (userState is UserError) { - print(userState.message); + } else if (userState is UserError) { return const NetworkError(); } else if (userState is UserLoggedIn) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go('/school_space'); }); return const Center(child: CircularProgressIndicator()); - } else - if (userState is UserWihtoutLink) { + } else if (userState is UserWihtoutLink) { WidgetsBinding.instance.addPostFrameCallback((_) { context.go('/schedule'); }); diff --git a/frontend/app_student/lib/login/cubit/login_cubit.dart b/frontend/app_student/lib/login/cubit/login_cubit.dart index bae945e..622d54e 100644 --- a/frontend/app_student/lib/login/cubit/login_cubit.dart +++ b/frontend/app_student/lib/login/cubit/login_cubit.dart @@ -1,18 +1,15 @@ import 'package:app_student/api/users/repositories/user_repository.dart'; import 'package:bloc/bloc.dart'; import 'package:meta/meta.dart'; - import '../../api/users/entities/user_entity.dart'; import '../../api/users/models/user_model.dart'; -import '../../users/cubit/user_cubit.dart'; part 'login_state.dart'; class LoginCubit extends Cubit { final UserRepository userRepository; - final UserCubit userCubit; - LoginCubit(this.userRepository, this.userCubit) : super(LoginInitial()) { + LoginCubit({required this.userRepository}) : super(LoginInitial()) { checkUserAuthentication(); } @@ -42,14 +39,11 @@ class LoginCubit extends Cubit { await userRepository.saveUserDetails(user); emit(RedirectToClassSelection()); - userCubit.emit(UserWithoutClass(user)); } Future checkUserAuthentication() async { try { - print('checkUserAuthentication'); var user = await userRepository.getUser(); - print(user.toString()); if (user.hasClassName == false || user.isEmpty) { emit(LoginInitial()); return false; @@ -63,7 +57,6 @@ class LoginCubit extends Cubit { } Future logout() async { - await userCubit.logout(); emit(LoginInitial()); } -} \ No newline at end of file +} diff --git a/frontend/app_student/lib/login/views/login_page.dart b/frontend/app_student/lib/login/views/login_page.dart index b26f19e..b82f8f2 100644 --- a/frontend/app_student/lib/login/views/login_page.dart +++ b/frontend/app_student/lib/login/views/login_page.dart @@ -15,7 +15,6 @@ class LoginPage extends StatelessWidget { return BlocConsumer( listener: (context, state) {}, builder: (context, state) { - print('login state: $state'); return BlocBuilder( builder: (context, userState) { if (state is RedirectToClassSelection) { diff --git a/frontend/app_student/lib/login/views/widgets/form/submit_button.dart b/frontend/app_student/lib/login/views/widgets/form/submit_button.dart index dbccac7..13ed6e8 100644 --- a/frontend/app_student/lib/login/views/widgets/form/submit_button.dart +++ b/frontend/app_student/lib/login/views/widgets/form/submit_button.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import '../../../../users/cubit/user_cubit.dart'; + class SubmitButton extends StatelessWidget { final TextEditingController nameController; @@ -17,9 +19,10 @@ class SubmitButton extends StatelessWidget { Widget build(BuildContext context) { return CustomButton( text: AppLocalizations.of(context)!.loginButton, - onPressed: () { + onPressed: () async { final String name = nameController.text.trim(); - context.read().saveLoginDetails(name); + await context.read().saveLoginDetails(name); + await context.read().fetchUser(); }, backgroundColor: CustomTheme.secondaryColor, textColor: Colors.white, diff --git a/frontend/app_student/lib/main.dart b/frontend/app_student/lib/main.dart index e3e1ed4..28135c2 100644 --- a/frontend/app_student/lib/main.dart +++ b/frontend/app_student/lib/main.dart @@ -13,7 +13,6 @@ import 'api/api_service.dart'; import 'api/users/repositories/user_repository.dart'; import 'config/config.dart'; import 'config/prod_config.dart'; -import 'login/cubit/login_cubit.dart'; import 'utils/global.dart'; void main() async { @@ -36,7 +35,7 @@ void main() async { providers: [ BlocProvider( create: (context) => UserCubit( - userRepository: context.read(), loginCubit: context.read(), + userRepository: context.read(), )..fetchUser()), ], child: const MyApp(), diff --git a/frontend/app_student/lib/main_dev.dart b/frontend/app_student/lib/main_dev.dart index 4c28dae..1ce1412 100644 --- a/frontend/app_student/lib/main_dev.dart +++ b/frontend/app_student/lib/main_dev.dart @@ -34,14 +34,14 @@ void main() async { ], child: MultiBlocProvider( providers: [ - BlocProvider( - create: (context) => LoginCubit( - context.read(), context.read()), - ), BlocProvider( - create: (context) => UserCubit( - userRepository: context.read(), loginCubit: context.read(), - )..fetchUser(), + create: (context) => + UserCubit(userRepository: context.read()) + ..fetchUser(), + ), + BlocProvider( + create: (context) => + LoginCubit(userRepository: context.read()), ), ], child: const MyApp(), diff --git a/frontend/app_student/lib/menu/menu_view.dart b/frontend/app_student/lib/menu/menu_view.dart index 27f72ca..64a7ebc 100644 --- a/frontend/app_student/lib/menu/menu_view.dart +++ b/frontend/app_student/lib/menu/menu_view.dart @@ -40,7 +40,7 @@ class MenuBarViewState extends State { switch (index) { case 0: - GoRouter.of(context).go(AppRoutes.school_space); + GoRouter.of(context).go(AppRoutes.schoolSpace); break; case 1: GoRouter.of(context).go(AppRoutes.schedulePage); diff --git a/frontend/app_student/lib/profil/views/profil_page.dart b/frontend/app_student/lib/profil/views/profil_page.dart index cd42bc9..0ce277d 100644 --- a/frontend/app_student/lib/profil/views/profil_page.dart +++ b/frontend/app_student/lib/profil/views/profil_page.dart @@ -26,9 +26,7 @@ class ProfilPage extends StatelessWidget { appBar: HeaderLogo(appBarHeight: Global.screenHeight * 0.3), body: BlocBuilder( builder: (context, state) { - print('profil state: $state'); if (state is UserLoading) { - print('coucou'); return Container(); } else if (state is UserWihtoutLink) { final user = state.user; @@ -55,7 +53,7 @@ class ProfilPage extends StatelessWidget { final user = state.user; final birthDateString = - DateFormat('dd/MM/yyyy').format(user.birthDate ?? DateTime.now()); + DateFormat('dd/MM/yyyy').format(user.birthDate!); return Column( children: [ @@ -71,7 +69,6 @@ class ProfilPage extends StatelessWidget { firstName: user.firstName!, onTap: () { context.read().clearUserClass(); - GoRouter.of(context).go(AppRoutes.classListPage); }, ), UserInfoCard(ine: user.ine!, birthDate: birthDateString), @@ -91,9 +88,9 @@ class ProfilPage extends StatelessWidget { return CustomButton( text: AppLocalizations.of(context)!.disconnect, onPressed: () async { - final goRouter = GoRouter.of(context); await context.read().logout(); - goRouter.go(AppRoutes.loginPage); + await context.read().logout(); + context.pushReplacement(AppRoutes.loginPage); WidgetsBinding.instance.addPostFrameCallback((_) { Fluttertoast.showToast( msg: AppLocalizations.of(context)!.disconnectedMessage, diff --git a/frontend/app_student/lib/routes.dart b/frontend/app_student/lib/routes.dart index 7f91ea7..4d426b5 100644 --- a/frontend/app_student/lib/routes.dart +++ b/frontend/app_student/lib/routes.dart @@ -23,7 +23,7 @@ class AppRoutes { static const loginPage = '/login'; static const schedulePage = '/schedule'; static const profilPage = '/profil'; - static const school_space = '/school_space'; + static const schoolSpace = '/school_space'; static const linkAccountFormPage = '/linkAccountForm'; static final routes = [ @@ -36,7 +36,7 @@ class AppRoutes { RepositoryProvider( create: (context) => ClassGroupRepository( apiService: - ApiService(apiUrl: context.read().apiUrl))), + ApiService(apiUrl: context.read().apiUrl))), ], child: MultiBlocProvider(providers: [ BlocProvider( @@ -47,22 +47,34 @@ class AppRoutes { ], child: const ClassGroupPage()), ), ), - redirect: (context, state) { + // redirect: (context, state) { + // final loginCubit = context.read(); + // if (loginCubit.state is RedirectToClassSelection) { + // return classListPage; + // } + // return null; + // }, + ), + GoRoute( + redirect: (BuildContext context, GoRouterState state) { final loginCubit = context.read(); - if (loginCubit.state is RedirectToClassSelection) { - return classListPage; + final userCubit = context.read(); + if (loginCubit.state is LoginAuthenticated) { + if (userCubit.state is UserWithoutClass) { + return classListPage; + } + return schedulePage; } - return null; + return loginPage; }, - ), - GoRoute( path: loginPage, pageBuilder: (context, state) => MaterialPage( key: state.pageKey, child: MultiBlocProvider( providers: [ BlocProvider( - create: (context) => LoginCubit(context.read(), context.read()), + create: (context) => + LoginCubit(userRepository: context.read()), ), ], child: const LoginPage(), @@ -86,7 +98,7 @@ class AppRoutes { BlocProvider( create: (context) => WeekScheduleCubit( weekScheduleRepository: - context.read(), + context.read(), userCubit: context.read(), initialDate: DateTime.now(), )..fetchUserAndSchedule(), @@ -96,13 +108,13 @@ class AppRoutes { ), ), ), - redirect: (context, state) { - final loginCubit = context.read(); - if (loginCubit.state is LoginAuthenticated) { - return schedulePage; - } - return null; - }, + // redirect: (context, state) { + // final loginCubit = context.read(); + // if (loginCubit.state is LoginAuthenticated) { + // return schedulePage; + // } + // return null; + // }, ), GoRoute( path: profilPage, @@ -112,7 +124,7 @@ class AppRoutes { ), ), GoRoute( - path: school_space, + path: schoolSpace, pageBuilder: (context, state) => MaterialPage( key: state.pageKey, child: const SchoolSpacePage(), @@ -126,4 +138,4 @@ class AppRoutes { ), ), ]; -} \ No newline at end of file +} diff --git a/frontend/app_student/lib/school_space/views/pdf_view_page.dart b/frontend/app_student/lib/school_space/views/pdf_view_page.dart index 6d2733f..4ca2343 100644 --- a/frontend/app_student/lib/school_space/views/pdf_view_page.dart +++ b/frontend/app_student/lib/school_space/views/pdf_view_page.dart @@ -1,4 +1,3 @@ -import 'package:app_student/utils/custom_layout.dart'; import 'package:flutter/material.dart'; import 'package:flutter_pdfview/flutter_pdfview.dart'; @@ -10,7 +9,7 @@ class PdfViewPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - body: PDFView(filePath: filePath), + body: PDFView(filePath: filePath), ); } } diff --git a/frontend/app_student/lib/school_space/views/school_space_page.dart b/frontend/app_student/lib/school_space/views/school_space_page.dart index 6a4029f..73b6c5b 100644 --- a/frontend/app_student/lib/school_space/views/school_space_page.dart +++ b/frontend/app_student/lib/school_space/views/school_space_page.dart @@ -26,10 +26,7 @@ class SchoolSpacePageState extends State { appBar: HeaderLogo(appBarHeight: Global.screenHeight * 0.3), body: BlocBuilder( builder: (context, state) { - print("cc"); - print(state); if (state is UserLoading) { - print(state); return const Text('Loading'); } else if (state is UserLoggedIn) { return Column( diff --git a/frontend/app_student/lib/users/cubit/user_cubit.dart b/frontend/app_student/lib/users/cubit/user_cubit.dart index 43e2762..c11ae00 100644 --- a/frontend/app_student/lib/users/cubit/user_cubit.dart +++ b/frontend/app_student/lib/users/cubit/user_cubit.dart @@ -4,30 +4,21 @@ import 'package:bloc/bloc.dart'; import 'package:flutter/foundation.dart'; import '../../api/users/repositories/user_repository.dart'; -import '../../login/cubit/login_cubit.dart'; import '../../utils/global.dart'; part 'user_state.dart'; class UserCubit extends Cubit { final UserRepository userRepository; - final LoginCubit loginCubit; - UserCubit({required this.userRepository, required this.loginCubit}) - : super(UserInitial()); + UserCubit({required this.userRepository}) : super(UserInitial()); Future fetchUser() async { try { emit(UserLoading()); - print('fetchUser'); final user = await userRepository.getUser(); - print('fetchUser completed'); - - // print all user data to console - print(user.toString()); if (user.isEmpty) { - print(user.toString()); emit(UserInitial()); } else if (user.hasFirstName) { if (user.hasClassName == false) { @@ -39,7 +30,6 @@ class UserCubit extends Cubit { } } } catch (e) { - print('fetchUser failed: $e'); if (!isClosed) { if (e.toString() == 'Exception: No user found in cache') { emit(UserInitial()); @@ -69,24 +59,23 @@ class UserCubit extends Cubit { Future logout() async { await deleteUser(); - await loginCubit.logout(); + emit(UserInitial()); } Future clearUserClass() async { await userRepository.clearClass(); + final user = await userRepository.getUser(); + emit(UserWithoutClass(user)); } Future loginAndSaveId(String username, String password) async { emit(UserLoading()); - print('loginAndSaveId started'); try { final user = await userRepository.login(username, password); - print('loginAndSaveId completed'); await Global.setUser(user); emit(UserLoggedIn(user)); } catch (e) { - print('loginAndSaveId failed: $e'); emit(UserError(e.toString())); } } diff --git a/frontend/app_student/lib/users/cubit/user_state.dart b/frontend/app_student/lib/users/cubit/user_state.dart index cb4433b..066cf33 100644 --- a/frontend/app_student/lib/users/cubit/user_state.dart +++ b/frontend/app_student/lib/users/cubit/user_state.dart @@ -7,7 +7,6 @@ class UserInitial extends UserState {} class UserLoading extends UserState {} - class UserLoaded extends UserState { final UserModel user; @@ -46,4 +45,4 @@ class UserWihtoutLink extends UserState { UserWihtoutLink(this.user); } - +class UserLoggedOut extends UserState {} diff --git a/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart b/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart index 507175e..c732f3e 100644 --- a/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart +++ b/frontend/app_student/lib/week_schedule/views/week_schedule_page.dart @@ -48,7 +48,6 @@ class WeekSchedulePage extends StatelessWidget { ), ); } else if (state is WeekScheduleError) { - print(state.message); return const NetworkError(); } else { return const SizedBox.shrink(); From fc4d787e63bc1947d44bf8c1d8f05a4d077fe5bf Mon Sep 17 00:00:00 2001 From: Jules Artaud Date: Mon, 27 May 2024 11:45:00 +0200 Subject: [PATCH 5/9] :rotating_light: temporary fix linter --- .../lib/login/views/widgets/form/submit_button.dart | 4 +++- frontend/app_student/lib/profil/views/profil_page.dart | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/app_student/lib/login/views/widgets/form/submit_button.dart b/frontend/app_student/lib/login/views/widgets/form/submit_button.dart index 13ed6e8..ea39e8e 100644 --- a/frontend/app_student/lib/login/views/widgets/form/submit_button.dart +++ b/frontend/app_student/lib/login/views/widgets/form/submit_button.dart @@ -22,7 +22,9 @@ class SubmitButton extends StatelessWidget { onPressed: () async { final String name = nameController.text.trim(); await context.read().saveLoginDetails(name); - await context.read().fetchUser(); + if (context.mounted) { + await context.read().fetchUser(); + } }, backgroundColor: CustomTheme.secondaryColor, textColor: Colors.white, diff --git a/frontend/app_student/lib/profil/views/profil_page.dart b/frontend/app_student/lib/profil/views/profil_page.dart index 0ce277d..8a8004b 100644 --- a/frontend/app_student/lib/profil/views/profil_page.dart +++ b/frontend/app_student/lib/profil/views/profil_page.dart @@ -89,8 +89,13 @@ class ProfilPage extends StatelessWidget { text: AppLocalizations.of(context)!.disconnect, onPressed: () async { await context.read().logout(); - await context.read().logout(); - context.pushReplacement(AppRoutes.loginPage); + if (context.mounted) { + await context.read().logout(); + } + if (context.mounted) { + context.pushReplacement(AppRoutes.loginPage); + } + WidgetsBinding.instance.addPostFrameCallback((_) { Fluttertoast.showToast( msg: AppLocalizations.of(context)!.disconnectedMessage, From 9f78f2c1021f065ca84bc6fdd12647a4fcac6e56 Mon Sep 17 00:00:00 2001 From: Jules Artaud Date: Mon, 27 May 2024 16:03:36 +0200 Subject: [PATCH 6/9] :bug: fix minimal bug --- frontend/app_student/android/app/build.gradle | 2 +- frontend/app_student/lib/main.dart | 4 ++-- .../app_student/lib/profil/views/profil_page.dart | 9 +++++---- .../app_student/lib/users/cubit/user_cubit.dart | 13 +------------ 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/frontend/app_student/android/app/build.gradle b/frontend/app_student/android/app/build.gradle index 76cd5f8..d3e1b9f 100644 --- a/frontend/app_student/android/app/build.gradle +++ b/frontend/app_student/android/app/build.gradle @@ -83,4 +83,4 @@ flutter { } dependencies { -} +} \ No newline at end of file diff --git a/frontend/app_student/lib/main.dart b/frontend/app_student/lib/main.dart index 0f0369b..0332e2a 100644 --- a/frontend/app_student/lib/main.dart +++ b/frontend/app_student/lib/main.dart @@ -54,8 +54,8 @@ void main() async { providers: [ BlocProvider( create: (context) => - UserCubit(userRepository: context.read()) - ..fetchUser(), + UserCubit(userRepository: context.read()) + ..fetchUser(), ), BlocProvider( create: (context) => diff --git a/frontend/app_student/lib/profil/views/profil_page.dart b/frontend/app_student/lib/profil/views/profil_page.dart index 8a8004b..9a13114 100644 --- a/frontend/app_student/lib/profil/views/profil_page.dart +++ b/frontend/app_student/lib/profil/views/profil_page.dart @@ -42,9 +42,11 @@ class ProfilPage extends StatelessWidget { UserClassCard( className: user.className!, firstName: user.firstName!, - onTap: () { + onTap: () async { context.read().clearUserClass(); - GoRouter.of(context).go(AppRoutes.classListPage); + if (context.mounted) { + context.pushReplacement('/classList'); + } }, ), ], @@ -82,8 +84,7 @@ class ProfilPage extends StatelessWidget { bottomContent: BlocBuilder( builder: (context, state) { if (state is UserLoading) { - // return const Center(child: CircularProgressIndicator()); - return const Text('Loading'); + return const Center(child: CircularProgressIndicator()); } else { return CustomButton( text: AppLocalizations.of(context)!.disconnect, diff --git a/frontend/app_student/lib/users/cubit/user_cubit.dart b/frontend/app_student/lib/users/cubit/user_cubit.dart index c11ae00..b0a6291 100644 --- a/frontend/app_student/lib/users/cubit/user_cubit.dart +++ b/frontend/app_student/lib/users/cubit/user_cubit.dart @@ -64,8 +64,7 @@ class UserCubit extends Cubit { Future clearUserClass() async { await userRepository.clearClass(); - final user = await userRepository.getUser(); - emit(UserWithoutClass(user)); + emit(UserWithoutClass(await userRepository.getUser())); } Future loginAndSaveId(String username, String password) async { @@ -79,14 +78,4 @@ class UserCubit extends Cubit { emit(UserError(e.toString())); } } - - Future checkStudentId() async { - final user = await getCurrentUser(); - - if (user.studentId != null) { - emit(UserLoggedIn(user)); - } else { - emit(UserInitial()); - } - } } From 790879a44f1b8c578e02bdf73346d33db0e335f0 Mon Sep 17 00:00:00 2001 From: Jules Artaud Date: Mon, 27 May 2024 16:04:11 +0200 Subject: [PATCH 7/9] :bug: fix timetable array api --- backend/src/Service/TimetableService.php | 43 ++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/backend/src/Service/TimetableService.php b/backend/src/Service/TimetableService.php index 218fd37..7749dee 100644 --- a/backend/src/Service/TimetableService.php +++ b/backend/src/Service/TimetableService.php @@ -41,7 +41,7 @@ public function getXmlFile(string $classParam): ?string if ($class->getName() === $classParam) { $encodedClassFile = str_replace(' ', '%20', $class->getFile()); - return $this->schedule_url.$encodedClassFile; + return $this->schedule_url . $encodedClassFile; } } @@ -73,6 +73,13 @@ public function parseData(array $parsedData): array $changes = false; + $weeksTest = $parsedData['GROUPE']['PLAGES']['SEMAINE']; + // Si 'weeksTest' contient une seule semaine, convertissez-la en tableau multidimensionnel + + if (!isset($weeksTest[0])) { + $parsedData['GROUPE']['PLAGES']['SEMAINE'] = [$weeksTest]; + } + foreach ($parsedData['GROUPE']['PLAGES']['SEMAINE'] as $week) { $weekSchedule = new WeekSchedule(); $weekSchedule->setId($week['SemId']); @@ -125,26 +132,28 @@ public function parseData(array $parsedData): array if ($existingEvent) { // Si l'événement existe déjà, fusionnez les modifications - if ($existingEvent->getActivite() !== $event->getActivite() + if ( + $existingEvent->getActivite() !== $event->getActivite() || $existingEvent->getCouleur() !== $event->getCouleur() || $existingEvent->getSalle() !== $event->getSalle() || $existingEvent->isRepas() !== $event->isRepas() || $existingEvent->isVisio() !== $event->isVisio() - || $existingEvent->getEval() !== $event->getEval()) { - - - (new Logger())->info('Existing event: '.$existingEvent->getActivite()); - (new Logger())->info('New event: '.$event->getActivite()); - (new Logger())->info('Existing event: '.$existingEvent->getCouleur()); - (new Logger())->info('New event: '.$event->getCouleur()); - (new Logger())->info('Existing event: '.$existingEvent->getSalle()); - (new Logger())->info('New event: '.$event->getSalle()); - (new Logger())->info('Existing event: '.$existingEvent->isRepas()); - (new Logger())->info('New event: '.$event->isRepas()); - (new Logger())->info('Existing event: '.$existingEvent->isVisio()); - (new Logger())->info('New event: '.$event->isVisio()); - (new Logger())->info('Existing event: '.$existingEvent->getEval()); - (new Logger())->info('New event: '.$event->getEval()); + || $existingEvent->getEval() !== $event->getEval() + ) { + + + (new Logger())->info('Existing event: ' . $existingEvent->getActivite()); + (new Logger())->info('New event: ' . $event->getActivite()); + (new Logger())->info('Existing event: ' . $existingEvent->getCouleur()); + (new Logger())->info('New event: ' . $event->getCouleur()); + (new Logger())->info('Existing event: ' . $existingEvent->getSalle()); + (new Logger())->info('New event: ' . $event->getSalle()); + (new Logger())->info('Existing event: ' . $existingEvent->isRepas()); + (new Logger())->info('New event: ' . $event->isRepas()); + (new Logger())->info('Existing event: ' . $existingEvent->isVisio()); + (new Logger())->info('New event: ' . $event->isVisio()); + (new Logger())->info('Existing event: ' . $existingEvent->getEval()); + (new Logger())->info('New event: ' . $event->getEval()); $existingEvent->setActivite($event->getActivite()); $existingEvent->setCouleur($event->getCouleur()); From 4db0178f4789849c904bc252e672ebd5348e8593 Mon Sep 17 00:00:00 2001 From: Jules Artaud Date: Tue, 28 May 2024 11:23:42 +0200 Subject: [PATCH 8/9] :twisted_rightwards_arrows: code review update --- .../android/app/src/main/AndroidManifest.xml | 4 +- .../lib/api/users/models/user_model.dart | 14 ++++++ .../users/repositories/user_repository.dart | 45 ++++++++++--------- .../lib/login/cubit/login_cubit.dart | 30 +++++++------ frontend/app_student/lib/main_dev.dart | 15 +++++++ .../lib/profil/views/profil_page.dart | 8 ++-- .../lib/school_space/views/pdf_view_page.dart | 14 +++++- .../school_space/views/school_space_page.dart | 6 ++- .../school_space/views/widgets/pdf_card.dart | 5 ++- .../lib/shared_components/app_bar.dart | 4 +- .../lib/users/cubit/user_cubit.dart | 10 ++++- 11 files changed, 107 insertions(+), 48 deletions(-) diff --git a/frontend/app_student/android/app/src/main/AndroidManifest.xml b/frontend/app_student/android/app/src/main/AndroidManifest.xml index 80c3a8f..137f378 100644 --- a/frontend/app_student/android/app/src/main/AndroidManifest.xml +++ b/frontend/app_student/android/app/src/main/AndroidManifest.xml @@ -6,7 +6,9 @@ + android:icon="@mipmap/ic_launcher" + android:enableOnBackInvokedCallback="true"> + ? documents) { + return UserModel( + entity: UserEntity( + firstName: firstName, + className: className, + ine: ine, + birthDate: birthDate, + studentId: studentId, + documents: documents?.map((doc) => doc.toEntity()).toList(), + ), + ); + } } diff --git a/frontend/app_student/lib/api/users/repositories/user_repository.dart b/frontend/app_student/lib/api/users/repositories/user_repository.dart index 48f2db6..6d45a36 100644 --- a/frontend/app_student/lib/api/users/repositories/user_repository.dart +++ b/frontend/app_student/lib/api/users/repositories/user_repository.dart @@ -14,7 +14,7 @@ class UserRepository { UserRepository({required this.apiService}); - Future saveUserDetails(UserModel user) async { + Future createUser(UserModel user) async { SharedPreferences prefs = await SharedPreferences.getInstance(); String userJson = jsonEncode(user.toJson()); await prefs.setString('user', userJson); @@ -43,33 +43,21 @@ class UserRepository { await prefs.remove('className'); } - Future login(String username, String password) async { + Future login(String ine, String birthDate) async { final response = await http.post( Uri.parse('${apiService.apiUrl}/api/student/login'), - body: {'username': username, 'password': password}, + body: {'username': ine, 'password': birthDate}, ); if (response.statusCode == 200) { final data = jsonDecode(response.body); final studentId = (data['studentId']); - File? marksFile; - File? absencesFile; - + List documents = []; if (studentId != null) { - marksFile = await downloadFile( - 'https://api-dev.lukasvalois.com/api/student/marks/$studentId', - 'marks.pdf'); - absencesFile = await downloadFile( - 'https://api-dev.lukasvalois.com/api/student/absences/$studentId', - 'absences.pdf'); + documents = await downloadStudentFiles(studentId); } - final marksDocument = DocumentEntity(title: 'Marks', file: marksFile!); - - final absencesDocument = - DocumentEntity(title: 'Absences', file: absencesFile!); - // Get the current user from the cache UserModel user; try { @@ -80,15 +68,14 @@ class UserRepository { // Update the user data user.entity.firstName = user.entity.firstName; - user.entity.ine = username; + user.entity.ine = ine; DateFormat format = DateFormat('dd/MM/yyyy'); - user.entity.birthDate = format.parse(password); + user.entity.birthDate = format.parse(birthDate); user.entity.className = user.entity.className; user.entity.studentId = studentId ?? ''; - user.entity.documents = [marksDocument, absencesDocument]; + user.entity.documents = documents; - // Save the user details in the cache - await saveUserDetails(user); + await createUser(user); return user; } else { @@ -110,4 +97,18 @@ class UserRepository { throw Exception('Failed to download file'); } } + + Future> downloadStudentFiles(int studentId) async { + final marksFile = await downloadFile( + '${apiService.apiUrl}/api/student/marks/$studentId', 'notes.pdf'); + final absencesFile = await downloadFile( + '${apiService.apiUrl}/api/student/absences/$studentId', 'absences.pdf'); + + final marksDocument = + DocumentEntity(title: 'Relevé de notes', file: marksFile); + final absencesDocument = + DocumentEntity(title: "Relevé d'absences", file: absencesFile); + + return [marksDocument, absencesDocument]; + } } diff --git a/frontend/app_student/lib/login/cubit/login_cubit.dart b/frontend/app_student/lib/login/cubit/login_cubit.dart index 622d54e..35d0a9f 100644 --- a/frontend/app_student/lib/login/cubit/login_cubit.dart +++ b/frontend/app_student/lib/login/cubit/login_cubit.dart @@ -1,7 +1,7 @@ import 'package:app_student/api/users/repositories/user_repository.dart'; import 'package:bloc/bloc.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:meta/meta.dart'; -import '../../api/users/entities/user_entity.dart'; import '../../api/users/models/user_model.dart'; part 'login_state.dart'; @@ -26,18 +26,22 @@ class LoginCubit extends Cubit { return; } - UserModel user = UserModel( - entity: UserEntity( - firstName: name, - className: null, - ine: null, - birthDate: null, - studentId: null, - documents: null, - ), - ); - - await userRepository.saveUserDetails(user); + final notificationSettings = await FirebaseMessaging.instance + .requestPermission( + provisional: true, + sound: true, + badge: true, + alert: true, + announcement: false); + + if (notificationSettings.authorizationStatus == + AuthorizationStatus.authorized) { + await FirebaseMessaging.instance.getToken(); + } + + UserModel user = UserModel.create(name, null, null, null, null, null); + + await userRepository.createUser(user); emit(RedirectToClassSelection()); } diff --git a/frontend/app_student/lib/main_dev.dart b/frontend/app_student/lib/main_dev.dart index 1ce1412..b99d7f7 100644 --- a/frontend/app_student/lib/main_dev.dart +++ b/frontend/app_student/lib/main_dev.dart @@ -2,6 +2,8 @@ import 'package:app_student/config/dev_config.dart'; import 'package:app_student/routes.dart'; import 'package:app_student/users/cubit/user_cubit.dart'; import 'package:app_student/utils/custom_theme.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; @@ -16,9 +18,22 @@ import 'config/config.dart'; import 'login/cubit/login_cubit.dart'; import 'utils/global.dart'; +@pragma('vm:entry-point') +Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { + // If you're going to use other Firebase services in the background, such as Firestore, + // make sure you call `initializeApp` before using other Firebase services. + await Firebase.initializeApp(); +} + void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + await Firebase.initializeApp(); + await dotenv.load(); + FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); + initializeDateFormatting('fr_FR', null).then((_) { runApp( MultiRepositoryProvider( diff --git a/frontend/app_student/lib/profil/views/profil_page.dart b/frontend/app_student/lib/profil/views/profil_page.dart index 9a13114..4387428 100644 --- a/frontend/app_student/lib/profil/views/profil_page.dart +++ b/frontend/app_student/lib/profil/views/profil_page.dart @@ -68,10 +68,10 @@ class ProfilPage extends StatelessWidget { ), UserClassCard( className: user.className!, - firstName: user.firstName!, - onTap: () { - context.read().clearUserClass(); - }, + firstName: user.firstName!, onTap: () {}, + // onTap: () { + // context.read().clearUserClass(); + // }, ), UserInfoCard(ine: user.ine!, birthDate: birthDateString), ], diff --git a/frontend/app_student/lib/school_space/views/pdf_view_page.dart b/frontend/app_student/lib/school_space/views/pdf_view_page.dart index 4ca2343..a1331b2 100644 --- a/frontend/app_student/lib/school_space/views/pdf_view_page.dart +++ b/frontend/app_student/lib/school_space/views/pdf_view_page.dart @@ -1,15 +1,25 @@ import 'package:flutter/material.dart'; import 'package:flutter_pdfview/flutter_pdfview.dart'; +import 'package:app_student/shared_components/app_bar.dart'; class PdfViewPage extends StatelessWidget { final String filePath; + final String documentTitle; - const PdfViewPage({super.key, required this.filePath}); + const PdfViewPage( + {super.key, required this.filePath, required this.documentTitle}); @override Widget build(BuildContext context) { return Scaffold( - body: PDFView(filePath: filePath), + appBar: const CustomAppBar(), + body: Column( + children: [ + Expanded( + child: PDFView(filePath: filePath), + ), + ], + ), ); } } diff --git a/frontend/app_student/lib/school_space/views/school_space_page.dart b/frontend/app_student/lib/school_space/views/school_space_page.dart index 73b6c5b..b462418 100644 --- a/frontend/app_student/lib/school_space/views/school_space_page.dart +++ b/frontend/app_student/lib/school_space/views/school_space_page.dart @@ -27,7 +27,9 @@ class SchoolSpacePageState extends State { body: BlocBuilder( builder: (context, state) { if (state is UserLoading) { - return const Text('Loading'); + return const Center( + child: CircularProgressIndicator(), + ); } else if (state is UserLoggedIn) { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -40,7 +42,7 @@ class SchoolSpacePageState extends State { borderRadius: BorderRadius.circular(10.0), ), child: const Text( - 'Votre espace est relié ! Vous pouvez désormais consulter vos notes et absences :).', + 'Votre espace est relié ! Vous pouvez désormais consulter vos notes et absences :)', style: TextStyle( fontSize: 18.0, fontWeight: FontWeight.bold, diff --git a/frontend/app_student/lib/school_space/views/widgets/pdf_card.dart b/frontend/app_student/lib/school_space/views/widgets/pdf_card.dart index 957f2c8..3a12aa7 100644 --- a/frontend/app_student/lib/school_space/views/widgets/pdf_card.dart +++ b/frontend/app_student/lib/school_space/views/widgets/pdf_card.dart @@ -37,7 +37,10 @@ class PdfCard extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (context) => PdfViewPage(filePath: filePath), + builder: (context) => PdfViewPage( + filePath: filePath, + documentTitle: 'Test', + ), ), ); }, diff --git a/frontend/app_student/lib/shared_components/app_bar.dart b/frontend/app_student/lib/shared_components/app_bar.dart index 908c5e3..204d6eb 100644 --- a/frontend/app_student/lib/shared_components/app_bar.dart +++ b/frontend/app_student/lib/shared_components/app_bar.dart @@ -15,9 +15,9 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { Widget build(BuildContext context) { final userState = context.watch().state; String className = ''; - if (userState is UserLoaded) { + if (userState is UserLoggedIn) { className = (userState).user.className ?? ''; - } else if (userState is UserNameLoaded) { + } else if (userState is UserWihtoutLink) { className = (userState).user.className ?? ''; } return AppBar( diff --git a/frontend/app_student/lib/users/cubit/user_cubit.dart b/frontend/app_student/lib/users/cubit/user_cubit.dart index b0a6291..82704e8 100644 --- a/frontend/app_student/lib/users/cubit/user_cubit.dart +++ b/frontend/app_student/lib/users/cubit/user_cubit.dart @@ -1,6 +1,7 @@ import 'package:app_student/api/class_groups/models/class_group_model.dart'; import 'package:app_student/api/users/models/user_model.dart'; import 'package:bloc/bloc.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import '../../api/users/repositories/user_repository.dart'; @@ -47,13 +48,20 @@ class UserCubit extends Cubit { Future saveUserClass(ClassGroupModel classGroup) async { UserModel user = await userRepository.getUser(); user.entity.className = classGroup.name; + await FirebaseMessaging.instance + .subscribeToTopic(classGroup.name.toString().replaceAll(' ', '')); - await userRepository.saveUserDetails(user); + await userRepository.createUser(user); emit(UserWihtoutLink(user)); } Future deleteUser() async { + final user = await userRepository.getUser(); + if (user.className != null) { + await FirebaseMessaging.instance + .unsubscribeFromTopic(user.className.toString().replaceAll(' ', '')); + } await userRepository.delete(); } From 281b169d6d2a7684195f7cd64fcad2652b024b80 Mon Sep 17 00:00:00 2001 From: Jules Artaud Date: Tue, 28 May 2024 11:26:08 +0200 Subject: [PATCH 9/9] :fire: remove useless code --- .../lib/school_space/views/forms/link_account_form.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/app_student/lib/school_space/views/forms/link_account_form.dart b/frontend/app_student/lib/school_space/views/forms/link_account_form.dart index b440cc6..ef42111 100644 --- a/frontend/app_student/lib/school_space/views/forms/link_account_form.dart +++ b/frontend/app_student/lib/school_space/views/forms/link_account_form.dart @@ -14,8 +14,8 @@ class LinkAccountForm extends StatelessWidget { @override Widget build(BuildContext context) { final formKey = GlobalKey(); - String ine = '050223219JD'; - String birthDate = '07/12/2002'; // Set your default birth date here + String ine = ''; + String birthDate = ''; final birthDateController = TextEditingController(text: birthDate); final ineController = TextEditingController(text: ine);