From 68f044de523a526e5f641b9eaa411dc25ebb9705 Mon Sep 17 00:00:00 2001 From: "Fatimah.Alshammari" Date: Wed, 24 Dec 2025 09:54:39 +0300 Subject: [PATCH] added monthly report --- lib/core/dependencies.dart | 7 +- .../monthly_reports/monthly_reports_repo.dart | 96 +++++++++++++++++++ .../monthly_reports_view_model.dart | 33 +++++++ .../terms_conditions_repo.dart | 0 .../terms_conditions_view_model.dart | 2 +- lib/main.dart | 2 +- .../monthly_reports/monthly_reports_page.dart | 51 +++++++--- .../monthly_reports/user_agreement_page.dart | 8 +- lib/routes/app_routes.dart | 14 ++- 9 files changed, 192 insertions(+), 21 deletions(-) create mode 100644 lib/features/monthly_reports/monthly_reports_repo.dart create mode 100644 lib/features/monthly_reports/monthly_reports_view_model.dart rename lib/features/{terms_conditions => monthly_reports}/terms_conditions_repo.dart (100%) rename lib/features/{terms_conditions => monthly_reports}/terms_conditions_view_model.dart (92%) diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index a6699c6..8cc29df 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -31,6 +31,7 @@ import 'package:hmg_patient_app_new/features/location/location_repo.dart'; import 'package:hmg_patient_app_new/features/location/location_view_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; +import 'package:hmg_patient_app_new/features/monthly_reports/monthly_reports_repo.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; @@ -48,6 +49,7 @@ import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_v import 'package:hmg_patient_app_new/features/todo_section/todo_section_repo.dart'; import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart'; import 'package:hmg_patient_app_new/presentation/health_calculators/health_calculator_view_model.dart'; +import 'package:hmg_patient_app_new/presentation/monthly_reports/monthly_reports_page.dart'; import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart'; @@ -62,8 +64,8 @@ import 'package:logger/web.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../features/active_prescriptions/active_prescriptions_repo.dart'; -import '../features/terms_conditions/terms_conditions_repo.dart'; -import '../features/terms_conditions/terms_conditions_view_model.dart'; +import '../features/monthly_reports/terms_conditions_repo.dart'; +import '../features/monthly_reports/terms_conditions_view_model.dart'; GetIt getIt = GetIt.instance; @@ -135,6 +137,7 @@ class AppDependencies { getIt.registerLazySingleton(() => TermsConditionsRepoImp(loggerService: getIt(), apiClient: getIt())); getIt.registerFactory(() => TermsConditionsViewModel(termsConditionsRepo: getIt(), errorHandlerService: getIt(), ),); + getIt.registerLazySingleton(() => MonthlyReportsRepoImp(loggerService: getIt(), apiClient: getIt())); // ViewModels // Global/shared VMs → LazySingleton diff --git a/lib/features/monthly_reports/monthly_reports_repo.dart b/lib/features/monthly_reports/monthly_reports_repo.dart new file mode 100644 index 0000000..4ace6ec --- /dev/null +++ b/lib/features/monthly_reports/monthly_reports_repo.dart @@ -0,0 +1,96 @@ +import 'package:dartz/dartz.dart'; +import '../../core/api/api_client.dart'; +import '../../core/api_consts.dart'; +import '../../core/common_models/generic_api_model.dart'; +import '../../core/exceptions/api_failure.dart'; +import '../../services/logger_service.dart'; + +abstract class MonthlyReportsRepo { + Future>> saveMonthlyReport({ + String? email, + }); +} + +class MonthlyReportsRepoImp implements MonthlyReportsRepo { + final ApiClient apiClient; + final LoggerService loggerService; + + MonthlyReportsRepoImp({ + required this.loggerService, + required this.apiClient, + }); + + @override + Future>> saveMonthlyReport({ + String? email, + }) async { + try { + Failure? failure; + + GenericApiModel? reportApiResponse; + + await apiClient.post( + ApiConsts.getMonthlyReports, + body: {}, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + reportApiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (reportApiResponse == null) return Left(ServerFailure("Unknown error")); + + if ((reportApiResponse!.messageStatus ?? 0) != 1) { + return Right(reportApiResponse!); + } + + GenericApiModel? emailApiResponse; + + final Map emailRequest = {}; + + if (email != null && email.trim().isNotEmpty) { + emailRequest["Email"] = email.trim(); + } + + await apiClient.post( + ApiConsts.updatePatientEmail, + body: emailRequest, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + emailApiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + } catch (e) { + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (emailApiResponse == null) return Left(ServerFailure("Unknown error")); + + return Right(emailApiResponse!); + } catch (e) { + loggerService.logError("MonthlyReportsRepo.saveMonthlyReport error: $e"); + return Left(UnknownFailure(e.toString())); + } + } +} diff --git a/lib/features/monthly_reports/monthly_reports_view_model.dart b/lib/features/monthly_reports/monthly_reports_view_model.dart new file mode 100644 index 0000000..4fd82da --- /dev/null +++ b/lib/features/monthly_reports/monthly_reports_view_model.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/services/error_handler_service.dart'; +import 'monthly_reports_repo.dart'; +class MonthlyReportsViewModel extends ChangeNotifier { + final MonthlyReportsRepo monthlyReportsRepo; + final ErrorHandlerService errorHandlerService; + + bool isLoading = false; + + MonthlyReportsViewModel({ + required this.monthlyReportsRepo, + required this.errorHandlerService, + }); + + Future saveMonthlyReport({String? email}) async { + isLoading = true; + notifyListeners(); + + final result = await monthlyReportsRepo.saveMonthlyReport(email: email); + + final success = result.fold( + (failure) { + errorHandlerService.handleError(failure: failure); + return false; + }, + (apiResponse) => (apiResponse.messageStatus ?? 0) == 1, + ); + + isLoading = false; + notifyListeners(); + return success; + } +} diff --git a/lib/features/terms_conditions/terms_conditions_repo.dart b/lib/features/monthly_reports/terms_conditions_repo.dart similarity index 100% rename from lib/features/terms_conditions/terms_conditions_repo.dart rename to lib/features/monthly_reports/terms_conditions_repo.dart diff --git a/lib/features/terms_conditions/terms_conditions_view_model.dart b/lib/features/monthly_reports/terms_conditions_view_model.dart similarity index 92% rename from lib/features/terms_conditions/terms_conditions_view_model.dart rename to lib/features/monthly_reports/terms_conditions_view_model.dart index 5d67ae7..bd70b87 100644 --- a/lib/features/terms_conditions/terms_conditions_view_model.dart +++ b/lib/features/monthly_reports/terms_conditions_view_model.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:hmg_patient_app_new/features/terms_conditions/terms_conditions_repo.dart'; +import 'package:hmg_patient_app_new/features/monthly_reports/terms_conditions_repo.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; class TermsConditionsViewModel extends ChangeNotifier { diff --git a/lib/main.dart b/lib/main.dart index 801a54c..714053f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -43,7 +43,7 @@ import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; import 'core/utils/size_utils.dart'; -import 'features/terms_conditions/terms_conditions_view_model.dart'; +import 'features/monthly_reports/terms_conditions_view_model.dart'; import 'firebase_options.dart'; @pragma('vm:entry-point') diff --git a/lib/presentation/monthly_reports/monthly_reports_page.dart b/lib/presentation/monthly_reports/monthly_reports_page.dart index 97cc0e3..78c3f30 100644 --- a/lib/presentation/monthly_reports/monthly_reports_page.dart +++ b/lib/presentation/monthly_reports/monthly_reports_page.dart @@ -3,12 +3,15 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/monthly_reports/monthly_reports_view_model.dart'; import 'package:hmg_patient_app_new/presentation/monthly_reports/user_agreement_page.dart'; +import 'package:provider/provider.dart'; import '../../generated/locale_keys.g.dart'; import '../../theme/colors.dart'; import '../../widgets/appbar/app_bar_widget.dart'; import '../../widgets/input_widget.dart'; +import '../../widgets/loader/bottomsheet_loader.dart'; class MonthlyReportsPage extends StatefulWidget { const MonthlyReportsPage({super.key}); @@ -39,7 +42,25 @@ class _MonthlyReportsPageState extends State { ); } - void _onSavePressed() { + void _showSuccessSnackBar() { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Successfully updated".needTranslation, + style: const TextStyle( + color: AppColors.whiteColor, + fontWeight: FontWeight.w600, + ), + ), + behavior: SnackBarBehavior.floating, + backgroundColor: AppColors.textGreenColor, + duration: const Duration(seconds: 2), + ), + ); + } + + Future _onSavePressed() async { if (!isTermsAccepted) { _showError("Please accept the terms and conditions".needTranslation); return; @@ -51,11 +72,18 @@ class _MonthlyReportsPageState extends State { return; } - setState(() { - isHealthSummaryEnabled = true; - }); + final vm = context.read(); - // TODO: هنا حطي API/logic حق الحفظ + // LoaderBottomSheet.showLoader(); + final ok = await vm.saveMonthlyReport(email: email); + // LoaderBottomSheet.hideLoader(); + + if (ok) { + setState(() => isHealthSummaryEnabled = true); + _showSuccessSnackBar(); + } else { + _showError("Failed to update".needTranslation); + } } @override @@ -87,7 +115,7 @@ class _MonthlyReportsPageState extends State { height: 54.h, alignment: Alignment.center, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: Colors.white, + color: AppColors.whiteColor, borderRadius: (12.r), ), child: Row( @@ -139,7 +167,7 @@ class _MonthlyReportsPageState extends State { child: Text( "Click here".needTranslation, style: TextStyle( - color: AppColors.errorColor, + color: AppColors.primaryRedColor, fontSize: 14.f, fontWeight: FontWeight.w600, ), @@ -179,7 +207,7 @@ class _MonthlyReportsPageState extends State { ), ), child: isTermsAccepted - ? Icon(Icons.check, size: 16.f, color: Colors.white) + ? Icon(Icons.check, size: 16.f, color: AppColors.whiteColor,) : null, ), SizedBox(width: 12.h), @@ -188,7 +216,7 @@ class _MonthlyReportsPageState extends State { style: context.dynamicTextStyle( fontSize: 12.f, fontWeight: FontWeight.w500, - color: const Color(0xFF2E3039), + color: AppColors.textColor, ), ), ], @@ -198,7 +226,8 @@ class _MonthlyReportsPageState extends State { SizedBox(height: 12.h), Text( - "This is monthly health summary report".needTranslation, + "This monthly Health Summary Report reflects the health indicators and analysis results of the latest visits. Please note that this will be sent automatically from the system and it's not considered as an official report so no medical decisions should be taken based on it" + .needTranslation, style: TextStyle( color: AppColors.textColor, fontSize: 10.f, @@ -279,5 +308,3 @@ class _MonthlyReportsPageState extends State { ); } } - - diff --git a/lib/presentation/monthly_reports/user_agreement_page.dart b/lib/presentation/monthly_reports/user_agreement_page.dart index f6379ad..73ea564 100644 --- a/lib/presentation/monthly_reports/user_agreement_page.dart +++ b/lib/presentation/monthly_reports/user_agreement_page.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; -import 'package:hmg_patient_app_new/features/terms_conditions/terms_conditions_view_model.dart'; +import 'package:hmg_patient_app_new/features/monthly_reports/terms_conditions_view_model.dart'; import 'package:provider/provider.dart'; import 'package:webview_flutter/webview_flutter.dart'; @@ -93,14 +93,14 @@ class _UserAgreementPageState extends State { margin: const EdgeInsets.all(16), padding: const EdgeInsets.all(12), decoration: BoxDecoration( - color: Colors.white.withOpacity(0.9), + color: AppColors.whiteColor, borderRadius: BorderRadius.circular(8), ), child: Text( _errorMessage!, textAlign: TextAlign.center, - style: const TextStyle( - color: Colors.red, + style: TextStyle( + color: AppColors.primaryRedColor, fontWeight: FontWeight.w600, ), ), diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 81c5ee4..11c6c00 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -23,7 +23,12 @@ import 'package:hmg_patient_app_new/presentation/symptoms_checker/user_info_sele import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/call_screen.dart'; import 'package:hmg_patient_app_new/splashPage.dart'; +import '../core/dependencies.dart'; +import '../features/monthly_reports/monthly_reports_repo.dart'; +import '../features/monthly_reports/monthly_reports_view_model.dart'; import '../presentation/monthly_reports/monthly_reports_page.dart'; +import '../services/error_handler_service.dart'; +import 'package:provider/provider.dart'; class AppRoutes { static const String initialRoute = '/initialRoute'; @@ -83,7 +88,14 @@ class AppRoutes { // healthCalculatorsPage: (context) => HealthCalculatorsPage(), - monthlyReports: (context) => MonthlyReportsPage() + // monthlyReports: (context) => MonthlyReportsPage() + monthlyReports: (context) => ChangeNotifierProvider( + create: (_) => MonthlyReportsViewModel( + monthlyReportsRepo: getIt(), + errorHandlerService: getIt(), + ), + child: const MonthlyReportsPage(), + ), }; }