active medication

pull/152/head
Fatimah.Alshammari 2 months ago
parent 3f123d12d6
commit eae16eec44

@ -729,7 +729,7 @@ var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatb
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
@ -848,6 +848,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';
// static values for Api
static final double appVersionID = 18.7;

@ -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';
@ -45,6 +47,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 {
@ -103,6 +107,7 @@ class AppDependencies {
getIt.registerLazySingleton<MedicalFileRepo>(() => MedicalFileRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ImmediateLiveCareRepo>(() => ImmediateLiveCareRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<EmergencyServicesRepo>(() => EmergencyServicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ActivePrescriptionsRepo>(() => ActivePrescriptionsRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -202,6 +207,13 @@ class AppDependencies {
),
);
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;

@ -670,7 +670,7 @@ class Utils {
}
/// Widget to build an SVG from network
static Widget buildImgWithNetwork({required String url, required Color iconColor, bool isDisabled = false, double width = 24, double height = 24, BoxFit fit = BoxFit.cover, ImageErrorWidgetBuilder? errorBuilder}) {
static Widget buildImgWithNetwork({required String url, bool isDisabled = false, double width = 24, double height = 24, BoxFit fit = BoxFit.cover, ImageErrorWidgetBuilder? errorBuilder}) {
return Image.network(
url,
width: width,

@ -2,7 +2,6 @@
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';
@ -11,7 +10,7 @@ import '../../services/logger_service.dart';
abstract class ActivePrescriptionsRepo {
Future<Either<Failure, GenericApiModel<dynamic>>> getActivePrescriptionsDetails();
Future<Either<Failure, GenericApiModel<List<ActivePrescriptionsResponseModel>>>> getActivePrescriptionsDetails();
}
@ -23,10 +22,10 @@ class ActivePrescriptionsRepoImp implements ActivePrescriptionsRepo {
@override
Future<Either<Failure, GenericApiModel<dynamic>>> getActivePrescriptionsDetails() async
Future<Either<Failure, GenericApiModel<List<ActivePrescriptionsResponseModel>>>> getActivePrescriptionsDetails() async
{
try {
GenericApiModel<dynamic>? apiResponse;
GenericApiModel<List<ActivePrescriptionsResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getActivePrescriptionsDetails,
@ -36,18 +35,20 @@ class ActivePrescriptionsRepoImp implements ActivePrescriptionsRepo {
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
// final list = response['GetActivePrescriptionReportByPatientIDList'];
// final prescriptionLists = list.map((item) => ActivePrescriptionsResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<ActivePrescriptionsResponseModel>();
var list = response['List_ActiveGetPrescriptionReportByPatientID'];
var res = list
.map<ActivePrescriptionsResponseModel>(
(item) => ActivePrescriptionsResponseModel.fromJson(item))
.toList();
apiResponse = GenericApiModel<dynamic>(
apiResponse = GenericApiModel<List<ActivePrescriptionsResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: response,
// data: response,
data: res
);
return ['List_ActiveGetPrescriptionReportByPatientID'];
//apiResponse;
return apiResponse;
} catch (e) {
failure = DataParsingFailure(e.toString());
}
@ -61,39 +62,4 @@ class ActivePrescriptionsRepoImp implements ActivePrescriptionsRepo {
}
}
//
// Future<Either<Failure, GenericApiModel>> getActiveMedications() {
// try {
// GenericApiModel<dynamic>? apiResponse;
// Failure? failure;
// return apiClient.post(
// ApiConsts.getActivePrescriptionsDetails,
// body: patientDeviceDataRequest,
// onFailure: (error, statusCode, {messageStatus, failureType}) {
// failure = failureType;
// },
// onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
// try {
// apiResponse = GenericApiModel<dynamic>(
// messageStatus: messageStatus,
// statusCode: statusCode,
// errorMessage: errorMessage,
// data: response,
// );
// } catch (e) {
// failure = DataParsingFailure(e.toString());
// }
// },
// ).then((_) {
// if (failure != null) return Left(failure!);
// if (apiResponse == null) return Left(ServerFailure("Unknown error"));
// return Right(apiResponse!);
// });
// } catch (e) {
// return Future.value(Left(UnknownFailure(e.toString())));
// }
// }
}

@ -4,13 +4,17 @@ import 'package:hmg_patient_app_new/features/active_prescriptions/models/active_
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 {
class ActivePrescriptionsViewModel extends ChangeNotifier {
bool isActivePrescriptionsDetailsLoading = false;
late ActivePrescriptionsRepo activePrescriptionsRepo;
late ActivePrescriptionsRepo activePrescriptionsRepo;
late ErrorHandlerService errorHandlerService;
// Prescription Orders Lists
ActivePrescriptionsViewModel({
required this.activePrescriptionsRepo,
required this.errorHandlerService,
});
List<ActivePrescriptionsResponseModel> activePrescriptionsDetailsList = [];
initActivePrescriptionsViewModel() {
@ -20,38 +24,172 @@ class ActivePrescriptionsViewModel extends ChangeNotifier {
setPrescriptionsDetailsLoading() {
isActivePrescriptionsDetailsLoading = true;
// activePrescriptionsDetailsList.clear();
notifyListeners();
}
Future<void> getActiveMedications( {Function(dynamic)? onSuccess, Function(String)? onError})
async {
// Get medications list
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 == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
activePrescriptionsDetailsList = apiResponse.data!;
isActivePrescriptionsDetailsLoading = false;
if (apiResponse.messageStatus == 1) {
activePrescriptionsDetailsList = apiResponse.data ?? [];
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
print(activePrescriptionsDetailsList.length);
}
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();
}
// Extract numeric value ( "3 / week" 3)
int extractNumberFromFrequency(String? frequency) {
if (frequency == null) return 1;
final m = RegExp(r'(\d+)').firstMatch(frequency);
if (m != null) return int.tryParse(m.group(1)!) ?? 1;
return 1;
}
// Generate medication days based on frequency text
List<DateTime> generateMedicationDays(ActivePrescriptionsResponseModel med) {
final start = parseDate(med.startDate);
final duration = med.days ?? 0;
final frequency = (med.frequency ?? "").toLowerCase().trim();
List<DateTime> result = [];
if (duration <= 0) return result;
// Every N hours ( "Every Six Hours", "Every 8 hours")
if (frequency.contains("hour")) {
final match = RegExp(r'every\s+(\d+)').firstMatch(frequency);
int intervalHours = 0;
if (match != null) {
intervalHours = int.tryParse(match.group(1)!) ?? 0;
} else {
// handle text numbers like "Every six hours"
final textNum = {
"one": 1,
"two": 2,
"three": 3,
"four": 4,
"five": 5,
"six": 6,
"seven": 7,
"eight": 8,
"nine": 9,
"ten": 10,
"twelve": 12,
};
for (var key in textNum.keys) {
if (frequency.contains(key)) {
intervalHours = textNum[key]!;
break;
}
}
}
if (intervalHours > 0) {
for (int day = 0; day < duration; day++) {
final dayStart = start.add(Duration(days: day));
for (int hour = 0; hour < 24; hour += intervalHours) {
result.add(DateTime(dayStart.year, dayStart.month, dayStart.day, hour));
}
}
return result;
}
}
// Daily (every day)
if (frequency.contains("day") &&
!frequency.contains("every other") &&
!frequency.contains("every ")) {
for (int i = 0; i < duration; i++) {
result.add(start.add(Duration(days: i)));
}
}
// Every other day
else if (frequency.contains("every other day")) {
for (int i = 0; i < duration; i += 2) {
result.add(start.add(Duration(days: i)));
}
}
// Every N days e.g. "Every 3 days", "Every 5 days"
else if (frequency.contains("every") && frequency.contains("day")) {
final match = RegExp(r'every\s+(\d+)').firstMatch(frequency);
final interval = match != null ? int.tryParse(match.group(1)!) ?? 1 : 1;
for (int i = 0; i < duration; i += interval) {
result.add(start.add(Duration(days: i)));
}
}
// Once or twice a week
else if (frequency.contains("once a week")) {
for (int i = 0; i < duration; i += 7) {
result.add(start.add(Duration(days: i)));
}
} else if (frequency.contains("twice a week")) {
for (int i = 0; i < duration; i += 3) {
result.add(start.add(Duration(days: i)));
}
}
// Numeric frequency like "3 / week", "2 / week"
else if (frequency.contains("week")) {
int timesPerWeek = extractNumberFromFrequency(frequency);
double interval = 7 / timesPerWeek;
double dayPointer = 0;
for (int i = 0; i < duration; i++) {
if (i >= dayPointer.floor()) {
result.add(start.add(Duration(days: i)));
dayPointer += interval;
}
}
}
else {
result.add(start);
}
final unique = <String, DateTime>{};
for (final d in result) {
unique["${d.year}-${d.month}-${d.day}"] = d;
}
return unique.values.toList()..sort((a, b) => a.compareTo(b));
}
bool sameYMD(DateTime a, DateTime b) =>
a.year == b.year && a.month == b.month && a.day == b.day;
// Filter medications for selected day
List<ActivePrescriptionsResponseModel> getMedsForSelectedDay(DateTime selectedDate) {
final target = DateTime(selectedDate.year, selectedDate.month, selectedDate.day);
return activePrescriptionsDetailsList.where((med) {
final days = generateMedicationDays(med);
return days.any((d) => sameYMD(d, target));
}).toList();
}
}

@ -7,7 +7,7 @@ class ActivePrescriptionsResponseModel {
dynamic companyName;
int? days;
dynamic doctorName;
int? doseDailyQuantity;
int? doseDailyQuantity; // doses per day
String? frequency;
int? frequencyNumber;
dynamic image;
@ -23,7 +23,7 @@ class ActivePrescriptionsResponseModel {
dynamic patientName;
dynamic phoneOffice1;
dynamic prescriptionQr;
int? prescriptionTimes;
dynamic prescriptionTimes;
dynamic productImage;
String? productImageBase64;
String? productImageString;
@ -35,6 +35,10 @@ class ActivePrescriptionsResponseModel {
int? scaleOffset;
String? startDate;
// Added for reminder feature
List<String?> selectedDoseTimes = [];
bool isReminderOn = false; // toggle status
ActivePrescriptionsResponseModel({
this.address,
this.appointmentNo,
@ -69,47 +73,57 @@ class ActivePrescriptionsResponseModel {
this.sku,
this.scaleOffset,
this.startDate,
});
factory ActivePrescriptionsResponseModel.fromRawJson(String str) => ActivePrescriptionsResponseModel.fromJson(json.decode(str));
// 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"],
);
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,
@ -145,5 +159,7 @@ class ActivePrescriptionsResponseModel {
"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/doctor_filter/doctor_filter_view_model.dart';
@ -129,6 +130,9 @@ void main() async {
),
ChangeNotifierProvider<EmergencyServicesViewModel>(
create: (_) => getIt.get<EmergencyServicesViewModel>(),
),
ChangeNotifierProvider<ActivePrescriptionsViewModel>(
create: (_) => getIt.get<ActivePrescriptionsViewModel>(),
)
], child: MyApp()),
),

@ -119,7 +119,7 @@ class TrackingScreen extends StatelessWidget {
backgroundColor: AppColors.lightRedButtonColor,
borderColor: Colors.transparent,
text: "Share Your Live Locatin on Whatsapp".needTranslation,
fontSize: 12.fSize,
fontSize: 12.f,
textColor: AppColors.primaryRedColor,
iconColor: AppColors.primaryRedColor,
onPressed: () {},
@ -170,7 +170,7 @@ class TrackingScreen extends StatelessWidget {
return Row(
spacing: 16.h,
children: [
Utils.buildImgWithNetwork(url: "", iconColor: Colors.transparent)
Utils.buildImgWithNetwork(url: "",)
.circle(52.h),
Expanded(
child: Column(
@ -244,7 +244,7 @@ class TrackingScreen extends StatelessWidget {
TextSpan(
text: "Please wait for the call".needTranslation,
style: TextStyle(
fontSize: 21.fSize,
fontSize: 21.f,
fontWeight: FontWeight.w600,
color: AppColors.textColor,
),
@ -252,7 +252,7 @@ class TrackingScreen extends StatelessWidget {
TextSpan(
text: "...".needTranslation,
style: TextStyle(
fontSize: 21.fSize,
fontSize: 21.f,
fontWeight: FontWeight.w600,
color: AppColors.errorColor,
),
@ -265,7 +265,7 @@ class TrackingScreen extends StatelessWidget {
TextSpan(
text: "15:30".needTranslation,
style: TextStyle(
fontSize: 21.fSize,
fontSize: 21.f,
fontWeight: FontWeight.w600,
color: AppColors.textColor,
),
@ -273,7 +273,7 @@ class TrackingScreen extends StatelessWidget {
TextSpan(
text: " mins ".needTranslation,
style: TextStyle(
fontSize: 21.fSize,
fontSize: 21.f,
fontWeight: FontWeight.w600,
color: AppColors.errorColor,
),
@ -281,7 +281,7 @@ class TrackingScreen extends StatelessWidget {
TextSpan(
text: "to hospital".needTranslation,
style: TextStyle(
fontSize: 21.fSize,
fontSize: 21.f,
fontWeight: FontWeight.w600,
color: AppColors.textColor,
),

@ -49,7 +49,7 @@ class NearestERItem extends StatelessWidget {
).toShimmer2(isShow: isLoading)
: Utils.buildImgWithNetwork(
url: nearestERItem.projectImageURL ?? '',
iconColor: Colors.transparent,
// iconColor: Colors.transparent,
).circle(24.h).toShimmer2(isShow: isLoading),
const SizedBox(width: 12),
Expanded(

@ -351,7 +351,16 @@ class _LandingPageState extends State<LandingPage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Quick Links".needTranslation.toText16(isBold: true),
CustomButton(text: "Quick Links".needTranslation,
onPressed: () {
Navigator.of(context).push(
CustomPageRoute(
page: ActiveMedicationPage(),
),
);
},
),
// "Quick Links".needTranslation.toText16(isBold: true),
Row(
children: [
"View medical file".needTranslation.toText12(color: AppColors.primaryRedColor),

@ -77,5 +77,7 @@ static const Color calenderTextColor = Color(0xFFD0D0D0);
static const Color lightGreenButtonColor = Color(0x2618C273);
static const Color lightRedButtonColor = Color(0x1AED1C2B);
static const Color lightGreyTextColor = Color(0xFF959595);
static const Color labelColorYellow = Color(0xFFFBCB6E);
}

Loading…
Cancel
Save