Sickleave implementation done.

pull/30/head
Haroon Amjad 2 months ago
parent b240293064
commit de717edfe8

@ -811,5 +811,8 @@
"allSet": "جاهز! الآن يمكنك تسجيل الدخول باستخدام Face ID / Biometric أو البصمة",
"enableQuickLogin":"تمكين تسجيل الدخول السريع",
"enableMsg":"تمكين تسجيل الدخول السريع سيسمح بالتحقق من خلال Face ID / Biometric الخاص بجهازك الحالي",
"notNow": "ليس الآن"
"notNow": "ليس الآن",
"pendingActivation": "في انتظار التنشيط",
"awaitingApproval": "انتظر القبول",
"ready": "جاهز"
}

@ -807,5 +807,8 @@
"allSet": "All Set! Now you can login with Face ID or Biometric",
"enableQuickLogin": "Enable Quick Login",
"enableMsg": "Enabling the quick login will verify through your existing device Face ID / Biometric",
"notNow": "Not Now"
"notNow": "Not Now",
"pendingActivation": "Pending Activation",
"awaitingApproval": "Awaiting Approval",
"ready": "Ready"
}

@ -726,7 +726,7 @@ const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_In
class ApiConsts {
static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT

@ -1,5 +1,7 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:crypto/crypto.dart' as crypto;
@ -21,6 +23,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/dialogs/confirm_dialog.dart';
import 'package:hmg_patient_app_new/widgets/loading_dialog.dart';
import 'package:lottie/lottie.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:math' as dartMath;
@ -629,4 +632,13 @@ class Utils {
static String getAdvancePaymentTransID(int projectID, int fileNumber) {
return '$projectID-$fileNumber-${DateTime.now().millisecondsSinceEpoch}';
}
static Future<String> createFileFromString(String encodedStr, String ext) async {
Uint8List bytes = base64.decode(encodedStr);
String dir = (await getApplicationDocumentsDirectory()).path;
File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext);
await file.writeAsBytes(bytes);
return file.path;
}
}

@ -3,11 +3,18 @@ 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/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import '../authentication/models/resp_models/authenticated_user_resp_model.dart';
abstract class MedicalFileRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientVaccinesList();
Future<Either<Failure, GenericApiModel<List<PatientVaccineResponseModel>>>> getPatientVaccinesList();
Future<Either<Failure, GenericApiModel<List<PatientSickLeavesResponseModel>>>> getPatientSickLeavesList();
Future<Either<Failure, GenericApiModel<dynamic>>> getPatientSickLeavePDF(PatientSickLeavesResponseModel patientSickLeavesResponseModel, AuthenticatedUser authenticatedUser);
}
class MedicalFileRepoImp implements MedicalFileRepo {
@ -56,4 +63,98 @@ class MedicalFileRepoImp implements MedicalFileRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<PatientSickLeavesResponseModel>>>> getPatientSickLeavesList() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<PatientSickLeavesResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PATIENT_SICK_LEAVE_STATUS,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_SickLeave'];
// if (list == null || list.isEmpty) {
// throw Exception("lab list is empty");
// }
final vaccinesList = list.map((item) => PatientSickLeavesResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientSickLeavesResponseModel>();
apiResponse = GenericApiModel<List<PatientSickLeavesResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: vaccinesList,
);
} 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()));
}
}
@override
Future<Either<Failure, GenericApiModel>> getPatientSickLeavePDF(PatientSickLeavesResponseModel patientSickLeavesResponseModel, AuthenticatedUser authenticatedUser) async {
Map<String, dynamic> mapDevice = {
"RequestNo": patientSickLeavesResponseModel.requestNo,
"To": authenticatedUser.emailAddress,
"DateofBirth": authenticatedUser.dateofBirth,
"PatientIditificationNum": authenticatedUser.patientIdentificationNo,
"PatientMobileNumber": authenticatedUser.mobileNumber,
"PatientName": "${authenticatedUser.firstName!} ${authenticatedUser.lastName!}",
"ProjectName": patientSickLeavesResponseModel.projectName,
"DoctorName": patientSickLeavesResponseModel.doctorName,
"ProjectID": patientSickLeavesResponseModel.projectID,
"SetupID": patientSickLeavesResponseModel.setupID,
"IsDownload": true,
};
try {
GenericApiModel<dynamic>? apiResponse;
Failure? failure;
await apiClient.post(
SendSickLeaveEmail,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['List_SickLeave'];
// if (list == null || list.isEmpty) {
// throw Exception("lab list is empty");
// }
// final vaccinesList = list.map((item) => PatientSickLeavesResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientSickLeavesResponseModel>();
apiResponse = GenericApiModel<dynamic>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response["Base64Data"],
);
} 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()));
}
}
}

