diff --git a/assets/images/svg/alarm_clock_icon.svg b/assets/images/svg/alarm_clock_icon.svg
new file mode 100644
index 0000000..50b64bd
--- /dev/null
+++ b/assets/images/svg/alarm_clock_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/email_icon.svg b/assets/images/svg/email_icon.svg
new file mode 100644
index 0000000..9e052e7
--- /dev/null
+++ b/assets/images/svg/email_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/svg/forward_chevron_icon.svg b/assets/images/svg/forward_chevron_icon.svg
new file mode 100644
index 0000000..656d80e
--- /dev/null
+++ b/assets/images/svg/forward_chevron_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/svg/my_account_icon.svg b/assets/images/svg/my_account_icon.svg
new file mode 100644
index 0000000..4bfe5b1
--- /dev/null
+++ b/assets/images/svg/my_account_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/svg/notes_icon.svg b/assets/images/svg/notes_icon.svg
new file mode 100644
index 0000000..5d7ab0e
--- /dev/null
+++ b/assets/images/svg/notes_icon.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/images/svg/select_hospital_icon.svg b/assets/images/svg/select_hospital_icon.svg
new file mode 100644
index 0000000..ce00f8c
--- /dev/null
+++ b/assets/images/svg/select_hospital_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart
index 2fd8082..5e9dbb7 100644
--- a/lib/core/api/api_client.dart
+++ b/lib/core/api/api_client.dart
@@ -26,6 +26,7 @@ abstract class ApiClient {
bool isAllowAny,
bool isExternal,
bool isRCService,
+ bool isPaymentServices,
bool bypassConnectionCheck,
});
@@ -97,6 +98,7 @@ class ApiClientImp implements ApiClient {
bool isAllowAny = false,
bool isExternal = false,
bool isRCService = false,
+ bool isPaymentServices = false,
bool bypassConnectionCheck = false,
}) async {
String url;
@@ -204,7 +206,12 @@ class ApiClientImp implements ApiClient {
} else {
var parsed = json.decode(utf8.decode(response.bodyBytes));
if (isAllowAny) {
- onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage']);
+ if (isPaymentServices) {
+ onSuccess(parsed, statusCode, messageStatus: 1, errorMessage: "");
+ } else {
+ onSuccess(parsed, statusCode,
+ messageStatus: parsed.contains('MessageStatus') ? parsed['MessageStatus'] : 1, errorMessage: parsed.contains('ErrorEndUserMessage') ? parsed['ErrorEndUserMessage'] : "");
+ }
} else {
if (parsed['Response_Message'] != null) {
onSuccess(parsed, statusCode, messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index bad2e4c..42f10f4 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -726,7 +726,7 @@ const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_In
class ApiConsts {
static const maxSmallScreen = 660;
- static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
+ static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index d0acea0..23945d0 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -93,7 +93,13 @@ class AppAssets {
static const String checkin_location_icon = '$svgBasePath/checkin_location_icon.svg';
static const String checkin_nfc_icon = '$svgBasePath/checkin_nfc_icon.svg';
static const String checkin_qr_icon = '$svgBasePath/checkin_qr_icon.svg';
+ static const String my_account_icon = '$svgBasePath/my_account_icon.svg';
+ static const String select_hospital_icon = '$svgBasePath/select_hospital_icon.svg';
+ static const String email_icon = '$svgBasePath/email_icon.svg';
+ static const String notes_icon = '$svgBasePath/notes_icon.svg';
+ static const String forward_chevron_icon = '$svgBasePath/forward_chevron_icon.svg';
static const String logout = '$svgBasePath/logout.svg';
+ static const String alarm_clock_icon = '$svgBasePath/alarm_clock_icon.svg';
//bottom navigation//
static const String homeBottom = '$svgBasePath/home_bottom.svg';
diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart
index 0afa53c..0edec4e 100644
--- a/lib/core/dependencies.dart
+++ b/lib/core/dependencies.dart
@@ -7,6 +7,8 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_repo.
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/common/common_repo.dart';
+import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_repo.dart';
+import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_repo.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
@@ -85,6 +87,7 @@ class AppDependencies {
getIt.registerLazySingleton(() => InsuranceRepoImp(loggerService: getIt(), apiClient: getIt()));
getIt.registerLazySingleton(() => PayfortRepoImp(loggerService: getIt(), apiClient: getIt()));
getIt.registerLazySingleton(() => LocalAuthService(loggerService: getIt(), localAuth: getIt()));
+ getIt.registerLazySingleton(() => HabibWalletRepoImp(loggerService: getIt(), apiClient: getIt()));
// ViewModels
// Global/shared VMs → LazySingleton
@@ -125,24 +128,24 @@ class AppDependencies {
);
getIt.registerLazySingleton(
- () => PayfortViewModel(
+ () => PayfortViewModel(
payfortRepo: getIt(),
errorHandlerService: getIt(),
),
);
- getIt.registerLazySingleton(
- () => AuthenticationViewModel(
- authenticationRepo: getIt(),
- cacheService: getIt(),
- navigationService: getIt(),
- dialogService: getIt(),
- appState: getIt(),
+ getIt.registerLazySingleton(
+ () => HabibWalletViewModel(
+ habibWalletRepo: getIt(),
errorHandlerService: getIt(),
- localAuthService: getIt()
),
);
+ getIt.registerLazySingleton(
+ () => AuthenticationViewModel(
+ authenticationRepo: getIt(), cacheService: getIt(), navigationService: getIt(), dialogService: getIt(), appState: getIt(), errorHandlerService: getIt(), localAuthService: getIt()),
+ );
+
// Screen-specific VMs → Factory
// getIt.registerFactory(
// () => BookAppointmentsViewModel(
diff --git a/lib/core/utils/request_utils.dart b/lib/core/utils/request_utils.dart
index fb6624d..fc9815d 100644
--- a/lib/core/utils/request_utils.dart
+++ b/lib/core/utils/request_utils.dart
@@ -65,7 +65,7 @@ class RequestUtils {
required String? deviceToken,
required bool patientOutSA,
required String? loginTokenID,
- required RegistrationDataModelPayload registeredData,
+ RegistrationDataModelPayload? registeredData,
int? patientId,
required String nationIdText,
required String countryCode,
diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart
index ebb7037..a330879 100644
--- a/lib/core/utils/utils.dart
+++ b/lib/core/utils/utils.dart
@@ -568,9 +568,10 @@ class Utils {
);
}
- static Widget getPaymentAmountWithSymbol(Widget paymentAmountWidget, Color iconColor, double iconSize, {bool isSaudiCurrency = true}) {
+ static Widget getPaymentAmountWithSymbol(Widget paymentAmountWidget, Color iconColor, double iconSize, {bool isSaudiCurrency = true, bool isExpanded = true}) {
return Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ mainAxisAlignment: isExpanded ? MainAxisAlignment.spaceBetween : MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.end,
children: [
appState.isArabic()
? Container()
diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart
index 95f821f..2c6cad8 100644
--- a/lib/features/authentication/authentication_view_model.dart
+++ b/lib/features/authentication/authentication_view_model.dart
@@ -82,7 +82,7 @@ class AuthenticationViewModel extends ChangeNotifier {
String errorMsg = '';
final FocusNode myFocusNode = FocusNode();
var healthId;
- int getDeviceLastLogin =1;
+ int getDeviceLastLogin = 1;
Future onLoginPressed() async {
try {
@@ -297,12 +297,11 @@ class AuthenticationViewModel extends ChangeNotifier {
} else if (apiResponse.messageStatus == 1) {
if (apiResponse.data['isSMSSent']) {
_appState.setAppAuthToken = apiResponse.data['LogInTokenID'];
- await sendActivationCode(
+ await sendActivationCode(
otpTypeEnum: otpTypeEnum,
phoneNumber: phoneNumberController.text,
nationalIdOrFileNumber: nationalIdController.text,
);
-
} else {
if (apiResponse.data['IsAuthenticated']) {
await checkActivationCode(
@@ -310,7 +309,6 @@ class AuthenticationViewModel extends ChangeNotifier {
onWrongActivationCode: (String? message) {},
activationCode: null, //todo silent login case halded on the repo itself..
);
-
}
}
}
@@ -325,10 +323,13 @@ class AuthenticationViewModel extends ChangeNotifier {
selectedLoginType: otpTypeEnum.toInt(),
zipCode: selectedCountrySignup.countryCode,
nationalId: int.parse(nationalIdOrFileNumber),
- isFileNo: isPatientHasFile(request: payload),
+ // isFileNo: isPatientHasFile(request: payload),
+ isFileNo: false,
patientId: 0,
- isForRegister: checkIsUserComingForRegister(request: payload),
- patientOutSA: isPatientOutsideSA(request: payload),
+ isForRegister: false,
+ // isForRegister: checkIsUserComingForRegister(request: payload),
+ patientOutSA: selectedCountrySignup.countryCode == CountryEnum.saudiArabia ? false : true,
+ // patientOutSA: isPatientOutsideSA(request: payload),
payload: payload);
// TODO: GET APP SMS SIGNATURE HERE
@@ -373,19 +374,25 @@ class AuthenticationViewModel extends ChangeNotifier {
required OTPTypeEnum otpTypeEnum,
required Function(String? message) onWrongActivationCode,
}) async {
+ bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true);
+
final request = RequestUtils.getCommonRequestWelcome(
phoneNumber: phoneNumberController.text,
otpTypeEnum: otpTypeEnum,
deviceToken: _appState.deviceToken,
- patientOutSA: _appState.getUserRegistrationPayload.projectOutSa == 1 ? true : false,
+ // patientOutSA: _appState.getUserRegistrationPayload.projectOutSa == 1 ? true : false,
+ patientOutSA: isForRegister
+ ? _appState.getUserRegistrationPayload.projectOutSa == 1
+ ? true
+ : false
+ : _appState.getSelectDeviceByImeiRespModelElement!.outSa!,
loginTokenID: _appState.appAuthToken,
- registeredData: _appState.getUserRegistrationPayload,
+ registeredData: isForRegister ? _appState.getUserRegistrationPayload : null,
nationIdText: nationalIdController.text,
countryCode: selectedCountrySignup.countryCode,
loginType: loginTypeEnum.toInt)
.toJson();
- LoaderBottomSheet.showLoader();
- bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true);
+ LoaderBottomSheet.showLoader();
if (isForRegister) {
if (_appState.getUserRegistrationPayload.patientOutSa == 0) request['DOB'] = _appState.getUserRegistrationPayload.dob;
request['HealthId'] = _appState.getUserRegistrationPayload.healthId;
@@ -425,7 +432,6 @@ class AuthenticationViewModel extends ChangeNotifier {
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
final activation = CheckActivationCode.fromJson(apiResponse.data as Map);
-
if (activation.errorCode == '699') {
// Todo: Hide Loader
// GifLoaderDialogUtils.hideDialog(context);
@@ -443,7 +449,6 @@ class AuthenticationViewModel extends ChangeNotifier {
// Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew));
return;
} else {
-
if (activation.list != null && activation.list!.isNotEmpty) {
_appState.setAuthenticatedUser(activation.list!.first);
}
@@ -453,7 +458,7 @@ class AuthenticationViewModel extends ChangeNotifier {
bool isUserAgreedBefore = await checkIfUserAgreedBefore(request: request);
//updating the last login type in app state to show the fingerprint/face id option on home screen
- if( _appState.getSelectDeviceByImeiRespModelElement !=null) {
+ if (_appState.getSelectDeviceByImeiRespModelElement != null) {
_appState.getSelectDeviceByImeiRespModelElement!.logInType = loginTypeEnum.toInt;
}
LoaderBottomSheet.hideLoader();
@@ -551,12 +556,12 @@ class AuthenticationViewModel extends ChangeNotifier {
loginTypeEnum = (_appState.deviceTypeID == 1 ? LoginTypeEnum.face : LoginTypeEnum.fingerprint);
if (!_appState.isAuthenticated) {
//commenting this api to check either the same flow working or not because this api does not needed further if work fine we will remove this
- // await getPatientDeviceData(loginTypeEnum.toInt);
+ // await getPatientDeviceData(loginTypeEnum.toInt);
await checkActivationCode(otpTypeEnum: OTPTypeEnum.faceIDFingerprint, activationCode: null, onWrongActivationCode: (String? message) {});
- await insertPatientIMEIData(loginTypeEnum.toInt);
+ await insertPatientIMEIData(loginTypeEnum.toInt);
} else {
// authenticated = true;
- await insertPatientIMEIData(loginTypeEnum.toInt);
+ await insertPatientIMEIData(loginTypeEnum.toInt);
}
LoaderBottomSheet.hideLoader();
notifyListeners();
@@ -813,33 +818,30 @@ class AuthenticationViewModel extends ChangeNotifier {
log("Insert IMEI Failed");
}
});
-
}
-
Future getPatientDeviceData(int loginType) async {
final resultEither = await _authenticationRepo.getPatientDeviceData(
patientDeviceDataRequest: GetUserMobileDeviceData(
- deviceToken: _appState.deviceToken,
- deviceTypeId: _appState.getDeviceTypeID(),
- patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!,
- patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType,
- patientOutSa:_appState.getSelectDeviceByImeiRespModelElement!.outSa == true ?1 :0,
- loginType: loginType,
- languageId: _appState.getLanguageID(),
- latitude: _appState.userLat,
- longitude: _appState.userLong,
- mobileNo:_appState.getSelectDeviceByImeiRespModelElement!.mobile! ,
- patientMobileNumber:int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!),
- nationalId:_appState.getSelectDeviceByImeiRespModelElement!.identificationNo)
+ deviceToken: _appState.deviceToken,
+ deviceTypeId: _appState.getDeviceTypeID(),
+ patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!,
+ patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType,
+ patientOutSa: _appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? 1 : 0,
+ loginType: loginType,
+ languageId: _appState.getLanguageID(),
+ latitude: _appState.userLat,
+ longitude: _appState.userLong,
+ mobileNo: _appState.getSelectDeviceByImeiRespModelElement!.mobile!,
+ patientMobileNumber: int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!),
+ nationalId: _appState.getSelectDeviceByImeiRespModelElement!.identificationNo)
.toJson());
resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async {
if (apiResponse.messageStatus == 1) {
- dynamic deviceInfo= apiResponse.data['List_MobileLoginInfo'];
- getDeviceLastLogin = deviceInfo['LoginType'];
+ dynamic deviceInfo = apiResponse.data['List_MobileLoginInfo'];
+ getDeviceLastLogin = deviceInfo['LoginType'];
}
});
-
}
@override
diff --git a/lib/features/habib_wallet/models/habib_wallet_repo.dart b/lib/features/habib_wallet/models/habib_wallet_repo.dart
new file mode 100644
index 0000000..5f47f6c
--- /dev/null
+++ b/lib/features/habib_wallet/models/habib_wallet_repo.dart
@@ -0,0 +1,58 @@
+import 'package:dartz/dartz.dart';
+import 'package:hmg_patient_app_new/core/api/api_client.dart';
+import 'package:hmg_patient_app_new/core/api_consts.dart';
+import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
+import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
+import 'package:hmg_patient_app_new/services/logger_service.dart';
+
+abstract class HabibWalletRepo {
+ Future>> getPatientBalanceAmount();
+}
+
+class HabibWalletRepoImp implements HabibWalletRepo {
+ final ApiClient apiClient;
+ final LoggerService loggerService;
+
+ HabibWalletRepoImp({required this.loggerService, required this.apiClient});
+
+ @override
+ Future>> getPatientBalanceAmount() async {
+ Map mapDevice = {};
+
+ try {
+ GenericApiModel? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ GET_PATIENT_AdVANCE_BALANCE_AMOUNT,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
+ try {
+ // final list = response['ListPLO'];
+ // if (list == null || list.isEmpty) {
+ // throw Exception("lab list is empty");
+ // }
+
+ // final labOrders = list.map((item) => PatientLabOrdersResponseModel.fromJson(item as Map)).toList().cast();
+
+ apiResponse = GenericApiModel(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: response["TotalAdvanceBalanceAmount"],
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
+}
diff --git a/lib/features/habib_wallet/models/habib_wallet_view_model.dart b/lib/features/habib_wallet/models/habib_wallet_view_model.dart
new file mode 100644
index 0000000..64c6ddf
--- /dev/null
+++ b/lib/features/habib_wallet/models/habib_wallet_view_model.dart
@@ -0,0 +1,39 @@
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_repo.dart';
+import 'package:hmg_patient_app_new/services/error_handler_service.dart';
+
+class HabibWalletViewModel extends ChangeNotifier {
+ bool isWalletAmountLoading = false;
+ num habibWalletAmount = 0;
+
+ HabibWalletRepo habibWalletRepo;
+ ErrorHandlerService errorHandlerService;
+
+ HabibWalletViewModel({required this.habibWalletRepo, required this.errorHandlerService});
+
+ initHabibWalletProvider() {
+ isWalletAmountLoading = true;
+ habibWalletAmount = 0;
+ notifyListeners();
+ }
+
+ Future getPatientBalanceAmount({Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await habibWalletRepo.getPatientBalanceAmount();
+
+ result.fold(
+ (failure) async => await errorHandlerService.handleError(failure: failure),
+ (apiResponse) {
+ if (apiResponse.messageStatus == 2) {
+ // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
+ } else if (apiResponse.messageStatus == 1) {
+ habibWalletAmount = apiResponse.data!;
+ isWalletAmountLoading = false;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+}
diff --git a/lib/features/lab/lab_repo.dart b/lib/features/lab/lab_repo.dart
index ede2ec8..f205494 100644
--- a/lib/features/lab/lab_repo.dart
+++ b/lib/features/lab/lab_repo.dart
@@ -7,7 +7,7 @@ import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class LabRepo {
- Future>>> getPatientLabOrders({required String patientId});
+ Future>>> getPatientLabOrders();
}
class LabRepoImp implements LabRepo {
@@ -17,7 +17,7 @@ class LabRepoImp implements LabRepo {
LabRepoImp({required this.loggerService, required this.apiClient});
@override
- Future>>> getPatientLabOrders({required String patientId}) async {
+ Future>>> getPatientLabOrders() async {
Map mapDevice = {};
try {
diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart
index 52f470d..2e481f4 100644
--- a/lib/features/lab/lab_view_model.dart
+++ b/lib/features/lab/lab_view_model.dart
@@ -29,7 +29,7 @@ class LabViewModel extends ChangeNotifier {
}
Future getPatientLabOrders({Function(dynamic)? onSuccess, Function(String)? onError}) async {
- final result = await labRepo.getPatientLabOrders(patientId: "1231755");
+ final result = await labRepo.getPatientLabOrders();
result.fold(
(failure) async => await errorHandlerService.handleError(failure: failure),
diff --git a/lib/features/my_appointments/my_appointments_repo.dart b/lib/features/my_appointments/my_appointments_repo.dart
index 804f9f9..a5528cf 100644
--- a/lib/features/my_appointments/my_appointments_repo.dart
+++ b/lib/features/my_appointments/my_appointments_repo.dart
@@ -32,6 +32,8 @@ abstract class MyAppointmentsRepo {
Future>> sendCheckInNfcRequest(
{required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, required String scannedCode, required int checkInType});
+
+ Future>>> getPatientAppointmentsForTimeLine();
}
class MyAppointmentsRepoImp implements MyAppointmentsRepo {
@@ -395,4 +397,51 @@ class MyAppointmentsRepoImp implements MyAppointmentsRepo {
return Left(UnknownFailure(e.toString()));
}
}
+
+ @override
+ Future>>> getPatientAppointmentsForTimeLine() async {
+ Map mapDevice = {
+ "isDentalAllowedBackend": false,
+ "PatientTypeID": 1,
+ "IsComingFromCOC": false,
+ "PatientType": 1,
+ "IsForTimeLine": true,
+ };
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ GET_PATIENT_APPOINTMENT_HISTORY,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
+ try {
+ final list = response['AppoimentAllHistoryResultList'];
+ // if (list == null || list.isEmpty) {
+ // throw Exception("Appointments list is empty");
+ // }
+
+ final appointmentsList = list.map((item) => PatientAppointmentHistoryResponseModel.fromJson(item as Map)).toList().cast();
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: appointmentsList,
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
}
diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart
index 4a921da..d3121af 100644
--- a/lib/features/my_appointments/my_appointments_view_model.dart
+++ b/lib/features/my_appointments/my_appointments_view_model.dart
@@ -12,12 +12,15 @@ class MyAppointmentsViewModel extends ChangeNotifier {
bool isMyAppointmentsLoading = false;
bool isAppointmentPatientShareLoading = false;
+ bool isTimeLineAppointmentsLoading = false;
List patientAppointmentsHistoryList = [];
List patientUpcomingAppointmentsHistoryList = [];
List patientArrivedAppointmentsHistoryList = [];
+ List patientTimelineAppointmentsList = [];
+
PatientAppointmentShareResponseModel? patientAppointmentShareResponseModel;
MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService});
@@ -31,8 +34,10 @@ class MyAppointmentsViewModel extends ChangeNotifier {
patientAppointmentsHistoryList.clear();
patientUpcomingAppointmentsHistoryList.clear();
patientArrivedAppointmentsHistoryList.clear();
+ patientTimelineAppointmentsList.clear();
isMyAppointmentsLoading = true;
isAppointmentPatientShareLoading = true;
+ isTimeLineAppointmentsLoading = true;
notifyListeners();
}
@@ -46,6 +51,11 @@ class MyAppointmentsViewModel extends ChangeNotifier {
notifyListeners();
}
+ setIsPatientTimeLineAppointmentLoading(bool val) {
+ isTimeLineAppointmentsLoading = val;
+ notifyListeners();
+ }
+
setAppointmentReminder(bool value, PatientAppointmentHistoryResponseModel item) {
int index = patientAppointmentsHistoryList.indexOf(item);
if (index != -1) {
diff --git a/lib/features/payfort/payfort_repo.dart b/lib/features/payfort/payfort_repo.dart
index 565422b..9f836d1 100644
--- a/lib/features/payfort/payfort_repo.dart
+++ b/lib/features/payfort/payfort_repo.dart
@@ -53,7 +53,7 @@ class PayfortRepoImp implements PayfortRepo {
} catch (e) {
failure = DataParsingFailure(e.toString());
}
- }, isAllowAny: true);
+ }, isAllowAny: true, isPaymentServices: true);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
@@ -80,7 +80,7 @@ class PayfortRepoImp implements PayfortRepo {
} catch (e) {
failure = DataParsingFailure(e.toString());
}
- }, isAllowAny: true);
+ }, isAllowAny: true, isPaymentServices: true);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
@@ -109,7 +109,7 @@ class PayfortRepoImp implements PayfortRepo {
} catch (e) {
failure = DataParsingFailure(e.toString());
}
- }, isAllowAny: true, isExternal: true);
+ }, isAllowAny: true, isExternal: true, isPaymentServices: true);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
@@ -139,7 +139,7 @@ class PayfortRepoImp implements PayfortRepo {
} catch (e) {
failure = DataParsingFailure(e.toString());
}
- }, isAllowAny: true);
+ }, isAllowAny: true, isPaymentServices: true);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
diff --git a/lib/main.dart b/lib/main.dart
index 70a2158..2739a6b 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
+import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
@@ -109,6 +110,12 @@ void main() async {
errorHandlerService: getIt(),
),
),
+ ChangeNotifierProvider(
+ create: (_) => HabibWalletViewModel(
+ habibWalletRepo: getIt(),
+ errorHandlerService: getIt(),
+ ),
+ ),
ChangeNotifierProvider(
create: (_) => AuthenticationViewModel(
authenticationRepo: getIt(),
diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart
index 7188620..ee2a042 100644
--- a/lib/presentation/appointments/appointment_details_page.dart
+++ b/lib/presentation/appointments/appointment_details_page.dart
@@ -5,8 +5,6 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
-import 'package:hmg_patient_app_new/core/app_state.dart';
-import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@@ -20,6 +18,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_payment_page.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@@ -58,338 +57,338 @@ class _AppointmentDetailsPageState extends State {
@override
Widget build(BuildContext context) {
- myAppointmentsViewModel = Provider.of(context);
- prescriptionsViewModel = Provider.of(context);
+ myAppointmentsViewModel = Provider.of(context, listen: false);
+ prescriptionsViewModel = Provider.of(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
- appBar: AppBar(
- title: "Appointment Details".needTranslation.toText18(),
- backgroundColor: AppColors.bgScaffoldColor,
- ),
body: Column(
children: [
Expanded(
- child: SingleChildScrollView(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- "Appointment Details".needTranslation.toText20(isBold: true),
- if (AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel))
- CustomButton(
- text: "Report".needTranslation,
- onPressed: () {},
- backgroundColor: AppColors.secondaryLightRedColor,
- borderColor: AppColors.secondaryLightRedColor,
- textColor: AppColors.primaryRedColor,
- fontSize: 14,
- fontWeight: FontWeight.w500,
- borderRadius: 12,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 40.h,
- iconSize: 16.h,
- icon: AppAssets.report_icon,
- iconColor: AppColors.primaryRedColor,
- )
- ],
- ),
- SizedBox(height: 24.h),
- AppointmentDoctorCard(
- patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
- onAskDoctorTap: () {},
- onCancelTap: () async {
- showCommonBottomSheet(context,
- child: Utils.getLoadingWidget(),
- callBackFunc: (str) {},
- title: "",
- height: ResponsiveExtension.screenHeight * 0.3,
- isCloseButtonVisible: false,
- isDismissible: false,
- isFullScreen: false);
- await myAppointmentsViewModel.cancelAppointment(
- patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
- onSuccess: (apiResponse) {
- Navigator.of(context).pop();
- showCommonBottomSheet(context,
- child: Utils.getSuccessWidget(loadingText: "Appointment Cancelled Successfully".needTranslation),
- callBackFunc: (str) {},
- title: "",
- height: ResponsiveExtension.screenHeight * 0.3,
- isCloseButtonVisible: false,
- isDismissible: false,
- isFullScreen: false,
- isSuccessDialog: true);
- });
- Navigator.of(context).pop();
- Navigator.of(context).pop();
- },
- onRescheduleTap: () {},
- ),
- SizedBox(height: 16.h),
- !AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
- ? Column(
- children: [
- Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.whiteColor,
- borderRadius: 20.h,
- hasShadow: false,
+ child: CollapsingListView(
+ title: "Appointment Details".needTranslation,
+ report: () {},
+ child: SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ // Row(
+ // mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ // children: [
+ // "Appointment Details".needTranslation.toText20(isBold: true),
+ // if (AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel))
+ // CustomButton(
+ // text: "Report".needTranslation,
+ // onPressed: () {},
+ // backgroundColor: AppColors.secondaryLightRedColor,
+ // borderColor: AppColors.secondaryLightRedColor,
+ // textColor: AppColors.primaryRedColor,
+ // fontSize: 14,
+ // fontWeight: FontWeight.w500,
+ // borderRadius: 12,
+ // padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ // height: 40.h,
+ // iconSize: 16.h,
+ // icon: AppAssets.report_icon,
+ // iconColor: AppColors.primaryRedColor,
+ // )
+ // ],
+ // ),
+ // SizedBox(height: 24.h),
+ AppointmentDoctorCard(
+ patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
+ onAskDoctorTap: () {},
+ onCancelTap: () async {
+ showCommonBottomSheet(context,
+ child: Utils.getLoadingWidget(),
+ callBackFunc: (str) {},
+ title: "",
+ height: ResponsiveExtension.screenHeight * 0.3,
+ isCloseButtonVisible: false,
+ isDismissible: false,
+ isFullScreen: false);
+ await myAppointmentsViewModel.cancelAppointment(
+ patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
+ onSuccess: (apiResponse) {
+ Navigator.of(context).pop();
+ showCommonBottomSheet(context,
+ child: Utils.getSuccessWidget(loadingText: "Appointment Cancelled Successfully".needTranslation),
+ callBackFunc: (str) {},
+ title: "",
+ height: ResponsiveExtension.screenHeight * 0.3,
+ isCloseButtonVisible: false,
+ isDismissible: false,
+ isFullScreen: false,
+ isSuccessDialog: true);
+ });
+ Navigator.of(context).pop();
+ Navigator.of(context).pop();
+ },
+ onRescheduleTap: () {},
+ ),
+ SizedBox(height: 16.h),
+ !AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
+ ? Column(
+ children: [
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.h,
+ hasShadow: false,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ "Appointment Status".needTranslation.toText16(isBold: true),
+ ],
+ ),
+ SizedBox(height: 4.h),
+ (!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel)
+ ? "Not Confirmed".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500)
+ : "Confirmed".needTranslation.toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)),
+ SizedBox(height: 16.h),
+ Stack(
+ children: [
+ ClipRRect(
+ clipBehavior: Clip.hardEdge,
+ borderRadius: BorderRadius.circular(24),
+ child: Image.network(
+ "https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng",
+ fit: BoxFit.contain,
+ ),
+ ),
+ Positioned(
+ bottom: 0,
+ child: SizedBox(
+ width: MediaQuery.of(context).size.width * 0.785,
+ child: CustomButton(
+ text: "Get Directions".needTranslation,
+ onPressed: () {
+ MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
+ double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName);
+ },
+ backgroundColor: AppColors.textColor.withOpacity(0.8),
+ borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
+ textColor: AppColors.whiteColor,
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12.h,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ icon: AppAssets.directions_icon,
+ iconColor: AppColors.whiteColor,
+ iconSize: 13.h,
+ ).paddingAll(12.h),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
),
- child: Padding(
- padding: EdgeInsets.all(16.h),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
+ SizedBox(height: 16.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.h,
+ hasShadow: false,
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.max,
children: [
- Row(
+ Utils.buildSvgWithAssets(icon: AppAssets.prescription_reminder_icon, width: 35.h, height: 35.h),
+ SizedBox(width: 8.h),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
- "Appointment Status".needTranslation.toText16(isBold: true),
+ LocaleKeys.setReminder.tr(context: context).toText13(isBold: true),
+ "Notify me before the appointment".needTranslation.toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
],
),
- SizedBox(height: 4.h),
- (!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel)
- ? "Not Confirmed".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500)
- : "Confirmed".needTranslation.toText12(color: AppColors.successColor, fontWeight: FontWeight.w500)),
- SizedBox(height: 16.h),
- Stack(
- children: [
- ClipRRect(
- clipBehavior: Clip.hardEdge,
- borderRadius: BorderRadius.circular(24),
- child: Image.network(
- "https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng",
- fit: BoxFit.contain,
- ),
- ),
- Positioned(
- bottom: 0,
- child: SizedBox(
- width: MediaQuery.of(context).size.width * 0.785,
- child: CustomButton(
- text: "Get Directions".needTranslation,
- onPressed: () {
- MapsLauncher.launchCoordinates(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
- double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName);
- },
- backgroundColor: AppColors.textColor.withOpacity(0.8),
- borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
- textColor: AppColors.whiteColor,
- fontSize: 14,
- fontWeight: FontWeight.w500,
- borderRadius: 12.h,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 40.h,
- icon: AppAssets.directions_icon,
- iconColor: AppColors.whiteColor,
- iconSize: 13.h,
- ).paddingAll(12.h),
- ),
- ),
- ],
+ const Spacer(),
+ Switch(
+ activeColor: AppColors.successColor,
+ activeTrackColor: AppColors.successColor.withValues(alpha: .15),
+ value: widget.patientAppointmentHistoryResponseModel.hasReminder!,
+ onChanged: (newValue) {
+ setState(() {
+ myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel);
+ });
+ },
),
],
- ),
+ ).paddingSymmetrical(16.h, 16.h),
),
- ),
- SizedBox(height: 16.h),
- Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.whiteColor,
- borderRadius: 20.h,
- hasShadow: false,
- ),
- child: Row(
- mainAxisSize: MainAxisSize.max,
+ SizedBox(height: 16.h),
+ ],
+ )
+ : Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ "Lab & Radiology".needTranslation.toText18(isBold: true),
+ SizedBox(height: 16.h),
+ GridView(
+ gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13.h, mainAxisSpacing: 13.h, childAspectRatio: 7 / 6),
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
children: [
- Utils.buildSvgWithAssets(icon: AppAssets.prescription_reminder_icon, width: 35.h, height: 35.h),
- SizedBox(width: 8.h),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- LocaleKeys.setReminder.tr(context: context).toText13(isBold: true),
- "Notify me before the appointment".needTranslation.toText11(color: AppColors.textColorLight, weight: FontWeight.w500),
- ],
+ MedicalFileCard(
+ label: LocaleKeys.labResults.tr(context: context),
+ textColor: AppColors.blackColor,
+ backgroundColor: AppColors.whiteColor,
+ svgIcon: AppAssets.lab_result_icon,
+ iconSize: 40,
+ isLargeText: true,
),
- const Spacer(),
- Switch(
- activeColor: AppColors.successColor,
- activeTrackColor: AppColors.successColor.withValues(alpha: .15),
- value: widget.patientAppointmentHistoryResponseModel.hasReminder!,
- onChanged: (newValue) {
- setState(() {
- myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel);
- });
- },
+ MedicalFileCard(
+ label: LocaleKeys.radiology.tr(context: context),
+ textColor: AppColors.blackColor,
+ backgroundColor: AppColors.whiteColor,
+ svgIcon: AppAssets.radiology_icon,
+ iconSize: 40,
+ isLargeText: true,
),
],
- ).paddingSymmetrical(16.h, 16.h),
- ),
- SizedBox(height: 16.h),
- ],
- )
- : Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- "Lab & Radiology".needTranslation.toText18(isBold: true),
- SizedBox(height: 16.h),
- GridView(
- gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13.h, mainAxisSpacing: 13.h, childAspectRatio: 7 / 6),
- physics: NeverScrollableScrollPhysics(),
- shrinkWrap: true,
- children: [
- MedicalFileCard(
- label: LocaleKeys.labResults.tr(context: context),
- textColor: AppColors.blackColor,
- backgroundColor: AppColors.whiteColor,
- svgIcon: AppAssets.lab_result_icon,
- iconSize: 40,
- isLargeText: true,
- ),
- MedicalFileCard(
- label: LocaleKeys.radiology.tr(context: context),
- textColor: AppColors.blackColor,
- backgroundColor: AppColors.whiteColor,
- svgIcon: AppAssets.radiology_icon,
- iconSize: 40,
- isLargeText: true,
- ),
- ],
- ),
- LocaleKeys.prescriptions.tr().toText18(isBold: true),
- SizedBox(height: 16.h),
- Consumer(builder: (context, prescriptionVM, child) {
- return prescriptionVM.isPrescriptionsDetailsLoading
- ? const MoviesShimmerWidget()
- : Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: Colors.white,
- borderRadius: 20.h,
- ),
- child: Padding(
- padding: EdgeInsets.all(16.h),
- child: Column(
- children: [
- ListView.separated(
- itemCount: prescriptionVM.prescriptionDetailsList.length,
- shrinkWrap: true,
- padding: const EdgeInsets.only(left: 0, right: 8),
- physics: NeverScrollableScrollPhysics(),
- itemBuilder: (context, index) {
- return AnimationConfiguration.staggeredList(
- position: index,
- duration: const Duration(milliseconds: 500),
- child: SlideAnimation(
- verticalOffset: 100.0,
- child: FadeInAnimation(
- child: Row(
- children: [
- Utils.buildSvgWithAssets(
- icon: AppAssets.prescription_item_icon,
- width: 40.h,
- height: 40.h,
- ),
- SizedBox(width: 8.h),
- Row(
- mainAxisSize: MainAxisSize.max,
- children: [
- Column(
- children: [
- SizedBox(width: 150.h, child: prescriptionVM.prescriptionDetailsList[index].itemDescription!.toText12(isBold: true, maxLine: 1)),
- SizedBox(
- width: 150.h,
- child:
- "Prescribed By: ${widget.patientAppointmentHistoryResponseModel.doctorTitle} ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}"
- .needTranslation
- .toText10(weight: FontWeight.w500, color: AppColors.greyTextColor, letterSpacing: -0.4),
- ),
- ],
- ),
- SizedBox(width: 68.h),
- Utils.buildSvgWithAssets(
- icon: AppAssets.forward_arrow_icon,
- iconColor: AppColors.blackColor,
- width: 18.h,
- height: 13.h,
- fit: BoxFit.contain,
- ),
- ],
- ),
- ],
+ ),
+ LocaleKeys.prescriptions.tr().toText18(isBold: true),
+ SizedBox(height: 16.h),
+ Consumer(builder: (context, prescriptionVM, child) {
+ return prescriptionVM.isPrescriptionsDetailsLoading
+ ? const MoviesShimmerWidget()
+ : Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: Colors.white,
+ borderRadius: 20.h,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ children: [
+ ListView.separated(
+ itemCount: prescriptionVM.prescriptionDetailsList.length,
+ shrinkWrap: true,
+ padding: const EdgeInsets.only(left: 0, right: 8),
+ physics: NeverScrollableScrollPhysics(),
+ itemBuilder: (context, index) {
+ return AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ verticalOffset: 100.0,
+ child: FadeInAnimation(
+ child: Row(
+ children: [
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.prescription_item_icon,
+ width: 40.h,
+ height: 40.h,
+ ),
+ SizedBox(width: 8.h),
+ Row(
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ Column(
+ children: [
+ SizedBox(width: 150.h, child: prescriptionVM.prescriptionDetailsList[index].itemDescription!.toText12(isBold: true, maxLine: 1)),
+ SizedBox(
+ width: 150.h,
+ child:
+ "Prescribed By: ${widget.patientAppointmentHistoryResponseModel.doctorTitle} ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}"
+ .needTranslation
+ .toText10(weight: FontWeight.w500, color: AppColors.greyTextColor, letterSpacing: -0.4),
+ ),
+ ],
+ ),
+ SizedBox(width: 68.h),
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ iconColor: AppColors.blackColor,
+ width: 18.h,
+ height: 13.h,
+ fit: BoxFit.contain,
+ ),
+ ],
+ ),
+ ],
+ ),
),
),
+ );
+ },
+ separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
+ ).onPress(() {
+ prescriptionVM.setPrescriptionsDetailsLoading();
+ Navigator.of(context).push(
+ FadePage(
+ page: PrescriptionDetailPage(prescriptionsResponseModel: getPrescriptionRequestModel()),
),
);
- },
- separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
- ).onPress(() {
- prescriptionVM.setPrescriptionsDetailsLoading();
- Navigator.of(context).push(
- FadePage(
- page: PrescriptionDetailPage(prescriptionsResponseModel: getPrescriptionRequestModel()),
- ),
- );
- }),
- SizedBox(height: 16.h),
- const Divider(color: AppColors.dividerColor),
- SizedBox(height: 16.h),
- Row(
- children: [
- // Expanded(
- // child: CustomButton(
- // text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? LocaleKeys.resendOrder.tr(context: context) : LocaleKeys.prescriptionDeliveryError.tr(context: context),
- // onPressed: () {},
- // backgroundColor: AppColors.secondaryLightRedColor,
- // borderColor: AppColors.secondaryLightRedColor,
- // textColor: AppColors.primaryRedColor,
- // fontSize: 14,
- // fontWeight: FontWeight.w500,
- // borderRadius: 12.h,
- // height: 40.h,
- // icon: AppAssets.appointment_calendar_icon,
- // iconColor: AppColors.primaryRedColor,
- // iconSize: 16.h,
- // ),
- // ),
- // SizedBox(width: 16.h),
- Expanded(
- child: CustomButton(
- text: "All Prescriptions".needTranslation,
- onPressed: () {
- Navigator.of(context)
- .push(
- FadePage(
- page: PrescriptionsListPage(),
- ),
- )
- .then((val) {
- prescriptionsViewModel.setPrescriptionsDetailsLoading();
- prescriptionsViewModel.getPrescriptionDetails(getPrescriptionRequestModel());
- });
- },
- backgroundColor: AppColors.secondaryLightRedColor,
- borderColor: AppColors.secondaryLightRedColor,
- textColor: AppColors.primaryRedColor,
- fontSize: 14,
- fontWeight: FontWeight.w500,
- borderRadius: 12.h,
- height: 40.h,
- icon: AppAssets.requests,
- iconColor: AppColors.primaryRedColor,
- iconSize: 16.h,
+ }),
+ SizedBox(height: 16.h),
+ const Divider(color: AppColors.dividerColor),
+ SizedBox(height: 16.h),
+ Row(
+ children: [
+ // Expanded(
+ // child: CustomButton(
+ // text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? LocaleKeys.resendOrder.tr(context: context) : LocaleKeys.prescriptionDeliveryError.tr(context: context),
+ // onPressed: () {},
+ // backgroundColor: AppColors.secondaryLightRedColor,
+ // borderColor: AppColors.secondaryLightRedColor,
+ // textColor: AppColors.primaryRedColor,
+ // fontSize: 14,
+ // fontWeight: FontWeight.w500,
+ // borderRadius: 12.h,
+ // height: 40.h,
+ // icon: AppAssets.appointment_calendar_icon,
+ // iconColor: AppColors.primaryRedColor,
+ // iconSize: 16.h,
+ // ),
+ // ),
+ // SizedBox(width: 16.h),
+ Expanded(
+ child: CustomButton(
+ text: "All Prescriptions".needTranslation,
+ onPressed: () {
+ Navigator.of(context)
+ .push(
+ FadePage(
+ page: PrescriptionsListPage(),
+ ),
+ )
+ .then((val) {
+ prescriptionsViewModel.setPrescriptionsDetailsLoading();
+ prescriptionsViewModel.getPrescriptionDetails(getPrescriptionRequestModel());
+ });
+ },
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12.h,
+ height: 40.h,
+ icon: AppAssets.requests,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 16.h,
+ ),
),
- ),
- ],
- ),
- ],
+ ],
+ ),
+ ],
+ ),
),
- ),
- );
- }),
- ],
- ),
- ],
- ).paddingSymmetrical(24.h, 24.h),
+ );
+ }),
+ ],
+ ),
+ ],
+ ).paddingSymmetrical(24.h, 24.h),
+ ),
),
),
Container(
diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart
index 7f2ea9d..baa2af3 100644
--- a/lib/presentation/appointments/appointment_payment_page.dart
+++ b/lib/presentation/appointments/appointment_payment_page.dart
@@ -9,7 +9,6 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
-import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
@@ -22,6 +21,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@@ -55,6 +55,7 @@ class _AppointmentPaymentPageState extends State {
void initState() {
scheduleMicrotask(() {
payfortViewModel.initPayfortViewModel();
+ payfortViewModel.setIsApplePayConfigurationLoading(false);
myAppointmentsViewModel.getPatientShareAppointment(
widget.patientAppointmentHistoryResponseModel.projectID,
widget.patientAppointmentHistoryResponseModel.clinicID,
@@ -71,131 +72,131 @@ class _AppointmentPaymentPageState extends State {
payfortViewModel = Provider.of(context);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
- appBar: AppBar(
- title: "Appointment Payment".needTranslation.toText18(),
- backgroundColor: AppColors.bgScaffoldColor,
- ),
body: Consumer(builder: (context, myAppointmentsVM, child) {
- return myAppointmentsVM.isAppointmentPatientShareLoading
- ? const MoviesShimmerWidget().paddingAll(24.h)
- : Column(
- children: [
- Expanded(
- child: SingleChildScrollView(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- "Appointment Payment".needTranslation.toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
- SizedBox(height: 24.h),
- Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.whiteColor,
- borderRadius: 20.h,
- hasShadow: false,
- ),
- child: Row(
- mainAxisSize: MainAxisSize.max,
- children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
- SizedBox(height: 16.h),
- "Mada".needTranslation.toText16(isBold: true),
- ],
- ),
- SizedBox(width: 8.h),
- const Spacer(),
- Utils.buildSvgWithAssets(
- icon: AppAssets.forward_arrow_icon,
- iconColor: AppColors.blackColor,
- width: 18.h,
- height: 13.h,
- fit: BoxFit.contain,
- ),
- ],
- ).paddingSymmetrical(16.h, 16.h),
- ).paddingSymmetrical(24.h, 0.h).onPress(() {
- selectedPaymentMethod = "MADA";
- openPaymentURL("mada");
- }),
- SizedBox(height: 16.h),
- Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.whiteColor,
- borderRadius: 20.h,
- hasShadow: false,
- ),
- child: Row(
- mainAxisSize: MainAxisSize.max,
- children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- children: [
- Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
- SizedBox(width: 8.h),
- Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h),
- ],
- ),
- SizedBox(height: 16.h),
- "Visa or Mastercard".needTranslation.toText16(isBold: true),
- ],
- ),
- SizedBox(width: 8.h),
- const Spacer(),
- Utils.buildSvgWithAssets(
- icon: AppAssets.forward_arrow_icon,
- iconColor: AppColors.blackColor,
- width: 18.h,
- height: 13.h,
- fit: BoxFit.contain,
- ),
- ],
- ).paddingSymmetrical(16.h, 16.h),
- ).paddingSymmetrical(24.h, 0.h).onPress(() {
- selectedPaymentMethod = "VISA";
- openPaymentURL("visa");
- }),
- SizedBox(height: 16.h),
- Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.whiteColor,
- borderRadius: 20.h,
- hasShadow: false,
- ),
- child: Row(
- mainAxisSize: MainAxisSize.max,
- children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h),
- SizedBox(height: 16.h),
- "Tamara".needTranslation.toText16(isBold: true),
- ],
- ),
- SizedBox(width: 8.h),
- const Spacer(),
- Utils.buildSvgWithAssets(
- icon: AppAssets.forward_arrow_icon,
- iconColor: AppColors.blackColor,
- width: 18.h,
- height: 13.h,
- fit: BoxFit.contain,
- ),
- ],
- ).paddingSymmetrical(16.h, 16.h),
- ).paddingSymmetrical(24.h, 0.h).onPress(() {
- selectedPaymentMethod = "TAMARA";
- openPaymentURL("tamara");
- }),
- ],
- ),
- ),
- ),
- Container(
+ return Column(
+ children: [
+ Expanded(
+ child: CollapsingListView(
+ title: "Appointment Payment".needTranslation,
+ child: SingleChildScrollView(
+ child: myAppointmentsVM.isAppointmentPatientShareLoading
+ ? const MoviesShimmerWidget().paddingAll(24.h)
+ : Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(height: 24.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.h,
+ hasShadow: false,
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Image.asset(AppAssets.mada, width: 72.h, height: 25.h),
+ SizedBox(height: 16.h),
+ "Mada".needTranslation.toText16(isBold: true),
+ ],
+ ),
+ SizedBox(width: 8.h),
+ const Spacer(),
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ iconColor: AppColors.blackColor,
+ width: 18.h,
+ height: 13.h,
+ fit: BoxFit.contain,
+ ),
+ ],
+ ).paddingSymmetrical(16.h, 16.h),
+ ).paddingSymmetrical(24.h, 0.h).onPress(() {
+ selectedPaymentMethod = "MADA";
+ openPaymentURL("mada");
+ }),
+ SizedBox(height: 16.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.h,
+ hasShadow: false,
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ Image.asset(AppAssets.visa, width: 50.h, height: 50.h),
+ SizedBox(width: 8.h),
+ Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ "Visa or Mastercard".needTranslation.toText16(isBold: true),
+ ],
+ ),
+ SizedBox(width: 8.h),
+ const Spacer(),
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ iconColor: AppColors.blackColor,
+ width: 18.h,
+ height: 13.h,
+ fit: BoxFit.contain,
+ ),
+ ],
+ ).paddingSymmetrical(16.h, 16.h),
+ ).paddingSymmetrical(24.h, 0.h).onPress(() {
+ selectedPaymentMethod = "VISA";
+ openPaymentURL("visa");
+ }),
+ SizedBox(height: 16.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.h,
+ hasShadow: false,
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h),
+ SizedBox(height: 16.h),
+ "Tamara".needTranslation.toText16(isBold: true),
+ ],
+ ),
+ SizedBox(width: 8.h),
+ const Spacer(),
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ iconColor: AppColors.blackColor,
+ width: 18.h,
+ height: 13.h,
+ fit: BoxFit.contain,
+ ),
+ ],
+ ).paddingSymmetrical(16.h, 16.h),
+ ).paddingSymmetrical(24.h, 0.h).onPress(() {
+ selectedPaymentMethod = "TAMARA";
+ openPaymentURL("tamara");
+ }),
+ ],
+ ),
+ ),
+ ),
+ ),
+ myAppointmentsVM.isAppointmentPatientShareLoading
+ ? SizedBox.shrink()
+ : Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
@@ -283,7 +284,7 @@ class _AppointmentPaymentPageState extends State {
height: 80.h,
fit: BoxFit.contain,
).paddingSymmetrical(24.h, 0.h).onPress(() {
- payfortVM.setIsApplePayConfigurationLoading(true);
+ // payfortVM.setIsApplePayConfigurationLoading(true);
startApplePay();
}),
SizedBox(height: 12.h),
@@ -291,8 +292,8 @@ class _AppointmentPaymentPageState extends State {
);
}),
),
- ],
- );
+ ],
+ );
}),
);
}
@@ -344,62 +345,74 @@ class _AppointmentPaymentPageState extends State {
// updateTamaraRequestStatus("Failed", "00", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID, num.parse(selectedInstallments), appo);
// }
} else {
- showCommonBottomSheet(context,
- child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
- await payfortViewModel.checkPaymentStatus(
- transactionID: transID,
- onSuccess: (apiResponse) async {
- print(apiResponse.data);
- if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
- await myAppointmentsViewModel.createAdvancePayment(
- paymentMethodName: selectedPaymentMethod,
- projectID: widget.patientAppointmentHistoryResponseModel.projectID,
- clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
- appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
- payedAmount: payfortViewModel.payfortCheckPaymentStatusResponseModel!.amount!,
- paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
- patientID: "4767477",
- patientType: 1,
- onSuccess: (value) async {
- print(value);
- await myAppointmentsViewModel.addAdvanceNumberRequest(
- advanceNumber: Utils.isVidaPlusProject(appState, widget.patientAppointmentHistoryResponseModel.projectID)
- ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString()
- : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(),
- paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
- appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
- onSuccess: (value) async {
- if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) {
- //TODO: Implement LiveCare Check-In API Call
- } else {
- await myAppointmentsViewModel.generateAppointmentQR(
- clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
- projectID: widget.patientAppointmentHistoryResponseModel.projectID,
- appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
- isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!,
- onSuccess: (apiResponse) {
- Future.delayed(Duration(milliseconds: 500), () {
- Navigator.of(context).pop();
- Navigator.pushAndRemoveUntil(
- context,
- FadePage(
- page: LandingNavigation(),
- ),
- (r) => false);
- Navigator.of(context).push(
- FadePage(page: MyAppointmentsPage()),
- );
- });
- });
- }
- });
- });
- } else {}
- });
+ checkPaymentStatus();
// checkPaymentStatus(appo);
}
}
+ void checkPaymentStatus() async {
+ showCommonBottomSheet(context,
+ child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
+ await payfortViewModel.checkPaymentStatus(
+ transactionID: transID,
+ onSuccess: (apiResponse) async {
+ print(apiResponse.data);
+ if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") {
+ await myAppointmentsViewModel.createAdvancePayment(
+ paymentMethodName: selectedPaymentMethod,
+ projectID: widget.patientAppointmentHistoryResponseModel.projectID,
+ clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
+ appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
+ payedAmount: payfortViewModel.payfortCheckPaymentStatusResponseModel!.amount!,
+ paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
+ patientID: "4767477",
+ patientType: 1,
+ onSuccess: (value) async {
+ print(value);
+ await myAppointmentsViewModel.addAdvanceNumberRequest(
+ advanceNumber: Utils.isVidaPlusProject(appState, widget.patientAppointmentHistoryResponseModel.projectID)
+ ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString()
+ : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(),
+ paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!,
+ appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
+ onSuccess: (value) async {
+ if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) {
+ //TODO: Implement LiveCare Check-In API Call
+ } else {
+ await myAppointmentsViewModel.generateAppointmentQR(
+ clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
+ projectID: widget.patientAppointmentHistoryResponseModel.projectID,
+ appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(),
+ isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!,
+ onSuccess: (apiResponse) {
+ Future.delayed(Duration(milliseconds: 500), () {
+ Navigator.of(context).pop();
+ Navigator.pushAndRemoveUntil(
+ context,
+ FadePage(
+ page: LandingNavigation(),
+ ),
+ (r) => false);
+ Navigator.of(context).push(
+ FadePage(page: MyAppointmentsPage()),
+ );
+ });
+ });
+ }
+ });
+ });
+ } else {
+ showCommonBottomSheetWithoutHeight(
+ context,
+ child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation),
+ callBackFunc: () {},
+ isFullScreen: false,
+ isCloseButtonVisible: true,
+ );
+ }
+ });
+ }
+
openPaymentURL(String paymentMethod) {
browser = MyInAppBrowser(onExitCallback: onBrowserExit, onLoadStartCallback: onBrowserLoadStart, context: context);
transID = Utils.getAppointmentTransID(
@@ -433,6 +446,8 @@ class _AppointmentPaymentPageState extends State {
}
startApplePay() async {
+ showCommonBottomSheet(context,
+ child: Utils.getLoadingWidget(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isCloseButtonVisible: false, isDismissible: false, isFullScreen: false);
transID = Utils.getAppointmentTransID(
widget.patientAppointmentHistoryResponseModel.projectID,
widget.patientAppointmentHistoryResponseModel.clinicID,
@@ -447,8 +462,7 @@ class _AppointmentPaymentPageState extends State {
applePayInsertRequest.clientRequestID = transID;
applePayInsertRequest.clinicID = widget.patientAppointmentHistoryResponseModel.clinicID;
- //TODO: Need to pass dynamic params to the payment request instead of static values
- applePayInsertRequest.currency = "SAR";
+ applePayInsertRequest.currency = appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED";
applePayInsertRequest.customerEmail = "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com";
applePayInsertRequest.customerID = appState.getAuthenticatedUser()!.patientId.toString();
applePayInsertRequest.customerName = "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}";
@@ -460,8 +474,8 @@ class _AppointmentPaymentPageState extends State {
applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString();
applePayInsertRequest.channelID = 3;
applePayInsertRequest.patientID = appState.getAuthenticatedUser()!.patientId.toString();
- applePayInsertRequest.patientTypeID = 1;
- applePayInsertRequest.patientOutSA = 0;
+ applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType;
+ applePayInsertRequest.patientOutSA = appState.getAuthenticatedUser()!.outSa;
applePayInsertRequest.appointmentDate = widget.patientAppointmentHistoryResponseModel.appointmentDate;
applePayInsertRequest.appointmentNo = widget.patientAppointmentHistoryResponseModel.appointmentNo;
applePayInsertRequest.orderDescription = "Appointment Payment";
@@ -472,7 +486,7 @@ class _AppointmentPaymentPageState extends State {
applePayInsertRequest.isSchedule = widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? "1" : "0";
applePayInsertRequest.language = appState.isArabic() ? 'ar' : 'en';
applePayInsertRequest.languageID = appState.isArabic() ? 1 : 2;
- applePayInsertRequest.userName = 3628599;
+ applePayInsertRequest.userName = appState.getAuthenticatedUser()!.patientId;
applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html";
applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html";
applePayInsertRequest.paymentOption = "ApplePay";
@@ -499,12 +513,22 @@ class _AppointmentPaymentPageState extends State {
merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier,
applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode,
applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest,
- currency: "SAR",
+ currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED",
onFailed: (failureResult) async {
log("failureResult: ${failureResult.message.toString()}");
+ Navigator.of(context).pop();
+ showCommonBottomSheetWithoutHeight(
+ context,
+ child: Utils.getErrorWidget(loadingText: failureResult.message.toString()),
+ callBackFunc: () {},
+ isFullScreen: false,
+ isCloseButtonVisible: true,
+ );
},
onSucceeded: (successResult) async {
+ Navigator.of(context).pop();
log("successResult: ${successResult.responseMessage.toString()}");
+ checkPaymentStatus();
},
// projectId: appo.projectID,
// serviceTypeEnum: ServiceTypeEnum.appointmentPayment,
diff --git a/lib/presentation/appointments/my_appointments_page.dart b/lib/presentation/appointments/my_appointments_page.dart
index 4a3a46e..5a3205d 100644
--- a/lib/presentation/appointments/my_appointments_page.dart
+++ b/lib/presentation/appointments/my_appointments_page.dart
@@ -1,17 +1,14 @@
import 'dart:async';
-import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
-import 'package:hmg_patient_app_new/core/app_state.dart';
-import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.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/my_appointments/my_appointments_view_model.dart';
-import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
@@ -38,39 +35,33 @@ class _MyAppointmentsPageState extends State {
@override
Widget build(BuildContext context) {
- myAppointmentsViewModel = Provider.of(context);
+ myAppointmentsViewModel = Provider.of(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
- appBar: AppBar(
- title: "Appointments List".needTranslation.toText18(),
- backgroundColor: AppColors.bgScaffoldColor,
- ),
- body: SingleChildScrollView(
- child: Column(
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- "Appointments List".needTranslation.toText24(isBold: true),
- ],
- ).paddingSymmetrical(24.h, 24.h),
- CustomTabBar(
- activeTextColor: Color(0xffED1C2B),
- activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
- tabs: [
- CustomTabBarModel(null, "All Appt.".needTranslation),
- CustomTabBarModel(null, "Upcoming".needTranslation),
- CustomTabBarModel(null, "Completed".needTranslation),
- ],
- onTabChange: (index) {
- print(index);
- myAppointmentsViewModel.onTabChange(index);
- },
- ).paddingSymmetrical(24.h, 0.h),
- Consumer(builder: (context, myAppointmentsVM, child) {
- return getSelectedTabData(myAppointmentsVM.selectedTabIndex, myAppointmentsVM);
- }),
- ],
+ body: CollapsingListView(
+ title: "Appointments List".needTranslation,
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ SizedBox(height: 16.h),
+ CustomTabBar(
+ activeTextColor: Color(0xffED1C2B),
+ activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
+ tabs: [
+ CustomTabBarModel(null, "All Appt.".needTranslation),
+ CustomTabBarModel(null, "Upcoming".needTranslation),
+ CustomTabBarModel(null, "Completed".needTranslation),
+ ],
+ onTabChange: (index) {
+ print(index);
+ myAppointmentsViewModel.onTabChange(index);
+ },
+ ).paddingSymmetrical(24.h, 0.h),
+ Consumer(builder: (context, myAppointmentsVM, child) {
+ return getSelectedTabData(myAppointmentsVM.selectedTabIndex, myAppointmentsVM);
+ }),
+ ],
+ ),
),
),
);
@@ -83,9 +74,9 @@ class _MyAppointmentsPageState extends State {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- SizedBox(height: 24.h),
// Expandable list
ListView.separated(
+ padding: EdgeInsets.only(top: 24.h),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: myAppointmentsVM.isMyAppointmentsLoading
@@ -106,7 +97,6 @@ class _MyAppointmentsPageState extends State {
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
- margin: EdgeInsets.symmetric(vertical: 8.h),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
child: AppointmentCard(
patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index],
@@ -127,7 +117,6 @@ class _MyAppointmentsPageState extends State {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- SizedBox(height: 24.h),
// Expandable list
ListView.separated(
shrinkWrap: true,
@@ -171,7 +160,6 @@ class _MyAppointmentsPageState extends State {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- SizedBox(height: 24.h),
// Expandable list
ListView.separated(
shrinkWrap: true,
@@ -179,32 +167,32 @@ class _MyAppointmentsPageState extends State {
itemCount: myAppointmentsVM.isMyAppointmentsLoading
? 5
: myAppointmentsVM.patientArrivedAppointmentsHistoryList.isNotEmpty
- ? myAppointmentsVM.patientArrivedAppointmentsHistoryList.length
- : 1,
+ ? myAppointmentsVM.patientArrivedAppointmentsHistoryList.length
+ : 1,
itemBuilder: (context, index) {
return myAppointmentsVM.isMyAppointmentsLoading
? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0.h)
: myAppointmentsVM.patientArrivedAppointmentsHistoryList.isNotEmpty
- ? AnimationConfiguration.staggeredList(
- position: index,
- duration: const Duration(milliseconds: 500),
- child: SlideAnimation(
- verticalOffset: 100.0,
- child: FadeInAnimation(
- child: AnimatedContainer(
- duration: Duration(milliseconds: 300),
- curve: Curves.easeInOut,
- margin: EdgeInsets.symmetric(vertical: 8.h),
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
- child: AppointmentCard(
- patientAppointmentHistoryResponseModel: myAppointmentsVM.patientArrivedAppointmentsHistoryList[index],
- myAppointmentsViewModel: myAppointmentsViewModel,
- ),
- ).paddingSymmetrical(24.h, 0.h),
- ),
- ),
- )
- : Utils.getNoDataWidget(context);
+ ? AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ verticalOffset: 100.0,
+ child: FadeInAnimation(
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
+ child: AppointmentCard(
+ patientAppointmentHistoryResponseModel: myAppointmentsVM.patientArrivedAppointmentsHistoryList[index],
+ myAppointmentsViewModel: myAppointmentsViewModel,
+ ),
+ ).paddingSymmetrical(24.h, 0.h),
+ ),
+ ),
+ )
+ : Utils.getNoDataWidget(context);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart
index e9babeb..815443e 100644
--- a/lib/presentation/appointments/widgets/appointment_card.dart
+++ b/lib/presentation/appointments/widgets/appointment_card.dart
@@ -142,7 +142,7 @@ class _AppointmentCardState extends State {
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
- runSpacing: -8.h,
+ runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: widget.patientAppointmentHistoryResponseModel.clinicName!),
AppCustomChipWidget(labelText: widget.patientAppointmentHistoryResponseModel.projectName!),
diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart
index e6d7338..d7b0f68 100644
--- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart
+++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart
@@ -51,7 +51,7 @@ class AppointmentDoctorCard extends StatelessWidget {
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
- runSpacing: -8.h,
+ runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: patientAppointmentHistoryResponseModel.clinicName!),
AppCustomChipWidget(labelText: patientAppointmentHistoryResponseModel.projectName!),
diff --git a/lib/presentation/habib_wallet/habib_wallet_page.dart b/lib/presentation/habib_wallet/habib_wallet_page.dart
new file mode 100644
index 0000000..632b11d
--- /dev/null
+++ b/lib/presentation/habib_wallet/habib_wallet_page.dart
@@ -0,0 +1,109 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/app_state.dart';
+import 'package:hmg_patient_app_new/core/dependencies.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.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/habib_wallet/models/habib_wallet_view_model.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
+import 'package:provider/provider.dart';
+
+class HabibWalletPage extends StatefulWidget {
+ const HabibWalletPage({super.key});
+
+ @override
+ State createState() => _HabibWalletState();
+}
+
+class _HabibWalletState extends State {
+ @override
+ Widget build(BuildContext context) {
+ AppState _appState = getIt.get();
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ body: CollapsingListView(
+ title: LocaleKeys.myWallet.tr(),
+ child: Padding(
+ padding: EdgeInsets.all(24.h),
+ child: SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ width: double.infinity,
+ height: 180.h,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.blackBgColor,
+ borderRadius: 24,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ "${_appState.getAuthenticatedUser()!.firstName!} ${_appState.getAuthenticatedUser()!.lastName!}".toText19(isBold: true, color: AppColors.whiteColor),
+ "MRN: ${_appState.getAuthenticatedUser()!.patientId!}".toText14(weight: FontWeight.w500, color: AppColors.greyTextColor),
+ ],
+ ),
+ Utils.buildSvgWithAssets(icon: AppAssets.habiblogo, width: 24.h, height: 24.h),
+ ],
+ ),
+ Spacer(),
+ LocaleKeys.balanceAmount.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.whiteColor),
+ Consumer(builder: (context, habibWalletVM, child) {
+ return Utils.getPaymentAmountWithSymbol(habibWalletVM.habibWalletAmount.toString().toText32(isBold: true, color: AppColors.whiteColor), AppColors.whiteColor, 13.h,
+ isExpanded: false)
+ .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 40.h);
+ }),
+ ],
+ ),
+ ),
+ ),
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ CustomButton(
+ icon: AppAssets.recharge_icon,
+ iconSize: 21.h,
+ text: "Recharge".needTranslation,
+ onPressed: () {
+ Navigator.of(context).push(
+ FadePage(
+ page: RechargeWalletPage(),
+ ),
+ );
+ },
+ backgroundColor: AppColors.infoColor,
+ borderColor: AppColors.infoColor,
+ textColor: AppColors.whiteColor,
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/habib_wallet/recharge_wallet_page.dart b/lib/presentation/habib_wallet/recharge_wallet_page.dart
new file mode 100644
index 0000000..ff1a505
--- /dev/null
+++ b/lib/presentation/habib_wallet/recharge_wallet_page.dart
@@ -0,0 +1,229 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/app_state.dart';
+import 'package:hmg_patient_app_new/core/dependencies.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.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/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
+import 'package:hmg_patient_app_new/widgets/input_widget.dart';
+
+import 'widgets/select-medical_file.dart';
+
+class RechargeWalletPage extends StatefulWidget {
+ const RechargeWalletPage({super.key});
+
+ @override
+ State createState() => _RechargeWalletPageState();
+}
+
+class _RechargeWalletPageState extends State {
+ FocusNode textFocusNode = FocusNode();
+
+ @override
+ Widget build(BuildContext context) {
+ AppState appState = getIt.get();
+ return Scaffold(
+ backgroundColor: AppColors.bgScaffoldColor,
+ body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: CollapsingListView(
+ title: LocaleKeys.createAdvancedPayment.tr(context: context),
+ child: SingleChildScrollView(
+ child: Padding(
+ padding: EdgeInsets.all(24.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ height: 135.h,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 24.h,
+ hasShadow: false,
+ side: BorderSide(color: AppColors.textColor, width: 2.h),
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ "Enter an amount".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
+ Spacer(),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Utils.getPaymentAmountWithSymbol(
+ SizedBox(
+ width: 150.h,
+ child: TextInputWidget(
+ labelText: "",
+ hintText: "",
+ isEnable: true,
+ prefix: null,
+ isAllowRadius: true,
+ isBorderAllowed: false,
+ isAllowLeadingIcon: true,
+ autoFocus: true,
+ fontSize: 40,
+ padding: EdgeInsets.symmetric(horizontal: 8.h, vertical: 0.h),
+ focusNode: textFocusNode,
+ isWalletAmountInput: true,
+ // leadingIcon: AppAssets.student_card,
+ ),
+ ),
+ AppColors.textColor,
+ 13.h,
+ isExpanded: false),
+ const Spacer(),
+ "SAR".needTranslation.toText20(color: AppColors.greyTextColor, weight: FontWeight.w500),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ SizedBox(height: 24.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 24.h,
+ hasShadow: false,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ children: [
+ Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h),
+ SizedBox(width: 8.h),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.myAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
+ "${LocaleKeys.medicalFile.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}"
+ .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
+ ],
+ ),
+ ],
+ ),
+ Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
+ ],
+ ).onPress(() {
+ // showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: SelectMedicalFile(), callBackFunc: () {}, isFullScreen: false);
+ showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: const MultiPageBottomSheet(), callBackFunc: () {}, isFullScreen: false);
+ }),
+ SizedBox(height: 16.h),
+ Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ children: [
+ Utils.buildSvgWithAssets(icon: AppAssets.select_hospital_icon, width: 40.h, height: 40.h),
+ SizedBox(width: 8.h),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.hospital.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
+ "Olaya".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
+ ],
+ ),
+ ],
+ ),
+ Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ children: [
+ Utils.buildSvgWithAssets(icon: AppAssets.email_icon, width: 40.h, height: 40.h),
+ SizedBox(width: 8.h),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.email.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
+ "${appState.getAuthenticatedUser()!.emailAddress}".toText16(color: AppColors.textColor, weight: FontWeight.w500),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h),
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Row(
+ children: [
+ Utils.buildSvgWithAssets(icon: AppAssets.notes_icon, width: 40.h, height: 40.h),
+ SizedBox(width: 8.h),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.notes.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
+ "Lorem Ipsum".toText16(color: AppColors.textColor, weight: FontWeight.w500),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ )),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 24.h,
+ hasShadow: false,
+ ),
+ child: CustomButton(
+ text: LocaleKeys.next.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.primaryRedColor,
+ borderColor: AppColors.primaryRedColor,
+ textColor: AppColors.whiteColor,
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 50.h,
+ icon: AppAssets.appointment_pay_icon,
+ iconColor: AppColors.whiteColor,
+ iconSize: 18.h,
+ ).paddingSymmetrical(24.h, 24.h),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/habib_wallet/widgets/select-medical_file.dart b/lib/presentation/habib_wallet/widgets/select-medical_file.dart
new file mode 100644
index 0000000..a70edb3
--- /dev/null
+++ b/lib/presentation/habib_wallet/widgets/select-medical_file.dart
@@ -0,0 +1,238 @@
+// import 'package:flutter/cupertino.dart';
+// import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+//
+// class SelectMedicalFile extends StatelessWidget {
+// const SelectMedicalFile({super.key});
+//
+// @override
+// Widget build(BuildContext context) {
+// return Padding(
+// padding: EdgeInsets.all(24.h),
+// child: Column(
+// crossAxisAlignment: CrossAxisAlignment.start,
+// children: [
+// Container()
+// ],
+// ),
+// );
+// }
+// }
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/app_state.dart';
+import 'package:hmg_patient_app_new/core/dependencies.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.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/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+
+class MultiPageBottomSheet extends StatefulWidget {
+ const MultiPageBottomSheet({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _MultiPageBottomSheetState();
+}
+
+class _MultiPageBottomSheetState extends State {
+ final PageController _pageController = PageController();
+ int _currentPage = 0;
+ final int _totalPages = 3;
+
+ late AppState appState;
+
+ @override
+ void dispose() {
+ _pageController.dispose();
+ super.dispose();
+ }
+
+ void _nextPage() {
+ if (_currentPage < _totalPages - 1) {
+ _pageController.animateToPage(
+ _currentPage + 2,
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ );
+ }
+ }
+
+ void _previousPage() {
+ if (_currentPage > 0) {
+ _pageController.previousPage(
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ );
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ appState = getIt.get();
+ return Container(
+ height: MediaQuery.of(context).size.height * 0.38,
+ child: Column(
+ children: [
+ SizedBox(height: 12.h),
+ Expanded(
+ child: PageView(
+ controller: _pageController,
+ onPageChanged: (index) {
+ setState(() {
+ _currentPage = index;
+ });
+ },
+ children: [
+ _buildPage1(),
+ _buildPage2(),
+ _buildPage3(),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget _buildPage1() {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 16.h,
+ hasShadow: false,
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.myMedicalFile.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
+ "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
+ ],
+ ),
+ Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
+ ],
+ ).paddingAll(16.h),
+ ).onPress(() {
+ Navigator.of(context).pop();
+ }),
+ SizedBox(height: 16.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 16.h,
+ hasShadow: false,
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.familyTitle.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
+ "Select a medical file from your family".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
+ ],
+ ),
+ Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
+ ],
+ ).paddingAll(16.h),
+ ),
+ SizedBox(height: 16.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 16.h,
+ hasShadow: false,
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.otherAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500),
+ "Any active medical file from HMG".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
+ ],
+ ),
+ Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h),
+ ],
+ ).paddingAll(16.h),
+ ).onPress(() {
+ _pageController.animateToPage(
+ 2,
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ );
+ }),
+ ],
+ );
+ }
+
+ Widget _buildPage2() {
+ return Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'Page 2: Settings',
+ style: Theme.of(context).textTheme.headlineSmall,
+ ),
+ const SizedBox(height: 16),
+ SwitchListTile(
+ title: const Text('Enable notifications'),
+ value: true,
+ onChanged: (value) {},
+ ),
+ SwitchListTile(
+ title: const Text('Dark mode'),
+ value: false,
+ onChanged: (value) {},
+ ),
+ const ListTile(
+ leading: Icon(Icons.language),
+ title: Text('Language'),
+ subtitle: Text('English'),
+ trailing: Icon(Icons.arrow_forward_ios),
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget _buildPage3() {
+ return Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'Page 3: Summary',
+ style: Theme.of(context).textTheme.headlineSmall,
+ ),
+ const SizedBox(height: 16),
+ const Card(
+ child: Padding(
+ padding: EdgeInsets.all(16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text('Configuration Complete!'),
+ SizedBox(height: 8),
+ Text('Your settings have been saved successfully.'),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart
index 58aff04..b63b404 100644
--- a/lib/presentation/home/landing_page.dart
+++ b/lib/presentation/home/landing_page.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
@@ -10,6 +12,9 @@ import 'package:hmg_patient_app_new/extensions/int_extensions.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/authentication/authentication_view_model.dart';
+import 'package:hmg_patient_app_new/features/habib_wallet/models/habib_wallet_view_model.dart';
+import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/authentication/quick_login.dart';
import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart';
@@ -37,23 +42,40 @@ class LandingPage extends StatefulWidget {
class _LandingPageState extends State {
late final AuthenticationViewModel authVM;
bool isDone = false;
+ late final HabibWalletViewModel habibWalletVM;
+
+ late AppState appState;
+ late MyAppointmentsViewModel myAppointmentsViewModel;
+ late PrescriptionsViewModel prescriptionsViewModel;
+
@override
void initState() {
authVM = context.read();
+ habibWalletVM = context.read();
authVM.savePushTokenToAppState();
if (mounted) {
authVM.checkLastLoginStatus(() {
- showQuickLogin(context);
+ showQuickLogin(context);
});
}
+ scheduleMicrotask(() {
+ if (appState.isAuthenticated) {
+ habibWalletVM.initHabibWalletProvider();
+ habibWalletVM.getPatientBalanceAmount();
+ myAppointmentsViewModel.initAppointmentsViewModel();
+ myAppointmentsViewModel.getPatientAppointments(true, false);
+ prescriptionsViewModel.initPrescriptionsViewModel();
+ }
+ });
super.initState();
}
@override
Widget build(BuildContext context) {
- AppState appState = getIt.get();
+ appState = getIt.get();
NavigationService navigationService = getIt.get();
-
+ myAppointmentsViewModel = Provider.of(context, listen: false);
+ prescriptionsViewModel = Provider.of(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: SingleChildScrollView(
@@ -324,29 +346,22 @@ class _LandingPageState extends State {
void showQuickLogin(BuildContext context) {
showCommonBottomSheetWithoutHeight(
-
context,
title: "",
isCloseButtonVisible: false,
- child:
- StatefulBuilder(
- builder: (context, setState) {
- return QuickLogin(
- isDone: isDone,
- onPressed: () {
- // sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true);
- authVM.loginWithFingerPrintFace((){
-
- isDone = true;
- setState(() {
-
+ child: StatefulBuilder(builder: (context, setState) {
+ return QuickLogin(
+ isDone: isDone,
+ onPressed: () {
+ // sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true);
+ authVM.loginWithFingerPrintFace(() {
+ isDone = true;
+ setState(() {});
});
- });
-
- },
- );
+ },
+ );
}),
- // height: isDone == false ? ResponsiveExtension.screenHeight * 0.5 : ResponsiveExtension.screenHeight * 0.3,
+ // height: isDone == false ? ResponsiveExtension.screenHeight * 0.5 : ResponsiveExtension.screenHeight * 0.3,
isFullScreen: false,
callBackFunc: () {
isDone = true;
diff --git a/lib/presentation/home/widgets/habib_wallet_card.dart b/lib/presentation/home/widgets/habib_wallet_card.dart
index 80855dd..9bb53f5 100644
--- a/lib/presentation/home/widgets/habib_wallet_card.dart
+++ b/lib/presentation/home/widgets/habib_wallet_card.dart
@@ -4,8 +4,12 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.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/habib_wallet/models/habib_wallet_view_model.dart';
+import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
+import 'package:provider/provider.dart';
class HabibWalletCard extends StatelessWidget {
const HabibWalletCard({super.key});
@@ -69,19 +73,21 @@ class HabibWalletCard extends StatelessWidget {
],
),
SizedBox(height: 4.h),
- Row(
- children: [
- Utils.buildSvgWithAssets(
- icon: AppAssets.saudi_riyal_icon,
- iconColor: AppColors.dividerColor,
- width: 24.h,
- height: 24.h,
- fit: BoxFit.contain,
- ),
- SizedBox(width: 8.h),
- "200.18".toText32(isBold: true),
- ],
- ),
+ Consumer(builder: (context, habibWalletVM, child) {
+ return Row(
+ children: [
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.saudi_riyal_icon,
+ iconColor: AppColors.dividerColor,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.contain,
+ ),
+ SizedBox(width: 8.h),
+ habibWalletVM.habibWalletAmount.toString().toText32(isBold: true).toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 40.h),
+ ],
+ );
+ }),
Padding(
padding: EdgeInsets.symmetric(horizontal: 50.h),
child: Row(
@@ -90,7 +96,13 @@ class HabibWalletCard extends StatelessWidget {
SizedBox(width: 2.h),
Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h),
],
- ),
+ ).onPress(() {
+ Navigator.of(context).push(
+ FadePage(
+ page: HabibWalletPage(),
+ ),
+ );
+ }),
),
SizedBox(height: 16.h),
Row(
@@ -103,7 +115,7 @@ class HabibWalletCard extends StatelessWidget {
CustomButton(
icon: AppAssets.recharge_icon,
iconSize: 18.h,
- text: "Recharge",
+ text: "Recharge".needTranslation,
onPressed: () {},
backgroundColor: AppColors.infoColor,
borderColor: AppColors.infoColor,
diff --git a/lib/presentation/insurance/insurance_home_page.dart b/lib/presentation/insurance/insurance_home_page.dart
index 451eeee..dd63e55 100644
--- a/lib/presentation/insurance/insurance_home_page.dart
+++ b/lib/presentation/insurance/insurance_home_page.dart
@@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
@@ -39,52 +40,56 @@ class _InsuranceHomePageState extends State {
@override
Widget build(BuildContext context) {
- insuranceViewModel = Provider.of(context);
+ insuranceViewModel = Provider.of(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
- appBar: AppBar(
- title: LocaleKeys.insurance.tr(context: context).toText18(),
- backgroundColor: AppColors.bgScaffoldColor,
- ),
- body: SingleChildScrollView(
- child: Consumer(builder: (context, insuranceVM, child) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- "${LocaleKeys.insurance.tr(context: context)} ${LocaleKeys.updateInsurance.tr(context: context)}".toText24(isBold: true),
- CustomButton(
- icon: AppAssets.insurance_history_icon,
- iconColor: AppColors.primaryRedColor,
- iconSize: 21.h,
- text: LocaleKeys.history.tr(context: context),
- onPressed: () {
- insuranceVM.setIsInsuranceHistoryLoading(true);
- insuranceVM.getPatientInsuranceCardHistory();
- showCommonBottomSheet(context,
- child: InsuranceHistory(), callBackFunc: (str){}, title: "", height: ResponsiveExtension.screenHeight * 0.65, isCloseButtonVisible: false, isFullScreen: false);
- },
- backgroundColor: AppColors.primaryRedColor.withOpacity(0.1),
- borderColor: AppColors.primaryRedColor.withOpacity(0.0),
- textColor: AppColors.primaryRedColor,
- fontSize: 14,
- fontWeight: FontWeight.w600,
- borderRadius: 12,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 40.h,
- ),
- ],
- ).paddingSymmetrical(24.h, 24.h),
- insuranceVM.isInsuranceLoading
- ? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0)
- : PatientInsuranceCard(
- insuranceCardDetailsModel: insuranceVM.patientInsuranceList.first,
- isInsuranceExpired: DateTime.now().isAfter(DateUtil.convertStringToDate(insuranceVM.patientInsuranceList.first.cardValidTo))),
- ],
- );
- }),
+ body: CollapsingListView(
+ title: "${LocaleKeys.insurance.tr(context: context)} ${LocaleKeys.updateInsurance.tr(context: context)}",
+ history: () {
+ insuranceViewModel.setIsInsuranceHistoryLoading(true);
+ insuranceViewModel.getPatientInsuranceCardHistory();
+ showCommonBottomSheet(context,
+ child: InsuranceHistory(), callBackFunc: (str) {}, title: "", height: ResponsiveExtension.screenHeight * 0.65, isCloseButtonVisible: false, isFullScreen: false);
+ },
+ child: SingleChildScrollView(
+ child: Consumer(builder: (context, insuranceVM, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ // Row(
+ // mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ // children: [
+ // "${LocaleKeys.insurance.tr(context: context)} ${LocaleKeys.updateInsurance.tr(context: context)}".toText24(isBold: true),
+ // CustomButton(
+ // icon: AppAssets.insurance_history_icon,
+ // iconColor: AppColors.primaryRedColor,
+ // iconSize: 21.h,
+ // text: LocaleKeys.history.tr(context: context),
+ // onPressed: () {
+ // },
+ // backgroundColor: AppColors.primaryRedColor.withOpacity(0.1),
+ // borderColor: AppColors.primaryRedColor.withOpacity(0.0),
+ // textColor: AppColors.primaryRedColor,
+ // fontSize: 14,
+ // fontWeight: FontWeight.w600,
+ // borderRadius: 12,
+ // padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ // height: 40.h,
+ // ),
+ // ],
+ // ).paddingSymmetrical(24.h, 24.h),
+ insuranceVM.isInsuranceLoading
+ ? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0)
+ : Padding(
+ padding: EdgeInsets.only(top: 24.h),
+ child: PatientInsuranceCard(
+ insuranceCardDetailsModel: insuranceVM.patientInsuranceList.first,
+ isInsuranceExpired: DateTime.now().isAfter(DateUtil.convertStringToDate(insuranceVM.patientInsuranceList.first.cardValidTo))),
+ ),
+ ],
+ );
+ }),
+ ),
),
);
}
diff --git a/lib/presentation/insurance/widgets/insurance_update_details_card.dart b/lib/presentation/insurance/widgets/insurance_update_details_card.dart
index b6a38b2..aa04d8c 100644
--- a/lib/presentation/insurance/widgets/insurance_update_details_card.dart
+++ b/lib/presentation/insurance/widgets/insurance_update_details_card.dart
@@ -69,7 +69,7 @@ class PatientInsuranceCardUpdateCard extends StatelessWidget {
Wrap(
direction: Axis.horizontal,
spacing: 4.h,
- runSpacing: -8.h,
+ runSpacing: 4.h,
children: [
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
diff --git a/lib/presentation/insurance/widgets/patient_insurance_card.dart b/lib/presentation/insurance/widgets/patient_insurance_card.dart
index 720c452..cf8b7d7 100644
--- a/lib/presentation/insurance/widgets/patient_insurance_card.dart
+++ b/lib/presentation/insurance/widgets/patient_insurance_card.dart
@@ -75,7 +75,7 @@ class PatientInsuranceCard extends StatelessWidget {
Wrap(
direction: Axis.horizontal,
spacing: 4.h,
- runSpacing: -8.h,
+ runSpacing: 4.h,
children: [
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart
index 47951c4..4860bb1 100644
--- a/lib/presentation/medical_file/medical_file_page.dart
+++ b/lib/presentation/medical_file/medical_file_page.dart
@@ -2,18 +2,25 @@ import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.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/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
+import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
+import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
+import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
+import 'package:hmg_patient_app_new/presentation/medical_file/widgets/lab_rad_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_file_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@@ -23,6 +30,8 @@ import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:provider/provider.dart';
+import 'widgets/medical_file_appointment_card.dart';
+
class MedicalFilePage extends StatefulWidget {
MedicalFilePage({super.key});
@@ -33,6 +42,7 @@ class MedicalFilePage extends StatefulWidget {
class _MedicalFilePageState extends State {
late InsuranceViewModel insuranceViewModel;
late AppState appState;
+ late MyAppointmentsViewModel myAppointmentsViewModel;
int currentIndex = 0;
@@ -46,174 +56,174 @@ class _MedicalFilePageState extends State {
@override
Widget build(BuildContext context) {
- insuranceViewModel = Provider.of(context);
+ insuranceViewModel = Provider.of(context, listen: false);
+ myAppointmentsViewModel = Provider.of(context, listen: false);
appState = getIt.get();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
- appBar: AppBar(
- title: const Text('Appointments'),
- backgroundColor: AppColors.bgScaffoldColor,
- ),
body: SingleChildScrollView(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- LocaleKeys.medicalFile.tr(context: context).toText22(isBold: true).paddingSymmetrical(24.h, 0.0),
- SizedBox(height: 16.h),
- TextInputWidget(
- labelText: LocaleKeys.search.tr(context: context),
- hintText: "Type any record",
- controller: TextEditingController(),
- keyboardType: TextInputType.number,
- isEnable: true,
- prefix: null,
- autoFocus: false,
- isBorderAllowed: false,
- isAllowLeadingIcon: true,
- padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
- leadingIcon: AppAssets.student_card,
- ).paddingSymmetrical(24.h, 0.0),
- SizedBox(height: 16.h),
- Container(
- width: double.infinity,
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.whiteColor,
- borderRadius: 24,
- ),
- child: Padding(
- padding: EdgeInsets.all(16.h),
- child: Column(
+ child: Padding(
+ padding: EdgeInsets.only(top: 80.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ LocaleKeys.medicalFile.tr(context: context).toText22(isBold: true).paddingSymmetrical(24.h, 0.0),
+ SizedBox(height: 16.h),
+ TextInputWidget(
+ labelText: LocaleKeys.search.tr(context: context),
+ hintText: "Type any record",
+ controller: TextEditingController(),
+ keyboardType: TextInputType.number,
+ isEnable: true,
+ prefix: null,
+ autoFocus: false,
+ isBorderAllowed: false,
+ isAllowLeadingIcon: true,
+ padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
+ leadingIcon: AppAssets.student_card,
+ ).paddingSymmetrical(24.h, 0.0),
+ SizedBox(height: 16.h),
+ Container(
+ width: double.infinity,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 24,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Image.asset(
+ appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg,
+ width: 56.h,
+ height: 56.h,
+ ),
+ SizedBox(width: 8.h),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true),
+ SizedBox(height: 4.h),
+ Row(
+ children: [
+ CustomButton(
+ icon: AppAssets.file_icon,
+ iconColor: AppColors.blackColor,
+ iconSize: 12.h,
+ text: "File no: ${appState.getAuthenticatedUser()!.patientId}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.normal,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ SizedBox(width: 4.h),
+ CustomButton(
+ text: LocaleKeys.verified.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.normal,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ ],
+ ),
+ ],
+ )
+ ],
+ ),
+ SizedBox(height: 16.h),
+ Divider(color: AppColors.dividerColor, height: 1.h),
+ SizedBox(height: 16.h),
+ Row(
+ children: [
+ CustomButton(
+ text: "${appState.getAuthenticatedUser()!.age} Years Old",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.normal,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ SizedBox(width: 4.h),
+ CustomButton(
+ icon: AppAssets.blood_icon,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 13.h,
+ text: "Blood: ${appState.getUserBloodGroup}",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.normal,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ // SizedBox(width: 4.h),
+ // CustomButton(
+ // icon: AppAssets.insurance_active_icon,
+ // iconColor: AppColors.successColor,
+ // iconSize: 13.h,
+ // text: "Insurance Active",
+ // onPressed: () {},
+ // backgroundColor: AppColors.bgGreenColor.withOpacity(0.20),
+ // borderColor: AppColors.bgGreenColor.withOpacity(0.0),
+ // textColor: AppColors.blackColor,
+ // fontSize: 10,
+ // fontWeight: FontWeight.normal,
+ // borderRadius: 12,
+ // padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ // height: 30.h,
+ // ),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ ],
+ ),
+ ),
+ ).paddingSymmetrical(24.h, 0.0),
+ SizedBox(height: 16.h),
+ Consumer(builder: (context, medicalFileVM, child) {
+ return Column(
children: [
- Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Image.asset(
- appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg,
- width: 56.h,
- height: 56.h,
- ),
- SizedBox(width: 8.h),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true),
- SizedBox(height: 4.h),
- Row(
- children: [
- CustomButton(
- icon: AppAssets.file_icon,
- iconColor: AppColors.blackColor,
- iconSize: 12.h,
- text: "File no: ${appState.getAuthenticatedUser()!.patientId}",
- onPressed: () {},
- backgroundColor: AppColors.greyColor,
- borderColor: AppColors.greyColor,
- textColor: AppColors.blackColor,
- fontSize: 10,
- fontWeight: FontWeight.normal,
- borderRadius: 12,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 30.h,
- ),
- SizedBox(width: 4.h),
- CustomButton(
- text: LocaleKeys.verified.tr(context: context),
- onPressed: () {},
- backgroundColor: AppColors.greyColor,
- borderColor: AppColors.greyColor,
- textColor: AppColors.blackColor,
- fontSize: 10,
- fontWeight: FontWeight.normal,
- borderRadius: 12,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 30.h,
- ),
- ],
- ),
- ],
- )
+ CustomTabBar(
+ activeTextColor: Color(0xffED1C2B),
+ activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
+ tabs: [
+ CustomTabBarModel(AppAssets.myFilesBottom, LocaleKeys.general.tr(context: context).needTranslation),
+ CustomTabBarModel(AppAssets.insurance, LocaleKeys.insurance.tr(context: context)),
+ CustomTabBarModel(AppAssets.requests, LocaleKeys.request.tr(context: context).needTranslation),
+ CustomTabBarModel(AppAssets.more, "More".needTranslation),
],
- ),
- SizedBox(height: 16.h),
- Divider(color: AppColors.dividerColor, height: 1.h),
- SizedBox(height: 16.h),
- Row(
- children: [
- CustomButton(
- text: "${appState.getAuthenticatedUser()!.age} Years Old",
- onPressed: () {},
- backgroundColor: AppColors.greyColor,
- borderColor: AppColors.greyColor,
- textColor: AppColors.blackColor,
- fontSize: 10,
- fontWeight: FontWeight.normal,
- borderRadius: 12,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 30.h,
- ),
- SizedBox(width: 4.h),
- CustomButton(
- icon: AppAssets.blood_icon,
- iconColor: AppColors.primaryRedColor,
- iconSize: 13.h,
- text: "Blood: ${appState.getUserBloodGroup}",
- onPressed: () {},
- backgroundColor: AppColors.greyColor,
- borderColor: AppColors.greyColor,
- textColor: AppColors.blackColor,
- fontSize: 10,
- fontWeight: FontWeight.normal,
- borderRadius: 12,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 30.h,
- ),
- // SizedBox(width: 4.h),
- // CustomButton(
- // icon: AppAssets.insurance_active_icon,
- // iconColor: AppColors.successColor,
- // iconSize: 13.h,
- // text: "Insurance Active",
- // onPressed: () {},
- // backgroundColor: AppColors.bgGreenColor.withOpacity(0.20),
- // borderColor: AppColors.bgGreenColor.withOpacity(0.0),
- // textColor: AppColors.blackColor,
- // fontSize: 10,
- // fontWeight: FontWeight.normal,
- // borderRadius: 12,
- // padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- // height: 30.h,
- // ),
- ],
- ),
- SizedBox(height: 8.h),
+ onTabChange: (index) {
+ print(index);
+ medicalFileVM.onTabChanged(index);
+ },
+ ).paddingSymmetrical(24.h, 0.0),
+ SizedBox(height: 24.h),
+ getSelectedTabData(medicalFileVM.selectedTabIndex),
],
- ),
- ),
- ).paddingSymmetrical(24.h, 0.0),
- SizedBox(height: 16.h),
- Consumer(builder: (context, medicalFileVM, child) {
- return Column(
- children: [
- CustomTabBar(
- activeTextColor: Color(0xffED1C2B),
- activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1),
- tabs: [
- CustomTabBarModel(AppAssets.myFilesBottom, LocaleKeys.general.tr(context: context).needTranslation),
- CustomTabBarModel(AppAssets.insurance, LocaleKeys.insurance.tr(context: context)),
- CustomTabBarModel(AppAssets.requests, LocaleKeys.request.tr(context: context).needTranslation),
- CustomTabBarModel(AppAssets.more, "More".needTranslation),
- ],
- onTabChange: (index) {
- print(index);
- medicalFileVM.onTabChanged(index);
- },
- ).paddingSymmetrical(24.h, 0.0),
- SizedBox(height: 24.h),
- getSelectedTabData(medicalFileVM.selectedTabIndex),
- ],
- );
- }),
- ],
+ );
+ }),
+ ],
+ ),
),
),
);
@@ -224,6 +234,7 @@ class _MedicalFilePageState extends State {
case 0:
//General Tab Data
return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -244,6 +255,179 @@ class _MedicalFilePageState extends State {
),
);
}),
+ Consumer(builder: (context, myAppointmentsVM, child) {
+ return SizedBox(
+ height: 200.h,
+ child: ListView.separated(
+ scrollDirection: Axis.horizontal,
+ padding: EdgeInsets.only(top: 16.h, left: 24.h, right: 24.h, bottom: 0.h),
+ shrinkWrap: true,
+ itemCount: myAppointmentsVM.isMyAppointmentsLoading ? 5 : myAppointmentsVM.patientAppointmentsHistoryList.length,
+ itemBuilder: (context, index) {
+ return AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ horizontalOffset: 100.0,
+ child: FadeInAnimation(
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ child: myAppointmentsVM.isMyAppointmentsLoading
+ ? MedicalFileAppointmentCard(
+ patientAppointmentHistoryResponseModel: PatientAppointmentHistoryResponseModel(),
+ myAppointmentsViewModel: myAppointmentsVM,
+ )
+ : MedicalFileAppointmentCard(
+ patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index],
+ myAppointmentsViewModel: myAppointmentsViewModel,
+ ),
+ ),
+ ),
+ ),
+ );
+ },
+ separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 12.h),
+ ),
+ );
+ }),
+ SizedBox(height: 24.h),
+ "Lab & Radiology".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 16.h),
+ Row(
+ children: [
+ Expanded(
+ child: LabRadCard(
+ icon: AppAssets.lab_result_icon,
+ labelText: LocaleKeys.labResults.tr(context: context),
+ labOrderTests: ["Complete blood count", "Creatinine", "Blood Sugar"],
+ ),
+ ),
+ SizedBox(width: 16.h),
+ Expanded(
+ child: LabRadCard(
+ icon: AppAssets.radiology_icon,
+ labelText: LocaleKeys.radiology.tr(context: context),
+ labOrderTests: ["Chest X-ray", "Abdominal Ultrasound", "Dental X-ray"],
+ ),
+ ),
+ ],
+ ).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 24.h),
+ "Active Medications & Prescriptions".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 16.h),
+ Consumer(builder: (context, prescriptionVM, child) {
+ return prescriptionVM.isPrescriptionsOrdersLoading
+ ? const MoviesShimmerWidget()
+ : Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: Colors.white,
+ borderRadius: 20.h,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ children: [
+ ListView.separated(
+ itemCount: prescriptionVM.patientPrescriptionOrders.length,
+ shrinkWrap: true,
+ padding: const EdgeInsets.only(left: 0, right: 8),
+ physics: NeverScrollableScrollPhysics(),
+ itemBuilder: (context, index) {
+ return AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ verticalOffset: 100.0,
+ child: FadeInAnimation(
+ child: Row(
+ children: [
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.prescription_item_icon,
+ width: 40.h,
+ height: 40.h,
+ ),
+ SizedBox(width: 8.h),
+ Row(
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ Column(
+ children: [
+ // SizedBox(width: 150.h, child: prescriptionVM.prescriptionDetailsList[index].itemDescription!.toText12(isBold: true, maxLine: 1)),
+ // SizedBox(
+ // width: 150.h,
+ // child:
+ // "Prescribed By: ${widget.patientAppointmentHistoryResponseModel.doctorTitle} ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}"
+ // .needTranslation
+ // .toText10(weight: FontWeight.w500, color: AppColors.greyTextColor, letterSpacing: -0.4),
+ // ),
+ ],
+ ),
+ SizedBox(width: 68.h),
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ iconColor: AppColors.blackColor,
+ width: 18.h,
+ height: 13.h,
+ fit: BoxFit.contain,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ },
+ separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
+ ).onPress(() {
+ prescriptionVM.setPrescriptionsDetailsLoading();
+ // Navigator.of(context).push(
+ // FadePage(
+ // page: PrescriptionDetailPage(prescriptionsResponseModel: getPrescriptionRequestModel()),
+ // ),
+ // );
+ }),
+ SizedBox(height: 16.h),
+ const Divider(color: AppColors.dividerColor),
+ SizedBox(height: 16.h),
+ Row(
+ children: [
+ Expanded(
+ child: CustomButton(
+ text: "All Prescriptions".needTranslation,
+ onPressed: () {
+ // Navigator.of(context)
+ // .push(
+ // FadePage(
+ // page: PrescriptionsListPage(),
+ // ),
+ // )
+ // .then((val) {
+ // prescriptionsViewModel.setPrescriptionsDetailsLoading();
+ // prescriptionsViewModel.getPrescriptionDetails(getPrescriptionRequestModel());
+ // });
+ },
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12.h,
+ height: 40.h,
+ icon: AppAssets.requests,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 16.h,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ).paddingSymmetrical(24.h, 0.h);
+ }),
+ SizedBox(height: 24.h),
],
);
case 1:
diff --git a/lib/presentation/medical_file/widgets/lab_rad_card.dart b/lib/presentation/medical_file/widgets/lab_rad_card.dart
new file mode 100644
index 0000000..aa53b2f
--- /dev/null
+++ b/lib/presentation/medical_file/widgets/lab_rad_card.dart
@@ -0,0 +1,65 @@
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.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/theme/colors.dart';
+
+class LabRadCard extends StatelessWidget {
+ LabRadCard({super.key, required this.icon, required this.labelText, required this.labOrderTests});
+
+ String icon;
+ String labelText;
+ List labOrderTests = [];
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: false),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ Utils.buildSvgWithAssets(
+ icon: icon,
+ width: 40.h,
+ height: 40.h,
+ fit: BoxFit.contain,
+ ).toShimmer2(isShow: false, radius: 12.h),
+ SizedBox(width: 8.h),
+ labelText.toText14(isBold: true).toShimmer2(isShow: false, radius: 6.h, height: 32.h),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ ListView.separated(
+ scrollDirection: Axis.vertical,
+ padding: EdgeInsets.zero,
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ itemBuilder: (cxt, index) {
+ return labOrderTests[index].toText12(isBold: true, maxLine: 1).toShimmer2(isShow: false, radius: 6.h, height: 24.h, width: 120.h);
+ },
+ separatorBuilder: (cxt, index) => SizedBox(height: 8.h),
+ itemCount: labOrderTests.length,
+ ),
+ SizedBox(height: 16.h),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ SizedBox.shrink(),
+ Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ width: 15.h,
+ height: 15.h,
+ fit: BoxFit.contain,
+ iconColor: AppColors.textColor
+ ).toShimmer2(isShow: false, radius: 12.h),
+ ],
+ )
+ ],
+ ).paddingAll(16.h),
+ );
+ }
+}
diff --git a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart
new file mode 100644
index 0000000..48cc328
--- /dev/null
+++ b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart
@@ -0,0 +1,181 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/core/app_assets.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
+import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
+import 'package:hmg_patient_app_new/core/utils/utils.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/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
+import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
+import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart';
+import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/appointments/appointment_details_page.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
+import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
+
+class MedicalFileAppointmentCard extends StatelessWidget {
+ MedicalFileAppointmentCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel});
+
+ PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
+ MyAppointmentsViewModel myAppointmentsViewModel;
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ CustomButton(
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false),
+ onPressed: () {},
+ backgroundColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.greyColor : AppColors.secondaryLightRedColor,
+ borderColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.greyLightColor : AppColors.secondaryLightRedColor,
+ textColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12.h,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ icon: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppAssets.appointment_calendar_icon : AppAssets.alarm_clock_icon,
+ iconColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor,
+ iconSize: 16.h,
+ ).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
+ SizedBox(height: 16.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
+ width: 200.h,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ Image.network(
+ patientAppointmentHistoryResponseModel.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
+ width: 25.h,
+ height: 27.h,
+ fit: BoxFit.fill,
+ ).circle(100).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
+ SizedBox(width: 8.h),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ (patientAppointmentHistoryResponseModel.doctorNameObj ?? "").toText14(isBold: true, maxlines: 1).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
+ (patientAppointmentHistoryResponseModel.clinicName ?? "")
+ .toText12(maxLine: 1, fontWeight: FontWeight.w500, color: AppColors.greyTextColor)
+ .toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
+ ],
+ ),
+ ),
+ ],
+ ),
+ SizedBox(height: 12.h),
+ Row(
+ children: [
+ myAppointmentsViewModel.isMyAppointmentsLoading
+ ? Container().toShimmer2(isShow: true, height: 40.h, width: 100.h, radius: 12.h)
+ : Expanded(
+ flex: 6,
+ child: AppointmentType.isArrived(patientAppointmentHistoryResponseModel)
+ ? getArrivedAppointmentButton(context).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading)
+ : CustomButton(
+ text: AppointmentType.getNextActionText(patientAppointmentHistoryResponseModel.nextAction),
+ onPressed: () {
+ Navigator.of(context)
+ .push(FadePage(
+ page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
+ ))
+ .then((val) {
+ // widget.myAppointmentsViewModel.initAppointmentsViewModel();
+ // widget.myAppointmentsViewModel.getPatientAppointments(true, false);
+ });
+ },
+ backgroundColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.15),
+ borderColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
+ textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ icon: AppointmentType.getNextActionIcon(patientAppointmentHistoryResponseModel.nextAction),
+ iconColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
+ iconSize: 14.h,
+ ).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
+ ),
+ SizedBox(width: 8.h),
+ Expanded(
+ flex: 2,
+ child: Container(
+ height: 40.h,
+ width: 40.h,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.textColor,
+ borderRadius: 10.h,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(10.h),
+ child: Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ width: 10.h,
+ height: 10.h,
+ fit: BoxFit.contain,
+ ),
+ ),
+ ).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading).onPress(() {
+ Navigator.of(context)
+ .push(
+ FadePage(
+ page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel),
+ ),
+ )
+ .then((val) {
+ // widget.myAppointmentsViewModel.initAppointmentsViewModel();
+ // widget.myAppointmentsViewModel.getPatientAppointments(true, false);
+ });
+ }),
+ ),
+ ],
+ ),
+ ],
+ ).paddingAll(16.h),
+ ),
+ ],
+ );
+ }
+
+ Widget getArrivedAppointmentButton(BuildContext context) {
+ return DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15
+ ? CustomButton(
+ text: LocaleKeys.askDoctor.tr(context: context),
+ onPressed: () {},
+ backgroundColor: AppColors.secondaryLightRedColor,
+ borderColor: AppColors.secondaryLightRedColor,
+ textColor: AppColors.primaryRedColor,
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ icon: AppAssets.ask_doctor_icon,
+ iconColor: AppColors.primaryRedColor,
+ iconSize: 16.h,
+ )
+ : CustomButton(
+ text: "Rebook".needTranslation,
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 14,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ icon: AppAssets.rebook_appointment_icon,
+ iconColor: AppColors.blackColor,
+ iconSize: 16.h,
+ );
+ }
+}
diff --git a/lib/presentation/prescriptions/prescription_detail_page.dart b/lib/presentation/prescriptions/prescription_detail_page.dart
index 8f17c54..b3ace3d 100644
--- a/lib/presentation/prescriptions/prescription_detail_page.dart
+++ b/lib/presentation/prescriptions/prescription_detail_page.dart
@@ -13,6 +13,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_item_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_reminder_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@@ -53,94 +54,91 @@ class _PrescriptionDetailPageState extends State {
prescriptionsViewModel = Provider.of(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
- appBar: AppBar(
- title: LocaleKeys.prescriptions.tr(context: context).toText18(),
- backgroundColor: AppColors.bgScaffoldColor,
- ),
body: Column(
children: [
Expanded(
- child: SingleChildScrollView(
- child: Consumer(builder: (context, prescriptionVM, child) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- LocaleKeys.prescriptions.tr(context: context).toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
- SizedBox(height: 24.h),
- Container(
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.whiteColor,
- borderRadius: 20.h,
- hasShadow: true,
- ),
- child: Padding(
- padding: EdgeInsets.all(16.h),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Image.network(
- widget.prescriptionsResponseModel.doctorImageURL!,
- width: 24.h,
- height: 24.h,
- fit: BoxFit.fill,
- ).circle(100),
- SizedBox(width: 8.h),
- Expanded(child: widget.prescriptionsResponseModel.doctorName!.toText16(isBold: true)),
- ],
- ),
- SizedBox(height: 16.h),
- Wrap(
- direction: Axis.horizontal,
- spacing: 4.h,
- runSpacing: -8.h,
- children: [
- AppCustomChipWidget(
- icon: AppAssets.doctor_calendar_icon,
- labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.prescriptionsResponseModel.appointmentDate), false),
- ),
- AppCustomChipWidget(
- labelText: widget.prescriptionsResponseModel.clinicDescription!,
- ),
- AppCustomChipWidget(
- icon: AppAssets.rating_icon,
- iconColor: AppColors.ratingColorYellow,
- labelText: "Rating: ${widget.prescriptionsResponseModel.decimalDoctorRate}".needTranslation,
- ),
- AppCustomChipWidget(
- labelText: widget.prescriptionsResponseModel.name!,
- ),
- ],
- ),
- ],
+ child: CollapsingListView(
+ title: LocaleKeys.prescriptions.tr(context: context),
+ child: SingleChildScrollView(
+ child: Consumer(builder: (context, prescriptionVM, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(height: 24.h),
+ Container(
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.whiteColor,
+ borderRadius: 20.h,
+ hasShadow: true,
+ ),
+ child: Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Image.network(
+ widget.prescriptionsResponseModel.doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 8.h),
+ Expanded(child: widget.prescriptionsResponseModel.doctorName!.toText16(isBold: true)),
+ ],
+ ),
+ SizedBox(height: 16.h),
+ Wrap(
+ direction: Axis.horizontal,
+ spacing: 4.h,
+ runSpacing: 4.h,
+ children: [
+ AppCustomChipWidget(
+ icon: AppAssets.doctor_calendar_icon,
+ labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.prescriptionsResponseModel.appointmentDate), false),
+ ),
+ AppCustomChipWidget(
+ labelText: widget.prescriptionsResponseModel.clinicDescription!,
+ ),
+ AppCustomChipWidget(
+ icon: AppAssets.rating_icon,
+ iconColor: AppColors.ratingColorYellow,
+ labelText: "Rating: ${widget.prescriptionsResponseModel.decimalDoctorRate}".needTranslation,
+ ),
+ AppCustomChipWidget(
+ labelText: widget.prescriptionsResponseModel.name!,
+ ),
+ ],
+ ),
+ ],
+ ),
),
- ),
- ).paddingSymmetrical(24.h, 0.h),
- SizedBox(height: 16.h),
- ListView.builder(
- shrinkWrap: true,
- physics: NeverScrollableScrollPhysics(),
- itemCount: prescriptionVM.isPrescriptionsDetailsLoading ? 5 : prescriptionVM.prescriptionDetailsList.length,
- itemBuilder: (context, index) {
- return prescriptionVM.isPrescriptionsDetailsLoading
- ? PrescriptionItemView(prescriptionVM: prescriptionVM, index: index, isLoading: true)
- : AnimationConfiguration.staggeredList(
- position: index,
- duration: const Duration(milliseconds: 500),
- child: SlideAnimation(
- verticalOffset: 100.0,
- child: FadeInAnimation(
- child: PrescriptionItemView(prescriptionVM: prescriptionVM, index: index),
+ ).paddingSymmetrical(24.h, 0.h),
+ ListView.builder(
+ shrinkWrap: true,
+ physics: NeverScrollableScrollPhysics(),
+ itemCount: prescriptionVM.isPrescriptionsDetailsLoading ? 5 : prescriptionVM.prescriptionDetailsList.length,
+ itemBuilder: (context, index) {
+ return prescriptionVM.isPrescriptionsDetailsLoading
+ ? PrescriptionItemView(prescriptionVM: prescriptionVM, index: index, isLoading: true)
+ : AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ verticalOffset: 100.0,
+ child: FadeInAnimation(
+ child: PrescriptionItemView(prescriptionVM: prescriptionVM, index: index),
+ ),
),
- ),
- );
- },
- ).paddingSymmetrical(24.h, 0.h),
- ],
- );
- }),
+ );
+ },
+ ).paddingSymmetrical(24.h, 0.h),
+ ],
+ );
+ }),
+ ),
),
),
Container(
diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart
index 9574f28..148afb1 100644
--- a/lib/presentation/prescriptions/prescriptions_list_page.dart
+++ b/lib/presentation/prescriptions/prescriptions_list_page.dart
@@ -11,6 +11,7 @@ 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/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@@ -43,256 +44,252 @@ class _PrescriptionsListPageState extends State {
prescriptionsViewModel = Provider.of(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
- appBar: AppBar(
- title: LocaleKeys.prescriptions.tr(context: context).toText18(),
- backgroundColor: AppColors.bgScaffoldColor,
- ),
- body: SingleChildScrollView(
- child: Consumer(builder: (context, model, child) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- LocaleKeys.prescriptions.tr(context: context).toText24(isBold: true).paddingSymmetrical(24.h, 0.h),
- SizedBox(height: 16.h),
- // Build Tab Bar
- SizedBox(height: 16.h),
- // Clinic & Hospital Sort
- Row(
- children: [
- CustomButton(
- text: LocaleKeys.byClinic.tr(context: context),
- onPressed: () {
- model.setIsSortByClinic(true);
- },
- backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
- borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
- textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
- fontSize: 12,
- fontWeight: FontWeight.w500,
- borderRadius: 10,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 40.h,
- ),
- SizedBox(width: 8.h),
- CustomButton(
- text: LocaleKeys.byHospital.tr(context: context),
- onPressed: () {
- model.setIsSortByClinic(false);
- },
- backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor,
- borderColor: model.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor,
- textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
- fontSize: 12,
- fontWeight: FontWeight.w500,
- borderRadius: 10,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 40.h,
- ),
- ],
- ).paddingSymmetrical(24.h, 0.h),
- SizedBox(height: 20.h),
- // Expandable list
- ListView.builder(
- itemCount: model.isPrescriptionsOrdersLoading ? 4 : model.patientPrescriptionOrdersViewList.length,
- physics: NeverScrollableScrollPhysics(),
- shrinkWrap: true,
- padding: const EdgeInsets.only(left: 0, right: 8),
- itemBuilder: (context, index) {
- final isExpanded = expandedIndex == index;
- return model.isPrescriptionsOrdersLoading
- ? const MoviesShimmerWidget()
- : AnimationConfiguration.staggeredList(
- position: index,
- duration: const Duration(milliseconds: 500),
- child: SlideAnimation(
- verticalOffset: 100.0,
- child: FadeInAnimation(
- child: AnimatedContainer(
- duration: Duration(milliseconds: 300),
- curve: Curves.easeInOut,
- margin: EdgeInsets.symmetric(vertical: 8.h),
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
- child: InkWell(
- onTap: () {
- setState(() {
- expandedIndex = isExpanded ? null : index;
- });
- },
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Padding(
- padding: EdgeInsets.all(16.h),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- CustomButton(
- text: "${model.patientPrescriptionOrdersViewList[index].prescriptionsList!.length} Prescriptions Available",
- onPressed: () {},
- backgroundColor: AppColors.greyColor,
- borderColor: AppColors.greyColor,
- textColor: AppColors.blackColor,
- fontSize: 10,
- fontWeight: FontWeight.w500,
- borderRadius: 8,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 30.h,
- ),
- Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
- ],
- ),
- SizedBox(height: 8.h),
- model.patientPrescriptionOrdersViewList[index].filterName!.toText16(isBold: true)
- ],
+ body: CollapsingListView(
+ title: LocaleKeys.prescriptions.tr(context: context),
+ child: SingleChildScrollView(
+ child: Consumer(builder: (context, model, child) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(height: 16.h),
+ // Clinic & Hospital Sort
+ Row(
+ children: [
+ CustomButton(
+ text: LocaleKeys.byClinic.tr(context: context),
+ onPressed: () {
+ model.setIsSortByClinic(true);
+ },
+ backgroundColor: model.isSortByClinic ? AppColors.bgRedLightColor : AppColors.whiteColor,
+ borderColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.textColor.withOpacity(0.2),
+ textColor: model.isSortByClinic ? AppColors.primaryRedColor : AppColors.blackColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 10,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: LocaleKeys.byHospital.tr(context: context),
+ onPressed: () {
+ model.setIsSortByClinic(false);
+ },
+ backgroundColor: model.isSortByClinic ? AppColors.whiteColor : AppColors.bgRedLightColor,
+ borderColor: model.isSortByClinic ? AppColors.textColor.withOpacity(0.2) : AppColors.primaryRedColor,
+ textColor: model.isSortByClinic ? AppColors.blackColor : AppColors.primaryRedColor,
+ fontSize: 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 10,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ ),
+ ],
+ ).paddingSymmetrical(24.h, 0.h),
+ SizedBox(height: 20.h),
+ // Expandable list
+ ListView.builder(
+ itemCount: model.isPrescriptionsOrdersLoading ? 4 : model.patientPrescriptionOrdersViewList.length,
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ padding: const EdgeInsets.only(left: 0, right: 8),
+ itemBuilder: (context, index) {
+ final isExpanded = expandedIndex == index;
+ return model.isPrescriptionsOrdersLoading
+ ? const MoviesShimmerWidget()
+ : AnimationConfiguration.staggeredList(
+ position: index,
+ duration: const Duration(milliseconds: 500),
+ child: SlideAnimation(
+ verticalOffset: 100.0,
+ child: FadeInAnimation(
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ margin: EdgeInsets.symmetric(vertical: 8.h),
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true),
+ child: InkWell(
+ onTap: () {
+ setState(() {
+ expandedIndex = isExpanded ? null : index;
+ });
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.all(16.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomButton(
+ text: "${model.patientPrescriptionOrdersViewList[index].prescriptionsList!.length} Prescriptions Available",
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 30.h,
+ ),
+ Icon(isExpanded ? Icons.expand_less : Icons.expand_more),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ model.patientPrescriptionOrdersViewList[index].filterName!.toText16(isBold: true)
+ ],
+ ),
),
- ),
- AnimatedSwitcher(
- duration: Duration(milliseconds: 500),
- switchInCurve: Curves.easeIn,
- switchOutCurve: Curves.easeOut,
- transitionBuilder: (Widget child, Animation animation) {
- return FadeTransition(
- opacity: animation,
- child: SizeTransition(
- sizeFactor: animation,
- axisAlignment: 0.0,
- child: child,
- ),
- );
- },
- child: isExpanded
- ? Container(
- key: ValueKey(index),
- padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- ...model.patientPrescriptionOrdersViewList[index].prescriptionsList!.map((prescription) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Image.network(
- prescription.doctorImageURL!,
- width: 24.h,
- height: 24.h,
- fit: BoxFit.fill,
- ).circle(100),
- SizedBox(width: 8.h),
- Expanded(child: prescription.doctorName!.toText14(weight: FontWeight.w500)),
- ],
- ),
- SizedBox(height: 8.h),
- Row(
- children: [
- CustomButton(
- text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false),
- onPressed: () {},
- backgroundColor: AppColors.greyColor,
- borderColor: AppColors.greyColor,
- textColor: AppColors.blackColor,
- fontSize: 10,
- fontWeight: FontWeight.w500,
- borderRadius: 8,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 24.h,
- ),
- SizedBox(width: 8.h),
- CustomButton(
- text: model.isSortByClinic ? prescription.name! : prescription.clinicDescription!,
- onPressed: () {},
- backgroundColor: AppColors.greyColor,
- borderColor: AppColors.greyColor,
- textColor: AppColors.blackColor,
- fontSize: 10,
- fontWeight: FontWeight.w500,
- borderRadius: 8,
- padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 24.h,
- ),
- ],
- ),
- SizedBox(height: 8.h),
- Row(
- children: [
- Expanded(
- flex: 6,
- child: CustomButton(
- text: prescription.isHomeMedicineDeliverySupported!
- ? LocaleKeys.resendOrder.tr(context: context)
- : LocaleKeys.prescriptionDeliveryError.tr(context: context),
+ AnimatedSwitcher(
+ duration: Duration(milliseconds: 500),
+ switchInCurve: Curves.easeIn,
+ switchOutCurve: Curves.easeOut,
+ transitionBuilder: (Widget child, Animation animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: SizeTransition(
+ sizeFactor: animation,
+ axisAlignment: 0.0,
+ child: child,
+ ),
+ );
+ },
+ child: isExpanded
+ ? Container(
+ key: ValueKey(index),
+ padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ...model.patientPrescriptionOrdersViewList[index].prescriptionsList!.map((prescription) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Image.network(
+ prescription.doctorImageURL!,
+ width: 24.h,
+ height: 24.h,
+ fit: BoxFit.fill,
+ ).circle(100),
+ SizedBox(width: 8.h),
+ Expanded(child: prescription.doctorName!.toText14(weight: FontWeight.w500)),
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ CustomButton(
+ text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescription.appointmentDate), false),
+ onPressed: () {},
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
+ fontWeight: FontWeight.w500,
+ borderRadius: 8,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 24.h,
+ ),
+ SizedBox(width: 8.h),
+ CustomButton(
+ text: model.isSortByClinic ? prescription.name! : prescription.clinicDescription!,
onPressed: () {},
- backgroundColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor.withOpacity(0.15) : AppColors.greyF7Color,
- borderColor: AppColors.successColor.withOpacity(0.01),
- textColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
- fontSize: prescription.isHomeMedicineDeliverySupported! ? 14 : 12,
+ backgroundColor: AppColors.greyColor,
+ borderColor: AppColors.greyColor,
+ textColor: AppColors.blackColor,
+ fontSize: 10,
fontWeight: FontWeight.w500,
- borderRadius: 12,
+ borderRadius: 8,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
- height: 40.h,
- icon: AppAssets.prescription_refill_icon,
- iconColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
- iconSize: 14.h,
+ height: 24.h,
),
- ),
- SizedBox(width: 8.h),
- Expanded(
- flex: 1,
- child: Container(
- height: 40.h,
- width: 40.h,
- decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
- color: AppColors.textColor,
- borderRadius: 10.h,
+ ],
+ ),
+ SizedBox(height: 8.h),
+ Row(
+ children: [
+ Expanded(
+ flex: 6,
+ child: CustomButton(
+ text: prescription.isHomeMedicineDeliverySupported!
+ ? LocaleKeys.resendOrder.tr(context: context)
+ : LocaleKeys.prescriptionDeliveryError.tr(context: context),
+ onPressed: () {},
+ backgroundColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor.withOpacity(0.15) : AppColors.greyF7Color,
+ borderColor: AppColors.successColor.withOpacity(0.01),
+ textColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
+ fontSize: prescription.isHomeMedicineDeliverySupported! ? 14 : 12,
+ fontWeight: FontWeight.w500,
+ borderRadius: 12,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ height: 40.h,
+ icon: AppAssets.prescription_refill_icon,
+ iconColor: prescription.isHomeMedicineDeliverySupported! ? AppColors.successColor : AppColors.textColor.withOpacity(0.35),
+ iconSize: 14.h,
),
- child: Padding(
- padding: EdgeInsets.all(8.h),
- child: Utils.buildSvgWithAssets(
- icon: AppAssets.forward_arrow_icon,
- width: 10.h,
- height: 10.h,
- fit: BoxFit.contain,
+ ),
+ SizedBox(width: 8.h),
+ Expanded(
+ flex: 1,
+ child: Container(
+ height: 40.h,
+ width: 40.h,
+ decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
+ color: AppColors.textColor,
+ borderRadius: 10.h,
),
- ),
- ).onPress(() {
- model.setPrescriptionsDetailsLoading();
- Navigator.of(context).push(
- FadePage(
- page: PrescriptionDetailPage(prescriptionsResponseModel: prescription),
+ child: Padding(
+ padding: EdgeInsets.all(8.h),
+ child: Utils.buildSvgWithAssets(
+ icon: AppAssets.forward_arrow_icon,
+ width: 10.h,
+ height: 10.h,
+ fit: BoxFit.contain,
+ ),
),
- );
- }),
- ),
- ],
- ),
- SizedBox(height: 12.h),
- Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
- SizedBox(height: 12.h),
- ],
- );
- }).toList(),
- ],
- ),
- )
- : SizedBox.shrink(),
- ),
- ],
+ ).onPress(() {
+ model.setPrescriptionsDetailsLoading();
+ Navigator.of(context).push(
+ FadePage(
+ page: PrescriptionDetailPage(prescriptionsResponseModel: prescription),
+ ),
+ );
+ }),
+ ),
+ ],
+ ),
+ SizedBox(height: 12.h),
+ Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.05), height: 1.h),
+ SizedBox(height: 12.h),
+ ],
+ );
+ }).toList(),
+ ],
+ ),
+ )
+ : SizedBox.shrink(),
+ ),
+ ],
+ ),
),
),
),
),
- ),
- );
- },
- ).paddingSymmetrical(24.h, 0.h),
- ],
- );
- }),
+ );
+ },
+ ).paddingSymmetrical(24.h, 0.h),
+ ],
+ );
+ }),
+ ),
),
);
}
diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart
index d1b3830..19d0908 100644
--- a/lib/presentation/radiology/radiology_orders_page.dart
+++ b/lib/presentation/radiology/radiology_orders_page.dart
@@ -11,6 +11,7 @@ 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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
+import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
@@ -43,27 +44,14 @@ class _RadiologyOrdersPageState extends State {
radiologyViewModel = Provider.of(context);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
- appBar: AppBar(
- title: LocaleKeys.radiology.tr(context: context).toText18(),
- backgroundColor: AppColors.bgScaffoldColor,
- ),
- body: Padding(
- padding: EdgeInsets.all(24.h),
+ body: CollapsingListView(
+ title: LocaleKeys.radiology.tr(context: context),
child: SingleChildScrollView(
child: Consumer(
builder: (context, model, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- LocaleKeys.radiology.tr(context: context).toText24(isBold: true),
- Utils.buildSvgWithAssets(icon: AppAssets.search_icon),
- ],
- ),
- SizedBox(height: 16.h),
- // Build Tab Bar
SizedBox(height: 16.h),
// Expandable list
ListView.builder(
diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart
index 4fcf6f3..44e1327 100644
--- a/lib/widgets/input_widget.dart
+++ b/lib/widgets/input_widget.dart
@@ -5,9 +5,11 @@ import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/utils.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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart';
+import 'package:keyboard_actions/keyboard_actions.dart';
import '../core/dependencies.dart';
@@ -36,6 +38,8 @@ class TextInputWidget extends StatelessWidget {
final String? errorMessage;
Function(CountryEnum)? onCountryChange;
final SelectionTypeEnum? selectionType;
+ final num? fontSize;
+ final bool? isWalletAmountInput;
// final List countryList;
// final Function(Country)? onCountryChange;
@@ -63,10 +67,37 @@ class TextInputWidget extends StatelessWidget {
this.errorMessage,
this.onCountryChange,
this.selectionType,
+ this.fontSize = 14,
+ this.isWalletAmountInput = false,
// this.countryList = const [],
// this.onCountryChange,
});
+ final FocusNode _focusNode = FocusNode();
+
+ KeyboardActionsConfig get _keyboardActionsConfig {
+ return KeyboardActionsConfig(
+ keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
+ keyboardBarColor: const Color(0xFFCAD1D9), //Apple keyboard color
+ actions: [
+ KeyboardActionsItem(
+ focusNode: focusNode ?? _focusNode,
+ toolbarButtons: [
+ (node) {
+ return GestureDetector(
+ onTap: () => node.unfocus(),
+ child: Container(
+ padding: const EdgeInsets.all(12.0),
+ child: "Done".toText16(weight: FontWeight.w500, color: AppColors.infoColor),
+ ),
+ );
+ }
+ ],
+ ),
+ ],
+ );
+ }
+
@override
Widget build(BuildContext context) {
final errorColor = AppColors.primaryRedColor;
@@ -184,40 +215,46 @@ class TextInputWidget extends StatelessWidget {
}
Widget _buildTextField(BuildContext context) {
- return TextField(
- enabled: isEnable,
- scrollPadding: EdgeInsets.zero,
- keyboardType: keyboardType,
- controller: controller,
- readOnly: isReadOnly,
- textAlignVertical: TextAlignVertical.top,
- textAlign: TextAlign.left,
- textDirection: TextDirection.ltr,
- onChanged: onChange,
- focusNode: focusNode,
- autofocus: autoFocus,
- style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, color: AppColors.textColor, letterSpacing: -0.2),
- decoration: InputDecoration(
- isDense: true,
- hintText: hintText,
- hintStyle: TextStyle(fontSize: 14.fSize, height: 21 / 16, fontWeight: FontWeight.w500, color: Color(0xff898A8D), letterSpacing: -0.2),
- prefixIconConstraints: BoxConstraints(minWidth: 45.h),
- prefixIcon: prefix == null
- ? null
- : Text(
- "+" + prefix!,
- style: TextStyle(
- fontSize: 14.fSize,
- height: 21 / 14,
- fontWeight: FontWeight.w500,
- color: Color(0xff2E303A),
- letterSpacing: -0.2,
+ return KeyboardActions(
+ config: _keyboardActionsConfig,
+ disableScroll: true,
+ child: TextField(
+ enabled: isEnable,
+ scrollPadding: EdgeInsets.zero,
+ keyboardType: keyboardType,
+ controller: controller,
+ readOnly: isReadOnly,
+ textAlignVertical: TextAlignVertical.top,
+ textAlign: TextAlign.left,
+ textDirection: TextDirection.ltr,
+ onChanged: onChange,
+ focusNode: focusNode ?? _focusNode,
+ autofocus: autoFocus,
+ textInputAction: TextInputAction.done,
+ cursorHeight: isWalletAmountInput! ? 40.h : 18.h,
+ style: TextStyle(fontSize: fontSize!.fSize, height: isWalletAmountInput! ? 1 / 4 : 21 / 14, fontWeight: FontWeight.w500, color: AppColors.textColor, letterSpacing: -0.2),
+ decoration: InputDecoration(
+ isDense: true,
+ hintText: hintText,
+ hintStyle: TextStyle(fontSize: 14.fSize, height: 21 / 16, fontWeight: FontWeight.w500, color: Color(0xff898A8D), letterSpacing: -0.2),
+ prefixIconConstraints: BoxConstraints(minWidth: 45.h),
+ prefixIcon: prefix == null
+ ? null
+ : Text(
+ "+" + prefix!,
+ style: TextStyle(
+ fontSize: 14.fSize,
+ height: 21 / 14,
+ fontWeight: FontWeight.w500,
+ color: Color(0xff2E303A),
+ letterSpacing: -0.2,
+ ),
),
- ),
- contentPadding: EdgeInsets.zero,
- border: InputBorder.none,
- focusedBorder: InputBorder.none,
- enabledBorder: InputBorder.none,
+ contentPadding: EdgeInsets.zero,
+ border: InputBorder.none,
+ focusedBorder: InputBorder.none,
+ enabledBorder: InputBorder.none,
+ ),
),
);
}
diff --git a/pubspec.yaml b/pubspec.yaml
index afbac11..36326f4 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -75,6 +75,7 @@ dependencies:
network_info_plus: ^6.1.4
flutter_nfc_kit: ^3.6.0
barcode_scan2: ^4.5.1
+ keyboard_actions: ^4.2.0
dev_dependencies:
flutter_test: