fatima #100

Open
Fatimah wants to merge 10 commits from fatima into master

@ -825,6 +825,7 @@ class ApiConsts {
static final String getAllSharedRecordsByStatus = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus';
static final String removeFileFromFamilyMembers = 'Services/Authentication.svc/REST/ActiveDeactive_PatientFile';
static final String acceptAndRejectFamilyFile = 'Services/Authentication.svc/REST/Update_FileStatus';
static final String getActivePrescriptionsDetails = 'Services/Patients.svc/Rest/GetActivePrescriptionReportByPatientID';
// Ancillary Order Apis
static final String getOnlineAncillaryOrderList = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderList';

@ -3,6 +3,8 @@ import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart';
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';
@ -52,6 +54,8 @@ import 'package:local_auth/local_auth.dart';
import 'package:logger/web.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../features/active_prescriptions/active_prescriptions_repo.dart';
GetIt getIt = GetIt.instance;
class AppDependencies {
@ -116,6 +120,7 @@ class AppDependencies {
getIt.registerLazySingleton<LocationRepo>(() => LocationRepoImpl(apiClient: getIt()));
getIt.registerLazySingleton<ContactUsRepo>(() => ContactUsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<HmgServicesRepo>(() => HmgServicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ActivePrescriptionsRepo>(() => ActivePrescriptionsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -218,6 +223,13 @@ class AppDependencies {
() => HmgServicesViewModel(bookAppointmentsRepo: getIt(), hmgServicesRepo: getIt(), errorHandlerService: getIt()),
);
getIt.registerLazySingleton<ActivePrescriptionsViewModel>(
() => ActivePrescriptionsViewModel(
errorHandlerService: getIt(),
activePrescriptionsRepo: getIt()
),
);
// Screen-specific VMs Factory
// getIt.registerFactory<BookAppointmentsViewModel>(
// () => BookAppointmentsViewModel(

@ -266,7 +266,7 @@ setCalender(BuildContext context,
eventId: eventId + (i.toString() + j.toString()),
location: '', //event id with varitions
);
print("Creating event #$j for day $i$actualDate");
actualDate = DateTime(actualDate.year, actualDate.month, actualDate.day, 8, 0);
}
actualDate = Jiffy.parseFromDateTime(actualDate).add(days: 1).dateTime;

@ -0,0 +1,65 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart';
import '../../core/api/api_client.dart';
import '../../core/api_consts.dart';
import '../../core/common_models/generic_api_model.dart';
import '../../core/exceptions/api_failure.dart';
import '../../services/logger_service.dart';
abstract class ActivePrescriptionsRepo {
Future<Either<Failure, GenericApiModel<List<ActivePrescriptionsResponseModel>>>> getActivePrescriptionsDetails();
}
class ActivePrescriptionsRepoImp implements ActivePrescriptionsRepo {
final ApiClient apiClient;
final LoggerService loggerService;
ActivePrescriptionsRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<ActivePrescriptionsResponseModel>>>> getActivePrescriptionsDetails() async
{
try {
GenericApiModel<List<ActivePrescriptionsResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getActivePrescriptionsDetails,
body: {},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
var list = response['List_ActiveGetPrescriptionReportByPatientID'];
var res = list
.map<ActivePrescriptionsResponseModel>(
(item) => ActivePrescriptionsResponseModel.fromJson(item))
.toList();
apiResponse = GenericApiModel<List<ActivePrescriptionsResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
// data: response,
data: res
);
return apiResponse;
} 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()));
}
}
}

@ -0,0 +1,101 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class ActivePrescriptionsViewModel extends ChangeNotifier {
late ActivePrescriptionsRepo activePrescriptionsRepo;
late ErrorHandlerService errorHandlerService;
List<ActivePrescriptionsResponseModel> activePrescriptionsDetailsList = [];
ActivePrescriptionsViewModel({
required this.activePrescriptionsRepo,
required this.errorHandlerService,
});
Future<void> getActiveMedications({
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
final result =
await activePrescriptionsRepo.getActivePrescriptionsDetails();
result.fold(
(failure) async =>
await errorHandlerService.handleError(failure: failure),
(apiResponse) {
if (apiResponse.messageStatus == 1) {
activePrescriptionsDetailsList = apiResponse.data ?? [];
notifyListeners();
if (onSuccess != null) onSuccess(apiResponse.data);
}
},
);
}
DateTime parseDate(String? date) {
if (date == null) return DateTime.now();
final regex = RegExp(r"\/Date\((\d+)([+-]\d+)?\)\/");
final match = regex.firstMatch(date);
if (match != null) {
final millis = int.parse(match.group(1)!);
return DateTime.fromMillisecondsSinceEpoch(millis);
}
return DateTime.tryParse(date) ?? DateTime.now();
}
List<DateTime> generateMedicationDays(ActivePrescriptionsResponseModel med) {
final start = parseDate(med.startDate);
final duration = med.days ?? 0;
if (duration <= 0) return [];
final f = (med.frequency ?? "").toLowerCase().trim();
int intervalDays = 1;
if (f.contains("every six hours") ||
f.contains("every 6 hours") ||
f.contains("every four hours") ||
f.contains("every 4 hours") ||
f.contains("every eight hours") ||
f.contains("every 8 hours") ||
f.contains("every 12 hours") ||
f.contains("every twelve hours") ||
f.contains("every 24 hours") ||
f.contains("3 times a day") ||
f.contains("once a day")) {
intervalDays = 1;
}
else if (f.contains("once a week")) {
intervalDays = 7;
}
else if (f.contains("every 3 days")) {
intervalDays = 3;
}
else if (f.contains("every other day")) {
intervalDays = 2;
}
List<DateTime> result = [];
for (int offset = 0; offset < duration; offset += intervalDays) {
result.add(start.add(Duration(days: offset)));
}
return result;
}
bool sameYMD(DateTime a, DateTime b) =>
a.year == b.year && a.month == b.month && a.day == b.day;
List<ActivePrescriptionsResponseModel> getMedsForSelectedDay(
DateTime selectedDate) {
final clean = DateTime(selectedDate.year, selectedDate.month, selectedDate.day);
return activePrescriptionsDetailsList.where((med) {
final days = generateMedicationDays(med);
return days.any((d) => sameYMD(d, clean));
}).toList();
}
}

@ -0,0 +1,165 @@
import 'dart:convert';
class ActivePrescriptionsResponseModel {
dynamic address;
int? appointmentNo;
dynamic clinic;
dynamic companyName;
int? days;
dynamic doctorName;
int? doseDailyQuantity; // doses per day
String? frequency;
int? frequencyNumber;
dynamic image;
dynamic imageExtension;
dynamic imageSrcUrl;
String? imageString;
dynamic imageThumbUrl;
dynamic isCovered;
String? itemDescription;
int? itemId;
String? orderDate;
int? patientId;
dynamic patientName;
dynamic phoneOffice1;
dynamic prescriptionQr;
dynamic prescriptionTimes;
dynamic productImage;
String? productImageBase64;
String? productImageString;
int? projectId;
dynamic projectName;
dynamic remarks;
String? route;
String? sku;
int? scaleOffset;
String? startDate;
// Added for reminder feature
List<String?> selectedDoseTimes = [];
bool isReminderOn = false; // toggle status
ActivePrescriptionsResponseModel({
this.address,
this.appointmentNo,
this.clinic,
this.companyName,
this.days,
this.doctorName,
this.doseDailyQuantity,
this.frequency,
this.frequencyNumber,
this.image,
this.imageExtension,
this.imageSrcUrl,
this.imageString,
this.imageThumbUrl,
this.isCovered,
this.itemDescription,
this.itemId,
this.orderDate,
this.patientId,
this.patientName,
this.phoneOffice1,
this.prescriptionQr,
this.prescriptionTimes,
this.productImage,
this.productImageBase64,
this.productImageString,
this.projectId,
this.projectName,
this.remarks,
this.route,
this.sku,
this.scaleOffset,
this.startDate,
// Default values for new fields (wont break API)
List<String?>? selectedDoseTimes,
this.isReminderOn = false,
}) : selectedDoseTimes = selectedDoseTimes ?? [];
factory ActivePrescriptionsResponseModel.fromRawJson(String str) =>
ActivePrescriptionsResponseModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory ActivePrescriptionsResponseModel.fromJson(Map<String, dynamic> json) =>
ActivePrescriptionsResponseModel(
address: json["Address"],
appointmentNo: json["AppointmentNo"],
clinic: json["Clinic"],
companyName: json["CompanyName"],
days: json["Days"],
doctorName: json["DoctorName"],
doseDailyQuantity: json["DoseDailyQuantity"],
frequency: json["Frequency"],
frequencyNumber: json["FrequencyNumber"],
image: json["Image"],
imageExtension: json["ImageExtension"],
imageSrcUrl: json["ImageSRCUrl"],
imageString: json["ImageString"],
imageThumbUrl: json["ImageThumbUrl"],
isCovered: json["IsCovered"],
itemDescription: json["ItemDescription"],
itemId: json["ItemID"],
orderDate: json["OrderDate"],
patientId: json["PatientID"],
patientName: json["PatientName"],
phoneOffice1: json["PhoneOffice1"],
prescriptionQr: json["PrescriptionQR"],
prescriptionTimes: json["PrescriptionTimes"],
productImage: json["ProductImage"],
productImageBase64: json["ProductImageBase64"],
productImageString: json["ProductImageString"],
projectId: json["ProjectID"],
projectName: json["ProjectName"],
remarks: json["Remarks"],
route: json["Route"],
sku: json["SKU"],
scaleOffset: json["ScaleOffset"],
startDate: json["StartDate"],
// Ensure local reminder values are not overwritten by API
selectedDoseTimes: [],
isReminderOn: false,
);
Map<String, dynamic> toJson() => {
"Address": address,
"AppointmentNo": appointmentNo,
"Clinic": clinic,
"CompanyName": companyName,
"Days": days,
"DoctorName": doctorName,
"DoseDailyQuantity": doseDailyQuantity,
"Frequency": frequency,
"FrequencyNumber": frequencyNumber,
"Image": image,
"ImageExtension": imageExtension,
"ImageSRCUrl": imageSrcUrl,
"ImageString": imageString,
"ImageThumbUrl": imageThumbUrl,
"IsCovered": isCovered,
"ItemDescription": itemDescription,
"ItemID": itemId,
"OrderDate": orderDate,
"PatientID": patientId,
"PatientName": patientName,
"PhoneOffice1": phoneOffice1,
"PrescriptionQR": prescriptionQr,
"PrescriptionTimes": prescriptionTimes,
"ProductImage": productImage,
"ProductImageBase64": productImageBase64,
"ProductImageString": productImageString,
"ProjectID": projectId,
"ProjectName": projectName,
"Remarks": remarks,
"Route": route,
"SKU": sku,
"ScaleOffset": scaleOffset,
"StartDate": startDate,
};
}

@ -8,6 +8,7 @@ import 'package:flutter/services.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/utils.dart';
import 'package:hmg_patient_app_new/features/active_prescriptions/active_prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
@ -146,6 +147,9 @@ void main() async {
ChangeNotifierProvider<HmgServicesViewModel>(
create: (_) => getIt.get<HmgServicesViewModel>(),
)
ChangeNotifierProvider<ActivePrescriptionsViewModel>(
create: (_) => getIt.get<ActivePrescriptionsViewModel>(),
)
], child: MyApp()),
),
);