@ -1,16 +1,23 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_vaccine_response_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class MedicalFileViewModel extends ChangeNotifier {
int selectedTabIndex = 0;
bool isPatientVaccineListLoading = false;
bool isPatientSickLeaveListLoading = false;
bool isPatientSickLeavePDFLoading = false;
MedicalFileRepo medicalFileRepo;
ErrorHandlerService errorHandlerService;
List<PatientVaccineResponseModel> patientVaccineList = [];
List<PatientSickLeavesResponseModel> patientSickLeaveList = [];
String patientSickLeavePDFBase64 = "";
MedicalFileViewModel({required this.medicalFileRepo, required this.errorHandlerService});
@ -24,12 +31,26 @@ class MedicalFileViewModel extends ChangeNotifier {
notifyListeners();
}
setIsPatientSickLeavePDFLoading(bool isLoading) {
isPatientSickLeavePDFLoading = isLoading;
notifyListeners();
}
setIsPatientSickLeaveListLoading(bool val) {
if (val) {
patientSickLeaveList.clear();
}
isPatientSickLeaveListLoading = val;
notifyListeners();
}
void onTabChanged(int index) {
selectedTabIndex = index;
notifyListeners();
}
Future<void> getPatientVaccinesList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
patientVaccineList.clear();
final result = await medicalFileRepo.getPatientVaccinesList();
result.fold(
@ -53,4 +74,55 @@ class MedicalFileViewModel extends ChangeNotifier {
},
);
}
Future<void> getPatientSickLeaveList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
patientSickLeaveList.clear();
final result = await medicalFileRepo.getPatientSickLeavesList();
result.fold(
(failure) async => await errorHandlerService.handleError(
failure: failure,
onOkPressed: () {
onError!(failure.message);
},
),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientSickLeaveList = apiResponse.data!;
isPatientSickLeaveListLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> getPatientSickLeavePDF(PatientSickLeavesResponseModel patientSickLeavesResponseModel, AuthenticatedUser authenticatedUser,{Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await medicalFileRepo.getPatientSickLeavePDF(patientSickLeavesResponseModel, authenticatedUser);
result.fold(
(failure) async => await errorHandlerService.handleError(
failure: failure,
onOkPressed: () {
onError!(failure.message);
},
),
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
patientSickLeavePDFBase64 = apiResponse.data!;
isPatientSickLeaveListLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -0,0 +1,176 @@
class PatientSickLeavesResponseModel {
String? setupID;
int? projectID;
int? patientID;
int? patientType;
int? clinicID;
int? doctorID;
int? requestNo;
String? requestDate;
int? sickLeaveDays;
int? appointmentNo;
int? admissionNo;
dynamic reportDate;
num? actualDoctorRate;
String? appointmentDate;
String? clinicName;
double? decimalDoctorRate;
String? doctorImageURL;
String? doctorName;
num? doctorRate;
num? doctorStarsRate;
String? doctorTitle;
int? employeeID;
String? endDate;
int? gender;
String? genderDescription;
bool? isActiveDoctorProfile;
bool? isDoctorAllowVedioCall;
bool? isExecludeDoctor;
bool? isInOutPatient;
String? isInOutPatientDescription;
String? isInOutPatientDescriptionN;
bool? isLiveCareAppointment;
dynamic medicalDirectorApprovedStatus;
int? noOfPatientsRate;
dynamic patientName;
String? projectName;
String? qR;
List<String>? speciality;
String? startDate;
int? status;
String? strRequestDate;
PatientSickLeavesResponseModel(
{this.setupID,
this.projectID,
this.patientID,
this.patientType,
this.clinicID,
this.doctorID,
this.requestNo,
this.requestDate,
this.sickLeaveDays,
this.appointmentNo,
this.admissionNo,
this.reportDate,
this.actualDoctorRate,
this.appointmentDate,
this.clinicName,
this.decimalDoctorRate,
this.doctorImageURL,
this.doctorName,
this.doctorRate,
this.doctorStarsRate,
this.doctorTitle,
this.employeeID,
this.endDate,
this.gender,
this.genderDescription,
this.isActiveDoctorProfile,
this.isDoctorAllowVedioCall,
this.isExecludeDoctor,
this.isInOutPatient,
this.isInOutPatientDescription,
this.isInOutPatientDescriptionN,
this.isLiveCareAppointment,
this.medicalDirectorApprovedStatus,
this.noOfPatientsRate,
this.patientName,
this.projectName,
this.qR,
this.speciality,
this.startDate,
this.status,
this.strRequestDate});
PatientSickLeavesResponseModel.fromJson(Map<String, dynamic> json) {
setupID = json['SetupID'];
projectID = json['ProjectID'];
patientID = json['PatientID'];
patientType = json['PatientType'];
clinicID = json['ClinicID'];
doctorID = json['DoctorID'];
requestNo = json['RequestNo'];
requestDate = json['RequestDate'];
sickLeaveDays = json['SickLeaveDays'];
appointmentNo = json['AppointmentNo'];
admissionNo = json['AdmissionNo'];
reportDate = json['ReportDate'];
actualDoctorRate = json['ActualDoctorRate'];
appointmentDate = json['AppointmentDate'];
clinicName = json['ClinicName'];
decimalDoctorRate = json['DecimalDoctorRate'];
doctorImageURL = json['DoctorImageURL'];
doctorName = json['DoctorName'];
doctorRate = json['DoctorRate'];
doctorStarsRate = json['DoctorStarsRate'];
doctorTitle = json['DoctorTitle'];
employeeID = json['EmployeeID'];
endDate = json['EndDate'];
gender = json['Gender'];
genderDescription = json['GenderDescription'];
isActiveDoctorProfile = json['IsActiveDoctorProfile'];
isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall'];
isExecludeDoctor = json['IsExecludeDoctor'];
isInOutPatient = json['IsInOutPatient'];
isInOutPatientDescription = json['IsInOutPatientDescription'];
isInOutPatientDescriptionN = json['IsInOutPatientDescriptionN'];
isLiveCareAppointment = json['IsLiveCareAppointment'];
medicalDirectorApprovedStatus = json['MedicalDirectorApprovedStatus'];
noOfPatientsRate = json['NoOfPatientsRate'];
patientName = json['PatientName'];
projectName = json['ProjectName'];
qR = json['QR'];
speciality = json['Speciality'].cast<String>();
startDate = json['StartDate'];
status = json['Status'];
strRequestDate = json['StrRequestDate'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['SetupID'] = this.setupID;
data['ProjectID'] = this.projectID;
data['PatientID'] = this.patientID;
data['PatientType'] = this.patientType;
data['ClinicID'] = this.clinicID;
data['DoctorID'] = this.doctorID;
data['RequestNo'] = this.requestNo;
data['RequestDate'] = this.requestDate;
data['SickLeaveDays'] = this.sickLeaveDays;
data['AppointmentNo'] = this.appointmentNo;
data['AdmissionNo'] = this.admissionNo;
data['ReportDate'] = this.reportDate;
data['ActualDoctorRate'] = this.actualDoctorRate;
data['AppointmentDate'] = this.appointmentDate;
data['ClinicName'] = this.clinicName;
data['DecimalDoctorRate'] = this.decimalDoctorRate;
data['DoctorImageURL'] = this.doctorImageURL;
data['DoctorName'] = this.doctorName;
data['DoctorRate'] = this.doctorRate;
data['DoctorStarsRate'] = this.doctorStarsRate;
data['DoctorTitle'] = this.doctorTitle;
data['EmployeeID'] = this.employeeID;
data['EndDate'] = this.endDate;
data['Gender'] = this.gender;
data['GenderDescription'] = this.genderDescription;
data['IsActiveDoctorProfile'] = this.isActiveDoctorProfile;
data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall;
data['IsExecludeDoctor'] = this.isExecludeDoctor;
data['IsInOutPatient'] = this.isInOutPatient;
data['IsInOutPatientDescription'] = this.isInOutPatientDescription;
data['IsInOutPatientDescriptionN'] = this.isInOutPatientDescriptionN;
data['IsLiveCareAppointment'] = this.isLiveCareAppointment;
data['MedicalDirectorApprovedStatus'] = this.medicalDirectorApprovedStatus;
data['NoOfPatientsRate'] = this.noOfPatientsRate;
data['PatientName'] = this.patientName;
data['ProjectName'] = this.projectName;
data['QR'] = this.qR;
data['Speciality'] = this.speciality;
data['StartDate'] = this.startDate;
data['Status'] = this.status;
data['StrRequestDate'] = this.strRequestDate;
return data;
}
}

@ -780,6 +780,9 @@ abstract class LocaleKeys {
static const resultsPending = 'resultsPending';
static const resultsAvailable = 'resultsAvailable';
static const viewReport = 'viewReport';
static const checkAvailability = 'checkAvailability';
static const readInstructions = 'readInstructions';
static const searchLabReport = 'searchLabReport';
static const prescriptionDeliveryError = 'prescriptionDeliveryError';
static const receiveOtpToast = 'receiveOtpToast';
static const enterPhoneNumber = 'enterPhoneNumber';
@ -802,12 +805,13 @@ abstract class LocaleKeys {
static const loginByOTP = 'loginByOTP';
static const guest = 'guest';
static const switchAccount = 'switchAccount';
static const checkAvailability = 'checkAvailability';
static const readInstructions = 'readInstructions';
static const searchLabReport = 'searchLabReport';
static const lastloginBy = 'lastloginBy';
static const allSet ='allSet';
static const lastLoginBy = 'lastLoginBy';
static const allSet = 'allSet';
static const enableQuickLogin = 'enableQuickLogin';
static const enableMsg = 'enableMsg';
static const notNow = 'notNow';
static const pendingActivation = 'pendingActivation';
static const awaitingApproval = 'awaitingApproval';
static const ready = 'ready';
}

@ -84,7 +84,7 @@ class _SavedLogin extends State<SavedLogin> {
children: [
// Last login info
("${LocaleKeys.lastloginBy.tr()} ${loginType.displayName}").toText14(isBold: true, color: AppColors.greyTextColor),
("${LocaleKeys.lastLoginBy.tr()} ${loginType.displayName}").toText14(isBold: true, color: AppColors.greyTextColor),
(appState.getSelectDeviceByImeiRespModelElement!.createdOn != null
? DateUtil.getFormattedDate(DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), "d MMMM, y 'at' HH:mm")
: '--')

@ -13,17 +13,20 @@ 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/medical_file/models/patient_sickleave_response_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/appointments/my_doctors_page.dart';
import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_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/vaccine_list_page.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/presentation/medical_file/widgets/patient_sick_leave_card.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -56,6 +59,8 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
void initState() {
scheduleMicrotask(() {
insuranceViewModel.initInsuranceProvider();
medicalFileViewModel.setIsPatientSickLeaveListLoading(true);
medicalFileViewModel.getPatientSickLeaveList();
});
super.initState();
}
@ -326,124 +331,126 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
Consumer<PrescriptionsViewModel>(builder: (context, prescriptionVM, child) {
return prescriptionVM.isPrescriptionsOrdersLoading
? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0.h)
: 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: [
Image.network(
prescriptionVM.patientPrescriptionOrders[index].doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 16.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
prescriptionVM.patientPrescriptionOrders[index].doctorName!.toText16(isBold: true),
SizedBox(height: 4.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
: prescriptionVM.patientPrescriptionOrders.isNotEmpty
? 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: [
Image.network(
prescriptionVM.patientPrescriptionOrders[index].doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.fill,
).circle(100),
SizedBox(width: 16.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppCustomChipWidget(labelText: prescriptionVM.patientPrescriptionOrders[index].clinicDescription!),
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescriptionVM.patientPrescriptionOrders[index].appointmentDate), false),
prescriptionVM.patientPrescriptionOrders[index].doctorName!.toText16(isBold: true),
SizedBox(height: 4.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: prescriptionVM.patientPrescriptionOrders[index].clinicDescription!),
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(prescriptionVM.patientPrescriptionOrders[index].appointmentDate), false),
),
],
),
],
),
],
),
SizedBox(width: 40.h),
Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
],
).onPress(() {
prescriptionVM.setPrescriptionsDetailsLoading();
Navigator.of(context).push(
FadePage(
page: PrescriptionDetailPage(prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index]),
),
);
}),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
),
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(),
),
),
SizedBox(width: 40.h),
Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
],
);
},
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,
),
),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
).onPress(() {
prescriptionVM.setPrescriptionsDetailsLoading();
Navigator.of(context).push(
FadePage(
page: PrescriptionDetailPage(prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index]),
),
);
}),
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(),
),
);
},
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(width: 10.h),
Expanded(
child: CustomButton(
text: "All Medications".needTranslation,
onPressed: () {},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
height: 40.h,
icon: AppAssets.all_medications_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
),
SizedBox(width: 10.h),
Expanded(
child: CustomButton(
text: "All Medications".needTranslation,
onPressed: () {},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: 14,
fontWeight: FontWeight.w500,
borderRadius: 12.h,
height: 40.h,
icon: AppAssets.all_medications_icon,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
),
),
],
),
],
),
],
),
),
).paddingSymmetrical(24.h, 0.h);
),
).paddingSymmetrical(24.h, 0.h)
: SizedBox.shrink();
}),
SizedBox(height: 24.h),
//My Doctor Section
@ -594,7 +601,13 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
padding: EdgeInsets.only(top: 12),
shrinkWrap: true,
children: [
MedicalFileCard(label: "Update Insurance".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
MedicalFileCard(label: "Update Insurance".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon).onPress(() {
Navigator.of(context).push(
FadePage(
page: InsuranceHomePage(),
),
);
}),
MedicalFileCard(label: "Insurance Approvals".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
MedicalFileCard(label: "My Invoices List".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
MedicalFileCard(label: "Ancillary Orders List".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
@ -604,7 +617,42 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
],
);
case 2:
return Container();
// Requests Tab Data
return Column(
children: [
Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
return medicalFileVM.isPatientSickLeaveListLoading
? PatientSickLeaveCard(
patientSickLeavesResponseModel: PatientSickLeavesResponseModel(),
isLoading: true,
).paddingSymmetrical(24.h, 0.0)
: medicalFileVM.patientSickLeaveList.isNotEmpty ? PatientSickLeaveCard(
patientSickLeavesResponseModel: medicalFileVM.patientSickLeaveList.first,
isLoading: false,
).paddingSymmetrical(24.h, 0.0) : SizedBox.shrink();
}),
SizedBox(height: 10.h),
// GridView(
// gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, crossAxisSpacing: 13, mainAxisSpacing: 13),
// physics: NeverScrollableScrollPhysics(),
// padding: EdgeInsets.only(top: 12),
// shrinkWrap: true,
// children: [
// MedicalFileCard(label: "Update Insurance".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon).onPress(() {
// Navigator.of(context).push(
// FadePage(
// page: InsuranceHomePage(),
// ),
// );
// }),
// MedicalFileCard(label: "Insurance Approvals".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
// MedicalFileCard(label: "My Invoices List".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
// MedicalFileCard(label: "Ancillary Orders List".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.eye_result_icon),
// ],
// ).paddingSymmetrical(24.h, 0.0),
// SizedBox(height: 16.h),
],
);
case 3:
return Container();
default:

@ -0,0 +1,88 @@
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/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_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/theme/colors.dart';
import 'package:provider/provider.dart';
import 'widgets/patient_sick_leave_card.dart';
class PatientSickleavesListPage extends StatefulWidget {
const PatientSickleavesListPage({super.key});
@override
State<PatientSickleavesListPage> createState() => _PatientSickleavesListPageState();
}
class _PatientSickleavesListPageState extends State<PatientSickleavesListPage> {
late MedicalFileViewModel medicalFileViewModel;
@override
void initState() {
scheduleMicrotask(() {
medicalFileViewModel.setIsPatientSickLeaveListLoading(true);
medicalFileViewModel.getPatientSickLeaveList(onError: (error) {
Navigator.of(context).pop();
Navigator.of(context).pop();
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: "${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}",
child: SingleChildScrollView(
child: Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
scrollDirection: Axis.vertical,
itemCount: medicalFileVM.isPatientSickLeaveListLoading ? 3 : medicalFileVM.patientSickLeaveList.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return medicalFileVM.isPatientSickLeaveListLoading
? PatientSickLeaveCard(
patientSickLeavesResponseModel: PatientSickLeavesResponseModel(),
isLoading: true,
).paddingSymmetrical(24.h, 0.0)
: medicalFileVM.patientSickLeaveList.isNotEmpty
? AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 1000),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: PatientSickLeaveCard(
patientSickLeavesResponseModel: medicalFileVM.patientSickLeaveList.first,
isLoading: false,
).paddingSymmetrical(24.h, 0.0),
),
),
)
: SizedBox.shrink();
},
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 8.h),
),
SizedBox(height: 60.h),
],
);
}),
),
),
);
}
}