@ -47,6 +47,8 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/routes/spring_page_route_builder.dart';
import 'package:provider/provider.dart';
import '../active_medication/active_medication_page.dart';
class LandingPage extends StatefulWidget {
const LandingPage({super.key});

@ -13,6 +13,7 @@ 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/active_prescriptions/models/active_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
@ -24,6 +25,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/
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/active_medication/active_medication_page.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/book_appointment/book_appointment_page.dart';
@ -59,6 +61,7 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/shimmer/common_shimmer_widget.dart';
import 'package:provider/provider.dart';
import '../../features/active_prescriptions/active_prescriptions_view_model.dart';
import '../prescriptions/prescription_detail_page.dart';
import 'widgets/medical_file_appointment_card.dart';
@ -76,6 +79,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
late MedicalFileViewModel medicalFileViewModel;
late BookAppointmentsViewModel bookAppointmentsViewModel;
late LabViewModel labViewModel;
late ActivePrescriptionsViewModel activePrescriptionsViewModel;
int currentIndex = 0;
@ -101,6 +105,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context, listen: false);
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
NavigationService navigationService = getIt.get<NavigationService>();
return CollapsingListView(
title: "Medical File".needTranslation,
@ -574,7 +579,13 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
Expanded(
child: CustomButton(
text: "All Medications".needTranslation,
onPressed: () {},
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: ActiveMedicationPage(),
),
);
},
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,

@ -14,6 +14,8 @@ 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/family_files/family_file_add_widget.dart';
import '../widgets/medication_reminder/reminder_timer_dialog.dart';
abstract class DialogService {
Future<void> showErrorBottomSheet({String title = "", required String message, Function()? onOkPressed, Function()? onCancelPressed});
@ -33,6 +35,8 @@ abstract class DialogService {
Future<void> showPhoneNumberPickerSheet({String? label, String? message, required Function() onSMSPress, required Function() onWhatsappPress});
Future<void> showAddFamilyFileSheet({String? label, String? message, required Function() onVerificationPress});
Future<void> showReminderBottomSheetWithoutHWithChild({String? label, required String message, Widget? child, required Function() onOkPressed, Function()? onCancelPressed});
// TODO : Need to be Fixed showPhoneNumberPickerSheet ( From Login ADn Signup Bottom Sheet Move Here
}
@ -153,6 +157,18 @@ class DialogServiceImp implements DialogService {
);
}
@override
Future<void> showReminderBottomSheetWithoutHWithChild({String? label, required String message, Widget? child, required Function() onOkPressed, Function()? onCancelPressed}) async {
final context = navigationService.navigatorKey.currentContext;
if (context == null) return;
showCommonBottomSheetWithoutHeight(
context,
title: label ?? "",
child: child ?? SizedBox(),
callBackFunc: () {},
);
}
@override
Future<void> showPhoneNumberPickerSheet({String? label, String? message, required Function() onSMSPress, required Function() onWhatsappPress}) async {
final context = navigationService.navigatorKey.currentContext;

@ -68,7 +68,7 @@ class AppColors {
static const Color calenderTextColor = Color(0xFFD0D0D0);
static const Color lightGreenButtonColor = Color(0x2618C273);
static const Color lightRedButtonColor = Color(0x1AED1C2B);
static const Color lightRedButtonColor = Color(0x1AED1C2B);
// Status Colors
static const Color statusPendingColor = Color(0xffCC9B14);
@ -81,4 +81,6 @@ class AppColors {
static const Color infoBannerBorderColor = Color(0xFFFFE5B4);
static const Color infoBannerIconColor = Color(0xFFCC9B14);
static const Color infoBannerTextColor = Color(0xFF856404);
static const Color lightGreyTextColor = Color(0xFF959595);
static const Color labelColorYellow = Color(0xFFFBCB6E);
}

@ -0,0 +1,155 @@
// import 'package:easy_localization/easy_localization.dart';
// import 'package:flutter/material.dart';
// import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
//
// import '../../generated/locale_keys.g.dart';
// import '../../theme/colors.dart';
//
// class ReminderTimerDialog extends StatefulWidget {
// final Function()? onSetReminderPress;
// final String message;
//
// const ReminderTimerDialog(this.onSetReminderPress, this.message, {super.key});
//
//
// @override
// State<ReminderTimerDialog> createState() => _ReminderTimerDialogState();
// }
//
// class _ReminderTimerDialogState extends State<ReminderTimerDialog> {
// final List<String> options = ["Morning", "Afternoon", "Evening", "Midnight"];
// final List<String> selectedTimes = ["Morning"]; // Default selection
//
//
// @override
// Widget build(BuildContext context) {
// return //
// Column(
// children: [
// Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24,
// hasShadow: true,),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// // Checkboxes list
// children: options.map((time) => buildCircleCheckbox(time)).toList(),
// ).paddingAll(16),
// ),
// const SizedBox(height: 25),
// // Buttons Row
// Row(
// children: [
// Expanded(
// child: ElevatedButton.icon(
// onPressed: () => Navigator.pop(context),
// icon: const Icon(Icons.close, color: AppColors.errorColor),
// label: Text(
// LocaleKeys.cancel.tr(),
// style: TextStyle(
// color: AppColors.errorColor,
// fontWeight: FontWeight.w500,
// fontSize: 14
// ),
// ),
// style: ElevatedButton.styleFrom(
// backgroundColor: AppColors.secondaryLightRedColor,
// elevation: 0,
// padding: const EdgeInsets.symmetric(vertical: 14),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(12),
// ),
// ),
// ),
// ),
// const SizedBox(width: 12),
// Expanded(
// child: ElevatedButton.icon(
// onPressed: () {
// Navigator.pop(context, selectedTimes);
// },
// icon: const Icon(Icons.notifications_rounded),
// label: Text(
// LocaleKeys.setReminder.tr(),
// style: TextStyle(
// fontWeight: FontWeight.w500,
// fontSize: 14
// ),
// ),
// style: ElevatedButton.styleFrom(
// backgroundColor: AppColors.successColor,
// foregroundColor: AppColors.whiteColor,
// elevation: 0,
// padding: const EdgeInsets.symmetric(vertical: 14),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(12),
// ),
// ),
// ),
// ),
// ],
// ),
// const SizedBox(height: 30),
// ],
// );
// }
//
// Widget buildCircleCheckbox(String label) {
// final bool isSelected = selectedTimes.contains(label);
// return InkWell(
// onTap: () {
// setState(() {
// if (isSelected) {
// selectedTimes.remove(label);
// } else {
// selectedTimes.add(label);
// }
// });
// },
// borderRadius: BorderRadius.circular(25),
// child: Padding(
// padding: const EdgeInsets.symmetric(vertical: 8.0),
// child: Row(
// children: [
// // Custom circle checkbox
// Container(
// width: 15,
// height: 15,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// border: Border.all(
// color: isSelected ? AppColors.spacerLineColor: AppColors.spacerLineColor,
// width: 1,
// ),
// color: isSelected ? AppColors.errorColor: AppColors.transparent,
// ),
// ),
// const SizedBox(width: 12),
// // Label text
// Text(
// label,
// style: const TextStyle(fontSize: 16, color: Colors.black87),
// ),
// ],
// ),
// ),
// );
// }
//
//
// void showCircleCheckboxDialog(BuildContext context) async {
// final selected = await showDialog<List<String>>(
// context: context,
// builder: (context) => const ReminderTimerDialog(),
// );
//
// if (selected != null && selected.isNotEmpty) {
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text('Reminders set for: ${selected.join(', ')}')),
// );
// }
// }
// }
//
//
//
Loading…
Cancel
Save