@ -42,7 +42,7 @@ class _VaccineListPageState extends State<VaccineListPage> {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: "Vaccine Info",
title: "Vaccine Info".needTranslation,
child: SingleChildScrollView(
child: Consumer<MedicalFileViewModel>(builder: (context, medicalFileVM, child) {
return Column(

@ -36,7 +36,7 @@ class MedicalFileCard extends StatelessWidget {
children: [
Utils.buildSvgWithAssets(icon: svgIcon, width: iconSize.h, height: iconSize.h, fit: BoxFit.contain),
SizedBox(height: 12.h),
isLargeText ? label.toText14(color: textColor, isBold: true, maxlines: 1) : label.toText11(color: textColor, isBold: true, maxLine: 1),
isLargeText ? label.toText14(color: textColor, isBold: true, maxlines: 1) : label.toText11(color: textColor, isBold: true, maxLine: 2),
],
),
),

@ -0,0 +1,191 @@
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/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/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves_list_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/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart';
import 'package:open_filex/open_filex.dart';
import 'package:provider/provider.dart';
class PatientSickLeaveCard extends StatelessWidget {
PatientSickLeaveCard({super.key, required this.patientSickLeavesResponseModel, this.isLoading = false});
late MedicalFileViewModel medicalFileViewModel;
PatientSickLeavesResponseModel patientSickLeavesResponseModel;
bool isLoading;
@override
Widget build(BuildContext context) {
AppState _appState = getIt.get<AppState>();
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24, hasShadow: true),
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${LocaleKeys.sick.tr(context: context)} ${LocaleKeys.sickSubtitle.tr(context: context)}".toText16(isBold: true),
AppCustomChipWidget(
labelText: isLoading ? "" : getStatusText(context),
backgroundColor: getStatusColor().withOpacity(0.15),
textColor: getStatusColor(),
).toShimmer2(isShow: isLoading, width: 100.h),
],
),
SizedBox(height: 16.h),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : patientSickLeavesResponseModel.doctorImageURL!,
width: 30.h,
height: 30.h,
fit: BoxFit.fill,
).circle(100).toShimmer2(isShow: isLoading),
SizedBox(width: 16.h),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(isLoading ? "" : patientSickLeavesResponseModel.doctorName!).toText16(isBold: true).toShimmer2(isShow: isLoading),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 3.h,
runSpacing: 4.h,
children: [
AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientSickLeavesResponseModel.appointmentDate), false),
).toShimmer2(isShow: isLoading),
AppCustomChipWidget(labelText: isLoading ? "Pending Activation" : patientSickLeavesResponseModel.clinicName!).toShimmer2(isShow: isLoading),
],
),
],
),
),
],
),
SizedBox(height: 16.h),
Row(
children: [
isLoading
? Container().toShimmer2(isShow: true, height: 40.h, width: 100.h, radius: 12.h)
: Expanded(
flex: 6,
child: CustomButton(
text: "Download Report".needTranslation,
onPressed: () async {
LoaderBottomSheet.showLoader();
await medicalFileViewModel.getPatientSickLeavePDF(patientSickLeavesResponseModel, _appState.getAuthenticatedUser()!).then((val) async {
LoaderBottomSheet.hideLoader();
if (medicalFileViewModel.patientSickLeavePDFBase64.isNotEmpty) {
String path = await Utils.createFileFromString(medicalFileViewModel.patientSickLeavePDFBase64, "pdf");
try {
OpenFilex.open(path);
} catch (ex) {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: "Cannot open file".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
}
});
},
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.download,
iconColor: AppColors.primaryRedColor,
iconSize: 14.h,
).toShimmer2(isShow: isLoading),
),
SizedBox(width: 8.h),
Expanded(
flex: 1,
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: isLoading).onPress(() {
Navigator.of(context).push(
FadePage(
page: PatientSickleavesListPage(),
),
);
}),
),
],
),
],
),
),
);
}
String getStatusText(BuildContext context) {
String statusText = "";
if (patientSickLeavesResponseModel.status == 1) {
statusText = LocaleKeys.pendingActivation.tr(context: context);
} else if (patientSickLeavesResponseModel.status == 2) {
statusText = LocaleKeys.ready.tr(context: context);
} else if (patientSickLeavesResponseModel.status == 3) {
statusText = LocaleKeys.awaitingApproval.tr(context: context);
} else {
statusText = "";
}
return statusText;
}
Color getStatusColor() {
Color statusColor = Colors.white;
if (patientSickLeavesResponseModel.status == 1) {
statusColor = Color(0xffCC9B14);
} else if (patientSickLeavesResponseModel.status == 2) {
statusColor = Color(0xff359846);
} else if (patientSickLeavesResponseModel.status == 3) {
statusColor = Color(0xffD02127);
} else {
statusColor = Colors.white;
}
return statusColor;
}
}

@ -76,6 +76,8 @@ dependencies:
flutter_nfc_kit: ^3.6.0
barcode_scan2: ^4.5.1
keyboard_actions: ^4.2.0
path_provider: ^2.0.8
open_filex: ^4.7.0
dev_dependencies:
flutter_test:

Loading…
Cancel
Save