Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan
# Conflicts: # lib/core/api_consts.dart # lib/features/hmg_services/hmg_services_repo.dart # lib/features/hmg_services/hmg_services_view_model.dart # lib/presentation/emergency_services/call_ambulance/widgets/pickup_location.dartpull/104/head
commit
5f047e1b6f
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 543 KiB |
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.49411 2.85661C9.06887 2.71829 8.56575 2.71849 7.82926 2.71878L5.20973 2.7188C4.36011 2.71878 3.66581 2.71877 3.11767 2.79255C2.5447 2.86967 2.04795 3.03656 1.65143 3.43352C1.25491 3.83049 1.0882 4.32779 1.01117 4.90139C0.93747 5.45014 0.937484 6.14521 0.9375 6.99576V10.0798C0.937484 10.9303 0.93747 11.6254 1.01117 12.1741C1.0882 12.7477 1.25491 13.245 1.65143 13.642C1.76583 13.7565 1.89283 13.8531 2.02893 13.9345C2.22063 14.0492 2.31647 14.1065 2.39389 14.059C2.47131 14.0115 2.46224 13.8786 2.44411 13.6127C2.43973 13.5484 2.4375 13.4836 2.4375 13.4181C2.4375 11.8631 3.6967 10.6025 5.25 10.6025C6.8033 10.6025 8.0625 11.8631 8.0625 13.4181C8.0625 13.5947 8.04626 13.7675 8.01519 13.9351C7.97875 14.1317 7.96053 14.23 8.00499 14.2841C8.04945 14.3381 8.14092 14.3389 8.32387 14.3406C8.77449 14.3448 9.22551 14.3448 9.67614 14.3406C9.85908 14.3389 9.95055 14.3381 9.99501 14.2841C10.0395 14.23 10.0213 14.1317 9.98481 13.9351C9.95374 13.7675 9.9375 13.5947 9.9375 13.4181C9.9375 11.8631 11.1967 10.6025 12.75 10.6025C14.3033 10.6025 15.5625 11.8631 15.5625 13.4181C15.5625 13.4835 15.5603 13.5484 15.5559 13.6127C15.5378 13.8786 15.5287 14.0115 15.6061 14.059C15.6835 14.1065 15.7794 14.0492 15.9711 13.9345C16.1072 13.8531 16.2342 13.7565 16.3486 13.642C16.7451 13.245 16.9118 12.7477 16.9888 12.1741C17.0625 11.6254 17.0625 10.9303 17.0625 10.0798V8.55433C17.0654 8.4286 17.0367 8.30042 16.9729 8.18177L15.9988 6.37069C15.7544 5.91626 15.5451 5.52708 15.3388 5.22173C15.1184 4.89536 14.8689 4.61351 14.5195 4.40455C14.17 4.19558 13.8038 4.10932 13.4123 4.06973C13.046 4.0327 12.6044 4.03272 12.0889 4.03274L11.2524 4.03274C11.1353 4.03274 11.0767 4.03274 11.0295 4.00933C10.9823 3.98592 10.9424 3.93349 10.8626 3.82864C10.5202 3.37853 10.0455 3.03597 9.49411 2.85661ZM11.7406 5.53441C11.5945 5.53441 11.5214 5.53441 11.4773 5.57901C11.4333 5.62362 11.4342 5.69802 11.4359 5.84684C11.4377 5.99664 11.4376 6.15736 11.4375 6.33106C11.4375 6.93389 11.4444 7.20613 11.4834 7.32612C11.5761 7.61185 11.7999 7.83587 12.0853 7.92871C12.2052 7.96769 12.3728 7.97464 12.975 7.97464H14.6556C14.8798 7.97464 14.9919 7.97464 15.0355 7.90148C15.0792 7.82832 15.026 7.72952 14.9197 7.53192L14.6949 7.11386C14.429 6.61959 14.2551 6.29803 14.0963 6.06291C13.9469 5.84183 13.845 5.75037 13.7503 5.69375C13.6556 5.63714 13.5268 5.59062 13.2616 5.5638C12.9795 5.53529 12.6142 5.53441 12.0535 5.53441H11.7406ZM4.5001 5.53125C4.91431 5.53125 5.2501 5.86704 5.2501 6.28125V7.78125C5.2501 8.19546 4.91431 8.53125 4.5001 8.53125C4.08589 8.53125 3.7501 8.19546 3.7501 7.78125V6.28125C3.7501 5.86704 4.08589 5.53125 4.5001 5.53125ZM7.5001 5.53125C7.91431 5.53125 8.2501 5.86704 8.2501 6.28125V7.78125C8.2501 8.19546 7.91431 8.53125 7.5001 8.53125C7.08589 8.53125 6.7501 8.19546 6.7501 7.78125V6.28125C6.7501 5.86704 7.08589 5.53125 7.5001 5.53125Z" fill="#2E3039"/>
|
||||||
|
<path d="M5.25 11.5312C4.21447 11.5312 3.375 12.3707 3.375 13.4062C3.375 14.4418 4.21447 15.2812 5.25 15.2812C6.28553 15.2812 7.125 14.4418 7.125 13.4062C7.125 12.3707 6.28553 11.5312 5.25 11.5312Z" fill="#2E3039"/>
|
||||||
|
<path d="M12.75 11.5312C11.7145 11.5312 10.875 12.3707 10.875 13.4062C10.875 14.4418 11.7145 15.2812 12.75 15.2812C13.7855 15.2812 14.625 14.4418 14.625 13.4062C14.625 12.3707 13.7855 11.5312 12.75 11.5312Z" fill="#2E3039"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.4 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,11 @@
|
|||||||
|
class FeedbackType {
|
||||||
|
final int id;
|
||||||
|
final String nameEN;
|
||||||
|
final String nameAR;
|
||||||
|
|
||||||
|
FeedbackType({
|
||||||
|
required this.id,
|
||||||
|
required this.nameEN,
|
||||||
|
required this.nameAR,
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,137 @@
|
|||||||
|
class RequestInsertCOCItem {
|
||||||
|
bool? isUserLoggedIn;
|
||||||
|
String? mobileNo;
|
||||||
|
int? identificationNo;
|
||||||
|
int? patientID;
|
||||||
|
int? patientOutSA;
|
||||||
|
int? patientTypeID;
|
||||||
|
String? tokenID;
|
||||||
|
String? patientName;
|
||||||
|
int? projectID;
|
||||||
|
String? fileName;
|
||||||
|
String? attachment;
|
||||||
|
String? uILanguage;
|
||||||
|
String? browserInfo;
|
||||||
|
String? cOCTypeName;
|
||||||
|
String? formTypeID;
|
||||||
|
String? details;
|
||||||
|
String? deviceInfo;
|
||||||
|
String? deviceType;
|
||||||
|
String? title;
|
||||||
|
String? resolution;
|
||||||
|
double? versionID;
|
||||||
|
int? channel;
|
||||||
|
int? languageID;
|
||||||
|
String? iPAdress;
|
||||||
|
String? generalid;
|
||||||
|
String? sessionID;
|
||||||
|
bool? isDentalAllowedBackend;
|
||||||
|
int? deviceTypeID;
|
||||||
|
int? patientType;
|
||||||
|
double? appVersion;
|
||||||
|
bool? forDemo;
|
||||||
|
|
||||||
|
RequestInsertCOCItem(
|
||||||
|
{this.isUserLoggedIn,
|
||||||
|
this.mobileNo,
|
||||||
|
this.identificationNo,
|
||||||
|
this.patientID,
|
||||||
|
this.patientOutSA,
|
||||||
|
this.patientTypeID,
|
||||||
|
this.tokenID,
|
||||||
|
this.patientName,
|
||||||
|
this.projectID,
|
||||||
|
this.fileName,
|
||||||
|
this.attachment,
|
||||||
|
this.uILanguage,
|
||||||
|
this.browserInfo,
|
||||||
|
this.cOCTypeName,
|
||||||
|
this.formTypeID,
|
||||||
|
this.details,
|
||||||
|
this.deviceInfo,
|
||||||
|
this.deviceType,
|
||||||
|
this.title,
|
||||||
|
this.resolution,
|
||||||
|
this.versionID,
|
||||||
|
this.channel,
|
||||||
|
this.languageID,
|
||||||
|
this.iPAdress,
|
||||||
|
this.generalid,
|
||||||
|
this.sessionID,
|
||||||
|
this.isDentalAllowedBackend,
|
||||||
|
this.deviceTypeID,
|
||||||
|
this.patientType,
|
||||||
|
this.appVersion,
|
||||||
|
this.forDemo});
|
||||||
|
|
||||||
|
RequestInsertCOCItem.fromJson(Map<String, dynamic> json) {
|
||||||
|
isUserLoggedIn = json['IsUserLoggedIn'];
|
||||||
|
mobileNo = json['MobileNo'];
|
||||||
|
identificationNo = json['IdentificationNo'];
|
||||||
|
patientID = json['PatientID'];
|
||||||
|
patientOutSA = json['PatientOutSA'];
|
||||||
|
patientTypeID = json['PatientTypeID'];
|
||||||
|
tokenID = json['TokenID'];
|
||||||
|
patientName = json['PatientName'];
|
||||||
|
projectID = json['ProjectID'];
|
||||||
|
fileName = json['FileName'];
|
||||||
|
attachment = json['Attachment'];
|
||||||
|
uILanguage = json['UILanguage'];
|
||||||
|
browserInfo = json['BrowserInfo'];
|
||||||
|
cOCTypeName = json['COCTypeName'];
|
||||||
|
formTypeID = json['FormTypeID'];
|
||||||
|
details = json['Details'];
|
||||||
|
deviceInfo = json['DeviceInfo'];
|
||||||
|
deviceType = json['DeviceType'];
|
||||||
|
title = json['Title'];
|
||||||
|
resolution = json['Resolution'];
|
||||||
|
versionID = json['VersionID'];
|
||||||
|
channel = json['Channel'];
|
||||||
|
languageID = json['LanguageID'];
|
||||||
|
iPAdress = json['IPAdress'];
|
||||||
|
generalid = json['generalid'];
|
||||||
|
sessionID = json['SessionID'];
|
||||||
|
isDentalAllowedBackend = json['isDentalAllowedBackend'];
|
||||||
|
deviceTypeID = json['DeviceTypeID'];
|
||||||
|
patientType = json['PatientType'];
|
||||||
|
appVersion = json['AppVersion'];
|
||||||
|
forDemo = json['ForDemo'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['IsUserLoggedIn'] = this.isUserLoggedIn;
|
||||||
|
data['MobileNo'] = this.mobileNo;
|
||||||
|
data['IdentificationNo'] = this.identificationNo;
|
||||||
|
data['PatientID'] = this.patientID;
|
||||||
|
data['PatientOutSA'] = this.patientOutSA;
|
||||||
|
data['PatientTypeID'] = this.patientTypeID;
|
||||||
|
data['TokenID'] = this.tokenID;
|
||||||
|
data['PatientName'] = this.patientName;
|
||||||
|
data['ProjectID'] = this.projectID;
|
||||||
|
data['FileName'] = this.fileName;
|
||||||
|
data['Attachment'] = this.attachment;
|
||||||
|
data['UILanguage'] = this.uILanguage;
|
||||||
|
data['BrowserInfo'] = this.browserInfo;
|
||||||
|
data['COCTypeName'] = this.cOCTypeName;
|
||||||
|
data['FormTypeID'] = this.formTypeID;
|
||||||
|
data['Details'] = this.details;
|
||||||
|
data['DeviceInfo'] = this.deviceInfo;
|
||||||
|
data['DeviceType'] = this.deviceType;
|
||||||
|
data['Title'] = this.title;
|
||||||
|
data['Resolution'] = this.resolution;
|
||||||
|
data['VersionID'] = this.versionID;
|
||||||
|
data['Channel'] = this.channel;
|
||||||
|
data['LanguageID'] = this.languageID;
|
||||||
|
data['IPAdress'] = this.iPAdress;
|
||||||
|
data['generalid'] = this.generalid;
|
||||||
|
data['SessionID'] = this.sessionID;
|
||||||
|
data['isDentalAllowedBackend'] = this.isDentalAllowedBackend;
|
||||||
|
data['DeviceTypeID'] = this.deviceTypeID;
|
||||||
|
data['PatientType'] = this.patientType;
|
||||||
|
data['AppVersion'] = this.appVersion;
|
||||||
|
data['ForDemo'] = this.forDemo;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
enum OrderDislpay{
|
||||||
|
ALL,RRT,AMBULANCE
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
class RRTRequestModel {
|
||||||
|
num? patientId;
|
||||||
|
int? patientOutSa;
|
||||||
|
bool? isOutPatient;
|
||||||
|
int? nearestProjectId;
|
||||||
|
num? longitude;
|
||||||
|
num? latitude;
|
||||||
|
String? additionalDetails;
|
||||||
|
String? nationality;
|
||||||
|
num? paymentAmount;
|
||||||
|
List<Procedures>? procedures;
|
||||||
|
|
||||||
|
RRTRequestModel(
|
||||||
|
{this.patientId,
|
||||||
|
this.patientOutSa,
|
||||||
|
this.isOutPatient,
|
||||||
|
this.nearestProjectId,
|
||||||
|
this.longitude,
|
||||||
|
this.latitude,
|
||||||
|
this.additionalDetails,
|
||||||
|
this.nationality,
|
||||||
|
this.paymentAmount,
|
||||||
|
this.procedures});
|
||||||
|
|
||||||
|
RRTRequestModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
patientId = json['patientId'];
|
||||||
|
patientOutSa = json['patientOutSa'];
|
||||||
|
isOutPatient = json['isOutPatient'];
|
||||||
|
nearestProjectId = json['nearestProjectId'];
|
||||||
|
longitude = json['longitude'];
|
||||||
|
latitude = json['latitude'];
|
||||||
|
additionalDetails = json['additionalDetails'];
|
||||||
|
nationality = json['nationality'];
|
||||||
|
paymentAmount = json['paymentAmount'];
|
||||||
|
if (json['procedures'] != null) {
|
||||||
|
procedures = <Procedures>[];
|
||||||
|
json['procedures'].forEach((v) {
|
||||||
|
procedures!.add(new Procedures.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['patientId'] = this.patientId;
|
||||||
|
data['patientOutSa'] = this.patientOutSa;
|
||||||
|
data['isOutPatient'] = this.isOutPatient;
|
||||||
|
data['nearestProjectId'] = this.nearestProjectId;
|
||||||
|
data['longitude'] = this.longitude;
|
||||||
|
data['latitude'] = this.latitude;
|
||||||
|
data['additionalDetails'] = this.additionalDetails;
|
||||||
|
data['nationality'] = this.nationality;
|
||||||
|
data['paymentAmount'] = this.paymentAmount;
|
||||||
|
if (this.procedures != null) {
|
||||||
|
data['procedures'] = this.procedures!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Procedures {
|
||||||
|
String? serviceID;
|
||||||
|
|
||||||
|
Procedures({this.serviceID});
|
||||||
|
|
||||||
|
Procedures.fromJson(Map<String, dynamic> json) {
|
||||||
|
serviceID = json['ServiceID'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['ServiceID'] = this.serviceID;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
class ServicePrice {
|
||||||
|
String? currency;
|
||||||
|
dynamic maxPrice;
|
||||||
|
dynamic maxTotalPrice;
|
||||||
|
dynamic maxVAT;
|
||||||
|
dynamic minPrice;
|
||||||
|
dynamic minTotalPrice;
|
||||||
|
dynamic minVAT;
|
||||||
|
dynamic price;
|
||||||
|
dynamic totalPrice;
|
||||||
|
dynamic vat;
|
||||||
|
|
||||||
|
ServicePrice({
|
||||||
|
this.currency,
|
||||||
|
this.maxPrice,
|
||||||
|
this.maxTotalPrice,
|
||||||
|
this.maxVAT,
|
||||||
|
this.minPrice,
|
||||||
|
this.minTotalPrice,
|
||||||
|
this.minVAT,
|
||||||
|
this.price,
|
||||||
|
this.totalPrice,
|
||||||
|
this.vat});
|
||||||
|
|
||||||
|
ServicePrice.fromJson(dynamic json) {
|
||||||
|
currency = json["Currency"];
|
||||||
|
maxPrice = json["MaxPrice"];
|
||||||
|
maxTotalPrice = json["MaxTotalPrice"];
|
||||||
|
maxVAT = json["MaxVAT"];
|
||||||
|
minPrice = json["MinPrice"];
|
||||||
|
minTotalPrice = json["MinTotalPrice"];
|
||||||
|
minVAT = json["MinVAT"];
|
||||||
|
price = json["Price"];
|
||||||
|
totalPrice = json["TotalPrice"];
|
||||||
|
vat = json["VAT"];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
var map = <String, dynamic>{};
|
||||||
|
map["Currency"] = currency;
|
||||||
|
map["MaxPrice"] = maxPrice;
|
||||||
|
map["MaxTotalPrice"] = maxTotalPrice;
|
||||||
|
map["MaxVAT"] = maxVAT;
|
||||||
|
map["MinPrice"] = minPrice;
|
||||||
|
map["MinTotalPrice"] = minTotalPrice;
|
||||||
|
map["MinVAT"] = minVAT;
|
||||||
|
map["Price"] = price;
|
||||||
|
map["TotalPrice"] = totalPrice;
|
||||||
|
map["VAT"] = vat;
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,406 @@
|
|||||||
|
class RRTServiceData {
|
||||||
|
List<GetCMCAllOrdersResponseModel> pendingOrders = [];
|
||||||
|
List<GetCMCAllOrdersResponseModel> completedOrders = [];
|
||||||
|
ServicePrice servicePrice = ServicePrice();
|
||||||
|
}
|
||||||
|
|
||||||
|
class GetCMCAllOrdersResponseModel {
|
||||||
|
int? iD;
|
||||||
|
int? patientId;
|
||||||
|
int? patientOutSa;
|
||||||
|
bool? isOutPatient;
|
||||||
|
int? projectId;
|
||||||
|
int? nearestProjectId;
|
||||||
|
dynamic longitude;
|
||||||
|
dynamic latitude;
|
||||||
|
dynamic appointmentNo;
|
||||||
|
dynamic dischargeId;
|
||||||
|
int? statusId;
|
||||||
|
int? serviceId;
|
||||||
|
int? channel;
|
||||||
|
Orderpayment? orderpayment;
|
||||||
|
dynamic orderselectedservice;
|
||||||
|
dynamic wforder;
|
||||||
|
dynamic orderapprovalobj;
|
||||||
|
String? created;
|
||||||
|
dynamic createdBy;
|
||||||
|
dynamic modified;
|
||||||
|
dynamic modifiedBy;
|
||||||
|
bool? isDeleted;
|
||||||
|
String? statusText;
|
||||||
|
int? paymentStatus;
|
||||||
|
dynamic clientRequestid;
|
||||||
|
dynamic paymentStatusText;
|
||||||
|
String? projectName;
|
||||||
|
String? nearestProjectName;
|
||||||
|
dynamic paymentAmount;
|
||||||
|
WFOrder? wFOrder;
|
||||||
|
String? serviceText;
|
||||||
|
bool? isSentForApproval;
|
||||||
|
int? exaCartOrderId;
|
||||||
|
bool? isTimer;
|
||||||
|
int? timeSeconds;
|
||||||
|
int? totalPendingSeconds;
|
||||||
|
int? timeMinute;
|
||||||
|
int? timeHour;
|
||||||
|
int? timeTotalSeconds;
|
||||||
|
int? timeTotalMinute;
|
||||||
|
int? timeTotalHour;
|
||||||
|
dynamic approvalStatus;
|
||||||
|
bool? isActive;
|
||||||
|
int? clickButton;
|
||||||
|
List<dynamic>? procedures;
|
||||||
|
dynamic pickupLocation;
|
||||||
|
dynamic dropOffLocation;
|
||||||
|
dynamic clinicName;
|
||||||
|
dynamic doctorName;
|
||||||
|
dynamic branch;
|
||||||
|
dynamic time;
|
||||||
|
dynamic notes;
|
||||||
|
|
||||||
|
GetCMCAllOrdersResponseModel(
|
||||||
|
{this.iD,
|
||||||
|
this.patientId,
|
||||||
|
this.patientOutSa,
|
||||||
|
this.isOutPatient,
|
||||||
|
this.projectId,
|
||||||
|
this.nearestProjectId,
|
||||||
|
this.longitude,
|
||||||
|
this.latitude,
|
||||||
|
this.appointmentNo,
|
||||||
|
this.dischargeId,
|
||||||
|
this.statusId,
|
||||||
|
this.serviceId,
|
||||||
|
this.channel,
|
||||||
|
this.orderpayment,
|
||||||
|
this.orderselectedservice,
|
||||||
|
this.wforder,
|
||||||
|
this.orderapprovalobj,
|
||||||
|
this.created,
|
||||||
|
this.createdBy,
|
||||||
|
this.modified,
|
||||||
|
this.modifiedBy,
|
||||||
|
this.isDeleted,
|
||||||
|
this.statusText,
|
||||||
|
this.paymentStatus,
|
||||||
|
this.clientRequestid,
|
||||||
|
this.paymentStatusText,
|
||||||
|
this.projectName,
|
||||||
|
this.nearestProjectName,
|
||||||
|
this.paymentAmount,
|
||||||
|
this.wFOrder,
|
||||||
|
this.serviceText,
|
||||||
|
this.isSentForApproval,
|
||||||
|
this.exaCartOrderId,
|
||||||
|
this.isTimer,
|
||||||
|
this.timeSeconds,
|
||||||
|
this.totalPendingSeconds,
|
||||||
|
this.timeMinute,
|
||||||
|
this.timeHour,
|
||||||
|
this.timeTotalSeconds,
|
||||||
|
this.timeTotalMinute,
|
||||||
|
this.timeTotalHour,
|
||||||
|
this.approvalStatus,
|
||||||
|
this.isActive,
|
||||||
|
this.clickButton,
|
||||||
|
this.procedures,
|
||||||
|
this.pickupLocation,
|
||||||
|
this.dropOffLocation,
|
||||||
|
this.clinicName,
|
||||||
|
this.doctorName,
|
||||||
|
this.branch,
|
||||||
|
this.time,
|
||||||
|
this.notes});
|
||||||
|
|
||||||
|
GetCMCAllOrdersResponseModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
iD = json['ID'];
|
||||||
|
patientId = json['PatientId'];
|
||||||
|
patientOutSa = json['PatientOutSa'];
|
||||||
|
isOutPatient = json['IsOutPatient'];
|
||||||
|
projectId = json['ProjectId'];
|
||||||
|
nearestProjectId = json['NearestProjectId'];
|
||||||
|
longitude = json['Longitude'];
|
||||||
|
latitude = json['Latitude'];
|
||||||
|
appointmentNo = json['AppointmentNo'];
|
||||||
|
dischargeId = json['DischargeId'];
|
||||||
|
statusId = json['StatusId'];
|
||||||
|
serviceId = json['ServiceId'];
|
||||||
|
channel = json['Channel'];
|
||||||
|
orderpayment = json['orderpayment'] != null
|
||||||
|
? new Orderpayment.fromJson(json['orderpayment'])
|
||||||
|
: null;
|
||||||
|
orderselectedservice = json['orderselectedservice'];
|
||||||
|
wforder = json['wforder'];
|
||||||
|
orderapprovalobj = json['orderapprovalobj'];
|
||||||
|
created = json['Created'];
|
||||||
|
createdBy = json['CreatedBy'];
|
||||||
|
modified = json['Modified'];
|
||||||
|
modifiedBy = json['ModifiedBy'];
|
||||||
|
isDeleted = json['IsDeleted'];
|
||||||
|
statusText = json['StatusText'];
|
||||||
|
paymentStatus = json['PaymentStatus'];
|
||||||
|
clientRequestid = json['ClientRequestid'];
|
||||||
|
paymentStatusText = json['PaymentStatusText'];
|
||||||
|
projectName = json['ProjectName'];
|
||||||
|
nearestProjectName = json['NearestProjectName'];
|
||||||
|
paymentAmount = json['PaymentAmount'];
|
||||||
|
wFOrder = json['WF_order'] != null
|
||||||
|
? new WFOrder.fromJson(json['WF_order'])
|
||||||
|
: null;
|
||||||
|
serviceText = json['ServiceText'];
|
||||||
|
isSentForApproval = json['isSentForApproval'];
|
||||||
|
exaCartOrderId = json['ExaCart_OrderId'];
|
||||||
|
isTimer = json['isTimer'];
|
||||||
|
timeSeconds = json['TimeSeconds'];
|
||||||
|
totalPendingSeconds = json['TotalPendingSeconds'];
|
||||||
|
timeMinute = json['TimeMinute'];
|
||||||
|
timeHour = json['TimeHour'];
|
||||||
|
timeTotalSeconds = json['TimeTotalSeconds'];
|
||||||
|
timeTotalMinute = json['TimeTotalMinute'];
|
||||||
|
timeTotalHour = json['TimeTotalHour'];
|
||||||
|
approvalStatus = json['ApprovalStatus'];
|
||||||
|
isActive = json['isActive'];
|
||||||
|
clickButton = json['ClickButton'];
|
||||||
|
pickupLocation = json['PickupLocation'];
|
||||||
|
dropOffLocation = json['DropOffLocation'];
|
||||||
|
clinicName = json['clinicName'];
|
||||||
|
doctorName = json['DoctorName'];
|
||||||
|
branch = json['Branch'];
|
||||||
|
time = json['Time'];
|
||||||
|
notes = json['Notes'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['ID'] = this.iD;
|
||||||
|
data['PatientId'] = this.patientId;
|
||||||
|
data['PatientOutSa'] = this.patientOutSa;
|
||||||
|
data['IsOutPatient'] = this.isOutPatient;
|
||||||
|
data['ProjectId'] = this.projectId;
|
||||||
|
data['NearestProjectId'] = this.nearestProjectId;
|
||||||
|
data['Longitude'] = this.longitude;
|
||||||
|
data['Latitude'] = this.latitude;
|
||||||
|
data['AppointmentNo'] = this.appointmentNo;
|
||||||
|
data['DischargeId'] = this.dischargeId;
|
||||||
|
data['StatusId'] = this.statusId;
|
||||||
|
data['ServiceId'] = this.serviceId;
|
||||||
|
data['Channel'] = this.channel;
|
||||||
|
if (this.orderpayment != null) {
|
||||||
|
data['orderpayment'] = this.orderpayment!.toJson();
|
||||||
|
}
|
||||||
|
data['orderselectedservice'] = this.orderselectedservice;
|
||||||
|
|
||||||
|
data['wforder'] = this.wforder;
|
||||||
|
data['orderapprovalobj'] = this.orderapprovalobj;
|
||||||
|
data['Created'] = this.created;
|
||||||
|
data['CreatedBy'] = this.createdBy;
|
||||||
|
data['Modified'] = this.modified;
|
||||||
|
data['ModifiedBy'] = this.modifiedBy;
|
||||||
|
data['IsDeleted'] = this.isDeleted;
|
||||||
|
data['StatusText'] = this.statusText;
|
||||||
|
data['PaymentStatus'] = this.paymentStatus;
|
||||||
|
data['ClientRequestid'] = this.clientRequestid;
|
||||||
|
data['PaymentStatusText'] = this.paymentStatusText;
|
||||||
|
data['ProjectName'] = this.projectName;
|
||||||
|
data['NearestProjectName'] = this.nearestProjectName;
|
||||||
|
data['PaymentAmount'] = this.paymentAmount;
|
||||||
|
if (this.wFOrder != null) {
|
||||||
|
data['WF_order'] = this.wFOrder!.toJson();
|
||||||
|
}
|
||||||
|
data['ServiceText'] = this.serviceText;
|
||||||
|
data['isSentForApproval'] = this.isSentForApproval;
|
||||||
|
data['ExaCart_OrderId'] = this.exaCartOrderId;
|
||||||
|
data['isTimer'] = this.isTimer;
|
||||||
|
data['TimeSeconds'] = this.timeSeconds;
|
||||||
|
data['TotalPendingSeconds'] = this.totalPendingSeconds;
|
||||||
|
data['TimeMinute'] = this.timeMinute;
|
||||||
|
data['TimeHour'] = this.timeHour;
|
||||||
|
data['TimeTotalSeconds'] = this.timeTotalSeconds;
|
||||||
|
data['TimeTotalMinute'] = this.timeTotalMinute;
|
||||||
|
data['TimeTotalHour'] = this.timeTotalHour;
|
||||||
|
data['ApprovalStatus'] = this.approvalStatus;
|
||||||
|
data['isActive'] = this.isActive;
|
||||||
|
data['ClickButton'] = this.clickButton;
|
||||||
|
data['PickupLocation'] = this.pickupLocation;
|
||||||
|
data['DropOffLocation'] = this.dropOffLocation;
|
||||||
|
data['clinicName'] = this.clinicName;
|
||||||
|
data['DoctorName'] = this.doctorName;
|
||||||
|
data['Branch'] = this.branch;
|
||||||
|
data['Time'] = this.time;
|
||||||
|
data['Notes'] = this.notes;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Orderpayment {
|
||||||
|
int? iD;
|
||||||
|
int? orderId;
|
||||||
|
dynamic clientRequestId;
|
||||||
|
dynamic totalAmount;
|
||||||
|
int? paymentStatus;
|
||||||
|
dynamic order;
|
||||||
|
String? created;
|
||||||
|
dynamic createdBy;
|
||||||
|
dynamic modified;
|
||||||
|
dynamic modifiedBy;
|
||||||
|
bool? isDeleted;
|
||||||
|
|
||||||
|
Orderpayment(
|
||||||
|
{this.iD,
|
||||||
|
this.orderId,
|
||||||
|
this.clientRequestId,
|
||||||
|
this.totalAmount,
|
||||||
|
this.paymentStatus,
|
||||||
|
this.order,
|
||||||
|
this.created,
|
||||||
|
this.createdBy,
|
||||||
|
this.modified,
|
||||||
|
this.modifiedBy,
|
||||||
|
this.isDeleted});
|
||||||
|
|
||||||
|
Orderpayment.fromJson(Map<String, dynamic> json) {
|
||||||
|
iD = json['ID'];
|
||||||
|
orderId = json['OrderId'];
|
||||||
|
clientRequestId = json['ClientRequestId'];
|
||||||
|
totalAmount = json['TotalAmount'];
|
||||||
|
paymentStatus = json['PaymentStatus'];
|
||||||
|
order = json['Order'];
|
||||||
|
created = json['Created'];
|
||||||
|
createdBy = json['CreatedBy'];
|
||||||
|
modified = json['Modified'];
|
||||||
|
modifiedBy = json['ModifiedBy'];
|
||||||
|
isDeleted = json['IsDeleted'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['ID'] = this.iD;
|
||||||
|
data['OrderId'] = this.orderId;
|
||||||
|
data['ClientRequestId'] = this.clientRequestId;
|
||||||
|
data['TotalAmount'] = this.totalAmount;
|
||||||
|
data['PaymentStatus'] = this.paymentStatus;
|
||||||
|
data['Order'] = this.order;
|
||||||
|
data['Created'] = this.created;
|
||||||
|
data['CreatedBy'] = this.createdBy;
|
||||||
|
data['Modified'] = this.modified;
|
||||||
|
data['ModifiedBy'] = this.modifiedBy;
|
||||||
|
data['IsDeleted'] = this.isDeleted;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WFOrder {
|
||||||
|
dynamic wfButtonsDTO;
|
||||||
|
int? iD;
|
||||||
|
int? orderId;
|
||||||
|
int? previousStep;
|
||||||
|
int? nextStep;
|
||||||
|
int? serviceId;
|
||||||
|
dynamic order;
|
||||||
|
String? created;
|
||||||
|
dynamic createdBy;
|
||||||
|
dynamic modified;
|
||||||
|
dynamic modifiedBy;
|
||||||
|
bool? isDeleted;
|
||||||
|
|
||||||
|
WFOrder(
|
||||||
|
{this.wfButtonsDTO,
|
||||||
|
this.iD,
|
||||||
|
this.orderId,
|
||||||
|
this.previousStep,
|
||||||
|
this.nextStep,
|
||||||
|
this.serviceId,
|
||||||
|
this.order,
|
||||||
|
this.created,
|
||||||
|
this.createdBy,
|
||||||
|
this.modified,
|
||||||
|
this.modifiedBy,
|
||||||
|
this.isDeleted});
|
||||||
|
|
||||||
|
WFOrder.fromJson(Map<String, dynamic> json) {
|
||||||
|
wfButtonsDTO = json['wf_ButtonsDTO'];
|
||||||
|
iD = json['ID'];
|
||||||
|
orderId = json['OrderId'];
|
||||||
|
previousStep = json['PreviousStep'];
|
||||||
|
nextStep = json['NextStep'];
|
||||||
|
serviceId = json['ServiceId'];
|
||||||
|
order = json['Order'];
|
||||||
|
created = json['Created'];
|
||||||
|
createdBy = json['CreatedBy'];
|
||||||
|
modified = json['Modified'];
|
||||||
|
modifiedBy = json['ModifiedBy'];
|
||||||
|
isDeleted = json['IsDeleted'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['wf_ButtonsDTO'] = this.wfButtonsDTO;
|
||||||
|
data['ID'] = this.iD;
|
||||||
|
data['OrderId'] = this.orderId;
|
||||||
|
data['PreviousStep'] = this.previousStep;
|
||||||
|
data['NextStep'] = this.nextStep;
|
||||||
|
data['ServiceId'] = this.serviceId;
|
||||||
|
data['Order'] = this.order;
|
||||||
|
data['Created'] = this.created;
|
||||||
|
data['CreatedBy'] = this.createdBy;
|
||||||
|
data['Modified'] = this.modified;
|
||||||
|
data['ModifiedBy'] = this.modifiedBy;
|
||||||
|
data['IsDeleted'] = this.isDeleted;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ServicePrice {
|
||||||
|
String? currency;
|
||||||
|
dynamic maxPrice;
|
||||||
|
dynamic maxTotalPrice;
|
||||||
|
dynamic maxVAT;
|
||||||
|
dynamic minPrice;
|
||||||
|
dynamic minTotalPrice;
|
||||||
|
dynamic minVAT;
|
||||||
|
dynamic price;
|
||||||
|
dynamic totalPrice;
|
||||||
|
dynamic vat;
|
||||||
|
|
||||||
|
ServicePrice({
|
||||||
|
this.currency,
|
||||||
|
this.maxPrice,
|
||||||
|
this.maxTotalPrice,
|
||||||
|
this.maxVAT,
|
||||||
|
this.minPrice,
|
||||||
|
this.minTotalPrice,
|
||||||
|
this.minVAT,
|
||||||
|
this.price,
|
||||||
|
this.totalPrice,
|
||||||
|
this.vat});
|
||||||
|
|
||||||
|
ServicePrice.fromJson(dynamic json) {
|
||||||
|
currency = json["Currency"];
|
||||||
|
maxPrice = json["MaxPrice"];
|
||||||
|
maxTotalPrice = json["MaxTotalPrice"];
|
||||||
|
maxVAT = json["MaxVAT"];
|
||||||
|
minPrice = json["MinPrice"];
|
||||||
|
minTotalPrice = json["MinTotalPrice"];
|
||||||
|
minVAT = json["MinVAT"];
|
||||||
|
price = json["Price"];
|
||||||
|
totalPrice = json["TotalPrice"];
|
||||||
|
vat = json["VAT"];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
var map = <String, dynamic>{};
|
||||||
|
map["Currency"] = currency;
|
||||||
|
map["MaxPrice"] = maxPrice;
|
||||||
|
map["MaxTotalPrice"] = maxTotalPrice;
|
||||||
|
map["MaxVAT"] = maxVAT;
|
||||||
|
map["MinPrice"] = minPrice;
|
||||||
|
map["MinTotalPrice"] = minTotalPrice;
|
||||||
|
map["MinVAT"] = minVAT;
|
||||||
|
map["Price"] = price;
|
||||||
|
map["TotalPrice"] = totalPrice;
|
||||||
|
map["VAT"] = vat;
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
class CmcCreateServiceOrderReqModel {
|
||||||
|
int? recordID;
|
||||||
|
String? serviceID;
|
||||||
|
String? selectedServiceName;
|
||||||
|
String? selectedServiceNameAR;
|
||||||
|
dynamic price;
|
||||||
|
dynamic vAT;
|
||||||
|
dynamic totalPrice;
|
||||||
|
|
||||||
|
CmcCreateServiceOrderReqModel({
|
||||||
|
this.recordID,
|
||||||
|
this.serviceID,
|
||||||
|
this.selectedServiceName,
|
||||||
|
this.selectedServiceNameAR,
|
||||||
|
this.price,
|
||||||
|
this.vAT,
|
||||||
|
this.totalPrice,
|
||||||
|
});
|
||||||
|
|
||||||
|
CmcCreateServiceOrderReqModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
recordID = json['RecordID'];
|
||||||
|
serviceID = json['ServiceID'];
|
||||||
|
selectedServiceName = json['selectedServiceName'];
|
||||||
|
selectedServiceNameAR = json['selectedServiceNameAR'];
|
||||||
|
price = json['Price'];
|
||||||
|
vAT = json['VAT'];
|
||||||
|
totalPrice = json['TotalPrice'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['RecordID'] = recordID;
|
||||||
|
data['ServiceID'] = serviceID;
|
||||||
|
data['selectedServiceName'] = selectedServiceName;
|
||||||
|
data['selectedServiceNameAR'] = selectedServiceNameAR;
|
||||||
|
data['Price'] = price;
|
||||||
|
data['VAT'] = vAT;
|
||||||
|
data['TotalPrice'] = totalPrice;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,515 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
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/route_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/hmg_services/hmg_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/cmc_create_new_order_req_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_ui_selection_helper.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/loader/bottomsheet_loader.dart';
|
||||||
|
import 'package:maps_launcher/maps_launcher.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class CmcSelectionReviewPage extends StatefulWidget {
|
||||||
|
final GetCMCServicesResponseModel selectedService;
|
||||||
|
final HospitalsModel? preSelectedHospital;
|
||||||
|
|
||||||
|
const CmcSelectionReviewPage({super.key, required this.selectedService, this.preSelectedHospital});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CmcSelectionReviewPage> createState() => _CmcSelectionReviewPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CmcSelectionReviewPageState extends State<CmcSelectionReviewPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
// Initialize ViewModel state with preselected hospital if provided
|
||||||
|
if (widget.preSelectedHospital != null) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
hmgServicesViewModel.setSelectedHospitalForOrder(widget.preSelectedHospital);
|
||||||
|
hmgServicesViewModel.setSelectedServiceForOrder(widget.selectedService);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appState = getIt.get<AppState>();
|
||||||
|
final isArabic = appState.isArabic();
|
||||||
|
|
||||||
|
return CollapsingListView(
|
||||||
|
title: "Summary".needTranslation,
|
||||||
|
bottomChild: _buildBottomButton(),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildOrderSummaryCard(isArabic),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
_buildSelectedServiceCard(isArabic),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
_buildPaymentSummary(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildOrderSummaryCard(bool isArabic) {
|
||||||
|
return Consumer<HmgServicesViewModel>(
|
||||||
|
builder: (context, hmgServicesViewModel, child) {
|
||||||
|
final selectedHospital = hmgServicesViewModel.selectedHospitalForOrder;
|
||||||
|
final isLocationSelected = selectedHospital != null;
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 16.r,
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Select Hospital".needTranslation,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.f,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.blackColor,
|
||||||
|
letterSpacing: -0.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 12.h),
|
||||||
|
_buildHospitalSelector(isArabic, selectedHospital, isLocationSelected),
|
||||||
|
if (isLocationSelected) ...[
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
_buildHospitalMap(selectedHospital),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHospitalSelector(bool isArabic, HospitalsModel? selectedHospital, bool isLocationSelected) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: _showHospitalSelectionBottomSheet,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 14.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.bgScaffoldColor,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppColors.greyColor.withAlpha(51),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
isLocationSelected && selectedHospital != null
|
||||||
|
? (isArabic ? (selectedHospital.nameN ?? selectedHospital.name ?? '') : (selectedHospital.name ?? ''))
|
||||||
|
: "Select Hospital".needTranslation,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.f,
|
||||||
|
fontWeight: isLocationSelected ? FontWeight.w600 : FontWeight.w400,
|
||||||
|
color: isLocationSelected ? AppColors.blackColor : AppColors.greyTextColor,
|
||||||
|
letterSpacing: -0.4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Icon(
|
||||||
|
Icons.keyboard_arrow_down,
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
size: 24.h,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHospitalMap(HospitalsModel selectedHospital) {
|
||||||
|
final String lat = selectedHospital.latitude ?? "0.0";
|
||||||
|
final String lng = selectedHospital.longitude ?? "0.0";
|
||||||
|
|
||||||
|
log("selectedHospital: $lng and $lat");
|
||||||
|
|
||||||
|
if (lat == "0.0" || lng == "0.0") return SizedBox.shrink();
|
||||||
|
|
||||||
|
final String staticMapUrl =
|
||||||
|
"https://maps.googleapis.com/maps/api/staticmap?center=$lat,$lng&zoom=16&size=600x300&maptype=roadmap&markers=color:red%7C$lat,$lng&key=AIzaSyCyDbWUM9d_sBUGIE8PcuShzPaqO08NSC8";
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
child: Image.network(
|
||||||
|
staticMapUrl,
|
||||||
|
height: 200.h,
|
||||||
|
width: double.infinity,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
loadingBuilder: (context, child, loadingProgress) {
|
||||||
|
if (loadingProgress == null) return child;
|
||||||
|
return Container(
|
||||||
|
height: 200.h,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.bgScaffoldColor,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: AppColors.primaryRedColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
return Container(
|
||||||
|
height: 200.h,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.bgScaffoldColor,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
size: 48.h,
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 12.h,
|
||||||
|
right: 12.w,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () => _launchDirections(selectedHospital),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: BorderRadius.circular(1000.r),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromARGB(26, 0, 0, 0),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.directions_icon,
|
||||||
|
width: 16.w,
|
||||||
|
height: 16.h,
|
||||||
|
),
|
||||||
|
SizedBox(width: 6.w),
|
||||||
|
Text(
|
||||||
|
"Get Directions".needTranslation,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.f,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.blackColor,
|
||||||
|
letterSpacing: -0.4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSelectedServiceCard(bool isArabic) {
|
||||||
|
final serviceName = isArabic ? (widget.selectedService.textN ?? widget.selectedService.text ?? '') : (widget.selectedService.text ?? '');
|
||||||
|
final price = widget.selectedService.priceTotal ?? 0.0;
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 16.r,
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Selected Service".needTranslation.toText14(
|
||||||
|
weight: FontWeight.w600,
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
letterSpacing: -0.4,
|
||||||
|
),
|
||||||
|
SizedBox(height: 6.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: serviceName.toText16(weight: FontWeight.w700, color: AppColors.blackColor, letterSpacing: -0.5)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPaymentSummary() {
|
||||||
|
// Use selected service from widget
|
||||||
|
final service = widget.selectedService;
|
||||||
|
|
||||||
|
log("service: ${service.toJson()}");
|
||||||
|
|
||||||
|
final double amountBeforeTax = service.price ?? 0.0;
|
||||||
|
final double taxAmount = service.priceVAT ?? 0.0;
|
||||||
|
final double totalAmount = service.priceTotal ?? (amountBeforeTax + taxAmount);
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Consumer<PayfortViewModel>(builder: (context, payfortVM, child) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
"Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
|
||||||
|
SizedBox(height: 17.h),
|
||||||
|
|
||||||
|
// Amount before tax
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"Amount before tax".needTranslation.toText14(isBold: true),
|
||||||
|
Utils.getPaymentAmountWithSymbol(
|
||||||
|
amountBeforeTax.toString().toText16(isBold: true),
|
||||||
|
AppColors.blackColor,
|
||||||
|
13,
|
||||||
|
isSaudiCurrency: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
|
||||||
|
// VAT (use label VAT 15% if desired)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor),
|
||||||
|
Utils.getPaymentAmountWithSymbol(
|
||||||
|
taxAmount.toString().toText14(isBold: true, color: AppColors.greyTextColor),
|
||||||
|
AppColors.greyTextColor,
|
||||||
|
13,
|
||||||
|
isSaudiCurrency: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
SizedBox(height: 17.h),
|
||||||
|
// Total Amount
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
"".needTranslation.toText14(isBold: true),
|
||||||
|
Utils.getPaymentAmountWithSymbol(
|
||||||
|
totalAmount.toString().toText24(isBold: true),
|
||||||
|
AppColors.blackColor,
|
||||||
|
17,
|
||||||
|
isSaudiCurrency: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBottomButton() {
|
||||||
|
return Consumer<HmgServicesViewModel>(
|
||||||
|
builder: (context, hmgServicesViewModel, child) {
|
||||||
|
final isLocationSelected = hmgServicesViewModel.selectedHospitalForOrder != null;
|
||||||
|
|
||||||
|
return SafeArea(
|
||||||
|
top: false,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromARGB(13, 0, 0, 0),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, -2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: CustomButton(
|
||||||
|
text: "Confirm".needTranslation,
|
||||||
|
onPressed: () {
|
||||||
|
isLocationSelected ? _handleConfirm() : null;
|
||||||
|
},
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
backgroundColor: isLocationSelected ? AppColors.successColor : AppColors.greyColor,
|
||||||
|
borderRadius: 12.r,
|
||||||
|
borderColor: Colors.transparent,
|
||||||
|
borderWidth: 0,
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 14.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showHospitalSelectionBottomSheet() {
|
||||||
|
CmcUiSelectionHelper.showHospitalSelectionBottomSheet(context: context, onHospitalSelected: (hospital) => context.pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _launchDirections(HospitalsModel selectedHospital) {
|
||||||
|
final double lat = double.parse(selectedHospital.latitude ?? "0.0");
|
||||||
|
final double lng = double.parse(selectedHospital.longitude ?? "0.0");
|
||||||
|
|
||||||
|
if (lat != 0.0 && lng != 0.0) {
|
||||||
|
MapsLauncher.launchCoordinates(
|
||||||
|
lat,
|
||||||
|
lng,
|
||||||
|
selectedHospital.name ?? "Hospital",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showSuccessBottomSheet(int requestId, HmgServicesViewModel hmgServicesViewModel) {
|
||||||
|
return showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Utils.getSuccessWidget(loadingText: "Your request has been successfully submitted.".needTranslation),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
"Here is your request #: ".needTranslation.toText14(
|
||||||
|
color: AppColors.textColorLight,
|
||||||
|
weight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
SizedBox(width: 4.w),
|
||||||
|
("$requestId").toText16(isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
height: 56.h,
|
||||||
|
text: LocaleKeys.ok.tr(),
|
||||||
|
onPressed: () {
|
||||||
|
context.pop();
|
||||||
|
context.pop();
|
||||||
|
hmgServicesViewModel.getAllCmcOrders();
|
||||||
|
},
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isCloseButtonVisible: false,
|
||||||
|
isDismissible: false,
|
||||||
|
isFullScreen: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleConfirm() {
|
||||||
|
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
final selectedHospital = hmgServicesViewModel.selectedHospitalForOrder;
|
||||||
|
|
||||||
|
if (selectedHospital == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text("Please select a hospital to continue".needTranslation),
|
||||||
|
backgroundColor: AppColors.errorColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final selectedService = widget.selectedService;
|
||||||
|
return showCommonBottomSheetWithoutHeight(
|
||||||
|
title: LocaleKeys.notice.tr(context: context),
|
||||||
|
context,
|
||||||
|
child: Utils.getWarningWidget(
|
||||||
|
loadingText: "Are you sure you want to submit this request?".needTranslation,
|
||||||
|
isShowActionButtons: true,
|
||||||
|
onCancelTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
onConfirmTap: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
LoaderBottomSheet.showLoader();
|
||||||
|
|
||||||
|
// Create the services list
|
||||||
|
final servicesList = [
|
||||||
|
PatientERCMCInsertServicesList(
|
||||||
|
recordID: selectedService.iD,
|
||||||
|
serviceID: selectedService.serviceID,
|
||||||
|
selectedServiceName: selectedService.text,
|
||||||
|
selectedServiceNameAR: selectedService.textN,
|
||||||
|
price: selectedService.price,
|
||||||
|
vAT: selectedService.priceVAT,
|
||||||
|
totalPrice: selectedService.priceTotal,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
await hmgServicesViewModel.addCmcOrder(
|
||||||
|
projectID: selectedHospital.mainProjectID ?? 0,
|
||||||
|
orderServiceID: selectedService.orderServiceID ?? 3,
|
||||||
|
services: servicesList,
|
||||||
|
onSuccess: (requestId) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showSuccessBottomSheet(requestId, hmgServicesViewModel);
|
||||||
|
},
|
||||||
|
onError: (err) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
// showCommonBottomSheetWithoutHeight(context, child: Utils.getErrorWidget(loadingText: err), callBackFunc: () {});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,195 +0,0 @@
|
|||||||
// import 'package:hmg_patient_app/core/enum/viewstate.dart';
|
|
||||||
// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/ComprehensiveMedicalCheckup/cmc_insert_pres_order_request_model.dart';
|
|
||||||
// import 'package:hmg_patient_app/core/viewModels/AlHabibMedicalService/cmc_view_model.dart';
|
|
||||||
// import 'package:hmg_patient_app/core/viewModels/project_view_model.dart';
|
|
||||||
// import 'package:hmg_patient_app/pages/AlHabibMedicalService/ComprehensiveMedicalCheckup/NewCMC/new_cmc_step_three_page.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/translations_delegate_base.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/utils.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/utils_new.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/buttons/defaultButton.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/dragable_sheet.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/photo_view_page.dart';
|
|
||||||
// import 'package:flutter/cupertino.dart';
|
|
||||||
// import 'package:flutter/material.dart';
|
|
||||||
// import 'package:flutter_svg/svg.dart';
|
|
||||||
// import 'package:provider/provider.dart';
|
|
||||||
//
|
|
||||||
// import 'new_cmc_step_tow_page.dart';
|
|
||||||
//
|
|
||||||
// class NewCMCStepOnePage extends StatefulWidget {
|
|
||||||
// final CMCInsertPresOrderRequestModel cMCInsertPresOrderRequestModel;
|
|
||||||
// final Function changePageViewIndex;
|
|
||||||
// final CMCViewModel model;
|
|
||||||
//
|
|
||||||
// final double latitude;
|
|
||||||
// final double longitude;
|
|
||||||
//
|
|
||||||
// const NewCMCStepOnePage({Key? key, required this.cMCInsertPresOrderRequestModel, required this.model, required this.changePageViewIndex, required this.latitude, required this.longitude})
|
|
||||||
// : super(key: key);
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// _NewCMCStepOnePageState createState() => _NewCMCStepOnePageState();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// class _NewCMCStepOnePageState extends State<NewCMCStepOnePage> {
|
|
||||||
// int selectedItem = 0;
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// void initState() {
|
|
||||||
// super.initState();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// Widget build(BuildContext context) {
|
|
||||||
// ProjectViewModel projectViewModel = Provider.of(context);
|
|
||||||
//
|
|
||||||
// return AppScaffold(
|
|
||||||
// isShowAppBar: false,
|
|
||||||
// baseViewModel: widget.model,
|
|
||||||
// body: Column(
|
|
||||||
// children: [
|
|
||||||
// Expanded(
|
|
||||||
// child: SingleChildScrollView(
|
|
||||||
// physics: BouncingScrollPhysics(),
|
|
||||||
// padding: EdgeInsets.all(21),
|
|
||||||
// child: Column(
|
|
||||||
// children: [
|
|
||||||
// ListView.separated(
|
|
||||||
// physics: NeverScrollableScrollPhysics(),
|
|
||||||
// shrinkWrap: true,
|
|
||||||
// itemBuilder: (context, index) {
|
|
||||||
// return Row(
|
|
||||||
// children: [
|
|
||||||
// Radio(
|
|
||||||
// value: num.tryParse(widget.model.cmcAllServicesList[index].serviceID!),
|
|
||||||
// activeColor: Colors.red[800],
|
|
||||||
// onChanged: (newValue) async {
|
|
||||||
// selectedItem = index;
|
|
||||||
// PatientERCMCInsertServicesList patientERCMCInsertServicesList = PatientERCMCInsertServicesList(
|
|
||||||
// price: widget.model.cmcAllServicesList[index].price,
|
|
||||||
// serviceID: widget.model.cmcAllServicesList[index].serviceID,
|
|
||||||
// selectedServiceName: widget.model.cmcAllServicesList[index].text,
|
|
||||||
// selectedServiceNameAR: widget.model.cmcAllServicesList[index].textN,
|
|
||||||
// recordID: 1,
|
|
||||||
// totalPrice: widget.model.cmcAllServicesList[index].priceTotal,
|
|
||||||
// vAT: widget.model.cmcAllServicesList[index].priceVAT);
|
|
||||||
// setState(() {
|
|
||||||
// widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList = [patientERCMCInsertServicesList];
|
|
||||||
// });
|
|
||||||
// // CMCGetItemsRequestModel cMCGetItemsRequestModel = new CMCGetItemsRequestModel(checkupType: newValue);
|
|
||||||
// // await widget.model.getCheckupItems(cMCGetItemsRequestModel: cMCGetItemsRequestModel);
|
|
||||||
// },
|
|
||||||
// groupValue: widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList!.length > 0
|
|
||||||
// ? int.parse(widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList![0].serviceID!)
|
|
||||||
// : 1),
|
|
||||||
// Expanded(
|
|
||||||
// child: Padding(
|
|
||||||
// padding: const EdgeInsets.only(
|
|
||||||
// left: 10,
|
|
||||||
// right: 10,
|
|
||||||
// top: 20,
|
|
||||||
// bottom: 20,
|
|
||||||
// ),
|
|
||||||
// child: Text(
|
|
||||||
// projectViewModel.isArabic ? widget.model.cmcAllServicesList[index].textN! : widget.model.cmcAllServicesList[index].text!,
|
|
||||||
// style: TextStyle(
|
|
||||||
// fontSize: 14,
|
|
||||||
// fontWeight: FontWeight.w600,
|
|
||||||
// letterSpacing: -0.45,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// separatorBuilder: (context, index) {
|
|
||||||
// return mDivider(Colors.grey);
|
|
||||||
// },
|
|
||||||
// itemCount: widget.model.cmcAllServicesList.length),
|
|
||||||
// Stack(
|
|
||||||
// children: [
|
|
||||||
// Image.asset(
|
|
||||||
// projectViewModel.isArabic ? "assets/images/cc_ar.png" : "assets/images/cc_en.png",
|
|
||||||
// width: double.infinity,
|
|
||||||
// ),
|
|
||||||
// Align(
|
|
||||||
// alignment: Alignment.topRight,
|
|
||||||
// child: Container(
|
|
||||||
// decoration: containerColorRadiusBorder(
|
|
||||||
// Colors.black.withOpacity(0.2),
|
|
||||||
// 1000,
|
|
||||||
// Colors.white,
|
|
||||||
// ),
|
|
||||||
// margin: EdgeInsets.all(12),
|
|
||||||
// child: IconButton(
|
|
||||||
// icon: SvgPicture.asset(
|
|
||||||
// "assets/images/new/ic_zoom.svg",
|
|
||||||
// color: Colors.white,
|
|
||||||
// ),
|
|
||||||
// padding: EdgeInsets.all(12),
|
|
||||||
// onPressed: () {
|
|
||||||
// showDraggableDialog(context, PhotoViewPage(projectViewModel.isArabic ? "assets/images/cc_ar.png" : "assets/images/cc_en.png"));
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Container(
|
|
||||||
// color: Colors.white,
|
|
||||||
// padding: EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21),
|
|
||||||
// child: DefaultButton(
|
|
||||||
// TranslationBase.of(context).next,
|
|
||||||
// () async {
|
|
||||||
// if (widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList!.length != 0 || widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList == null) {
|
|
||||||
// // int index = widget.model.cmcAllServicesList.length;
|
|
||||||
// PatientERCMCInsertServicesList patientERCMCInsertServicesList = new PatientERCMCInsertServicesList(
|
|
||||||
// price: widget.model.cmcAllServicesList[selectedItem].price,
|
|
||||||
// serviceID: widget.model.cmcAllServicesList[selectedItem].serviceID.toString(),
|
|
||||||
// selectedServiceName: widget.model.cmcAllServicesList[selectedItem].text,
|
|
||||||
// selectedServiceNameAR: widget.model.cmcAllServicesList[selectedItem].textN,
|
|
||||||
// recordID: 1,
|
|
||||||
// totalPrice: widget.model.cmcAllServicesList[selectedItem].priceTotal,
|
|
||||||
// vAT: widget.model.cmcAllServicesList[selectedItem].priceVAT,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// widget.cMCInsertPresOrderRequestModel.patientID = projectViewModel.user!.patientID;
|
|
||||||
// widget.cMCInsertPresOrderRequestModel.patientOutSA = projectViewModel.user!.outSA;
|
|
||||||
//
|
|
||||||
// widget.cMCInsertPresOrderRequestModel.patientERCMCInsertServicesList = [patientERCMCInsertServicesList];
|
|
||||||
// navigateTo(
|
|
||||||
// context,
|
|
||||||
// NewCMCStepThreePage(
|
|
||||||
// cmcInsertPresOrderRequestModel: widget.cMCInsertPresOrderRequestModel,
|
|
||||||
// model: widget.model,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// // await widget.model.getCustomerInfo();
|
|
||||||
// if (widget.model.state == ViewState.ErrorLocal) {
|
|
||||||
// Utils.showErrorToast();
|
|
||||||
// } else {
|
|
||||||
// // navigateTo(
|
|
||||||
// // context,
|
|
||||||
// // NewCMCStepTowPage(
|
|
||||||
// // longitude: widget.longitude,
|
|
||||||
// // latitude: widget.latitude,
|
|
||||||
// // cmcInsertPresOrderRequestModel: widget.cMCInsertPresOrderRequestModel,
|
|
||||||
// // model: widget.model,
|
|
||||||
// // ),
|
|
||||||
// // );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@ -1,183 +0,0 @@
|
|||||||
// import 'package:hmg_patient_app/core/enum/viewstate.dart';
|
|
||||||
// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/ComprehensiveMedicalCheckup/GetCMCAllOrdersResponseModel.dart';
|
|
||||||
// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/HomeHealthCare/get_hhc_all_pres_orders_response_model.dart';
|
|
||||||
// import 'package:hmg_patient_app/core/model/AlHabibMedicalService/HomeHealthCare/update_pres_oreder_request_model.dart';
|
|
||||||
// import 'package:hmg_patient_app/core/viewModels/AlHabibMedicalService/cmc_view_model.dart';
|
|
||||||
// import 'package:hmg_patient_app/core/viewModels/project_view_model.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/app_toast.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/date_uitl.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/gif_loader_dialog_utils.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/translations_delegate_base.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/utils.dart';
|
|
||||||
// import 'package:hmg_patient_app/uitl/utils_new.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/buttons/defaultButton.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/buttons/secondary_button.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/data_display/text.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/dialogs/ConfirmWithMessageDialog.dart';
|
|
||||||
// import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart';
|
|
||||||
// import 'package:flutter/material.dart';
|
|
||||||
// import 'package:provider/provider.dart';
|
|
||||||
//
|
|
||||||
// import 'Dialog/confirm_cancel_order_dialog.dart';
|
|
||||||
//
|
|
||||||
// class OrdersLogDetailsPage extends StatelessWidget {
|
|
||||||
// final CMCViewModel model;
|
|
||||||
//
|
|
||||||
// const OrdersLogDetailsPage({Key ?key, required this.model}) : super(key: key);
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// Widget build(BuildContext context) {
|
|
||||||
// ProjectViewModel projectViewModel = Provider.of(context);
|
|
||||||
//
|
|
||||||
// void showConfirmMessage(CMCViewModel model, GetCMCAllOrdersResponseModel order) {
|
|
||||||
// showDialog(
|
|
||||||
// context: context,
|
|
||||||
// builder: (cxt) => ConfirmWithMessageDialog(
|
|
||||||
// message: TranslationBase.of(context).cancelOrderMsg,
|
|
||||||
// onTap: () {
|
|
||||||
// UpdatePresOrderRequestModel updatePresOrderRequestModel = UpdatePresOrderRequestModel(presOrderID: order.iD, rejectionReason: "", presOrderStatus: 4, editedBy: 3);
|
|
||||||
// Future.delayed(new Duration(milliseconds: 300)).then((value) async {
|
|
||||||
// GifLoaderDialogUtils.showMyDialog(context);
|
|
||||||
// await model.updateCmcPresOrder(updatePresOrderRequestModel);
|
|
||||||
// if (model.state == ViewState.ErrorLocal) {
|
|
||||||
// Utils.showErrorToast(model.error);
|
|
||||||
// GifLoaderDialogUtils.hideDialog(context);
|
|
||||||
// } else {
|
|
||||||
// AppToast.showSuccessToast(message: TranslationBase.of(context).processDoneSuccessfully);
|
|
||||||
// await model.getCmcAllPresOrders();
|
|
||||||
// GifLoaderDialogUtils.hideDialog(context);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// ));
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return AppScaffold(
|
|
||||||
// isShowAppBar: false,
|
|
||||||
// baseViewModel: model,
|
|
||||||
// body: model.cmcAllPresOrders.length > 0 ? ListView.separated(
|
|
||||||
// padding: EdgeInsets.all(21),
|
|
||||||
// physics: BouncingScrollPhysics(),
|
|
||||||
// itemBuilder: (context, index) {
|
|
||||||
// GetCMCAllOrdersResponseModel order = model.cmcAllPresOrders.reversed.toList()[index];
|
|
||||||
//
|
|
||||||
// int status = order.statusId!;
|
|
||||||
// String _statusDisp = order.statusText!;
|
|
||||||
// late Color _color;
|
|
||||||
// if (status == 1) {
|
|
||||||
// //pending
|
|
||||||
// _color = Color(0xffCC9B14);
|
|
||||||
// } else if (status == 2) {
|
|
||||||
// //processing
|
|
||||||
// _color = Color(0xff2E303A);
|
|
||||||
// } else if (status == 3) {
|
|
||||||
// //completed
|
|
||||||
// _color = Color(0xff359846);
|
|
||||||
// } else if (status == 4 || status == 6 || status == 7) {
|
|
||||||
// //cancel // Rejected
|
|
||||||
// _color = Color(0xffD02127);
|
|
||||||
// }
|
|
||||||
// return Container(
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: _color,
|
|
||||||
// borderRadius: BorderRadius.all(
|
|
||||||
// Radius.circular(10.0),
|
|
||||||
// ),
|
|
||||||
// boxShadow: [
|
|
||||||
// BoxShadow(
|
|
||||||
// color: Color(0xff000000).withOpacity(.05),
|
|
||||||
// blurRadius: 27,
|
|
||||||
// offset: Offset(0, -3),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// child: Container(
|
|
||||||
// margin: EdgeInsets.only(left: projectViewModel.isArabic ? 0 : 6, right: projectViewModel.isArabic ? 6 : 0),
|
|
||||||
// padding: EdgeInsets.symmetric(vertical: 14, horizontal: 12),
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: Colors.white,
|
|
||||||
// border: Border.all(color: Colors.white, width: 1),
|
|
||||||
// borderRadius: BorderRadius.only(
|
|
||||||
// bottomRight: projectViewModel.isArabic ? Radius.circular(0) : Radius.circular(10.0),
|
|
||||||
// topRight: projectViewModel.isArabic ? Radius.circular(0) : Radius.circular(10.0),
|
|
||||||
// bottomLeft: projectViewModel.isArabic ? Radius.circular(10.0) : Radius.circular(0),
|
|
||||||
// topLeft: projectViewModel.isArabic ? Radius.circular(10.0) : Radius.circular(0),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// // clipBehavior: Clip.antiAlias,
|
|
||||||
// child: Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Expanded(
|
|
||||||
// child: Column(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Text(
|
|
||||||
// _statusDisp,
|
|
||||||
// style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: _color, letterSpacing: -0.4, height: 16 / 10),
|
|
||||||
// ),
|
|
||||||
// SizedBox(height: 6),
|
|
||||||
// Text(
|
|
||||||
// '${TranslationBase.of(context).requestID}: ${order.iD}',
|
|
||||||
// style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2E303A), letterSpacing: -0.64, height: 25 / 16),
|
|
||||||
// ),
|
|
||||||
// Row(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// Text(
|
|
||||||
// TranslationBase.of(context).hospital + ": ",
|
|
||||||
// style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xff575757), letterSpacing: -0.4, height: 16 / 10),
|
|
||||||
// ),
|
|
||||||
// Expanded(
|
|
||||||
// child: Text(
|
|
||||||
// // !projectViewModel.isArabic ? order.nearestProjectDescription.trim().toString() : order.nearestProjectDescriptionN.toString(),
|
|
||||||
// order.projectName != null ? order.projectName!.trim().toString() : "",
|
|
||||||
// style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.56),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// )
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Column(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
// children: [
|
|
||||||
// Text(
|
|
||||||
// DateUtil.getDayMonthYearDateFormatted(DateTime.tryParse(order.created!)!),
|
|
||||||
// style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.4, height: 16 / 10),
|
|
||||||
// ),
|
|
||||||
// SizedBox(height: 12),
|
|
||||||
// if (order.statusId == 1 || order.statusId == 2)
|
|
||||||
// InkWell(
|
|
||||||
// onTap: () {
|
|
||||||
// showConfirmMessage(model, order);
|
|
||||||
// },
|
|
||||||
// child: Container(
|
|
||||||
// padding: EdgeInsets.symmetric(vertical: 8, horizontal: 14),
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: Color(0xffD02127),
|
|
||||||
// border: Border.all(color: Colors.white, width: 1),
|
|
||||||
// borderRadius: BorderRadius.circular(10),
|
|
||||||
// ),
|
|
||||||
// child: Text(
|
|
||||||
// TranslationBase.of(context).cancel_nocaps,
|
|
||||||
// style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Colors.white, letterSpacing: -0.4),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// separatorBuilder: (context, index) => SizedBox(height: 12),
|
|
||||||
// itemCount: model.cmcAllPresOrders.length) : getNoDataWidget(context),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@ -0,0 +1,111 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.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/enums.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||||
|
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_hospital_list_item.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shimmer/shimmer.dart';
|
||||||
|
|
||||||
|
class CmcHospitalBottomSheetBody extends StatelessWidget {
|
||||||
|
final Function(HospitalsModel) onHospitalSelected;
|
||||||
|
|
||||||
|
const CmcHospitalBottomSheetBody({super.key, required this.onHospitalSelected});
|
||||||
|
|
||||||
|
Widget _buildLoadingShimmer() {
|
||||||
|
return ListView.separated(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: 4,
|
||||||
|
separatorBuilder: (_, __) => SizedBox(height: 12.h),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Shimmer.fromColors(
|
||||||
|
baseColor: Colors.grey[300]!,
|
||||||
|
highlightColor: Colors.grey[100]!,
|
||||||
|
child: Container(
|
||||||
|
height: 80.h,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appState = getIt.get<AppState>();
|
||||||
|
final bool isArabic = appState.isArabic();
|
||||||
|
final bool isLocationEnabled = (appState.userLat != 0) && (appState.userLong != 0);
|
||||||
|
|
||||||
|
return Consumer(
|
||||||
|
builder: (BuildContext context, HmgServicesViewModel hmgServicesViewModel, Widget? child) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Choose your preferred hospital for the service".needTranslation.toText14(
|
||||||
|
weight: FontWeight.w400,
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
letterSpacing: -0.4,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
TextInputWidget(
|
||||||
|
labelText: LocaleKeys.search.tr(),
|
||||||
|
hintText: LocaleKeys.searchHospital.tr(),
|
||||||
|
onChange: (value) {
|
||||||
|
hmgServicesViewModel.filterHospitalsByString(value ?? '', isArabic);
|
||||||
|
},
|
||||||
|
isEnable: true,
|
||||||
|
prefix: null,
|
||||||
|
autoFocus: false,
|
||||||
|
isBorderAllowed: false,
|
||||||
|
keyboardType: TextInputType.text,
|
||||||
|
isAllowLeadingIcon: true,
|
||||||
|
selectionType: SelectionTypeEnum.search,
|
||||||
|
padding: EdgeInsets.symmetric(vertical: ResponsiveExtension(10).h, horizontal: ResponsiveExtension(15).h),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
SizedBox(
|
||||||
|
height: MediaQuery.of(context).size.height * 0.4,
|
||||||
|
child: hmgServicesViewModel.isHospitalListLoading
|
||||||
|
? _buildLoadingShimmer()
|
||||||
|
: hmgServicesViewModel.filteredHospitalsList.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: "No hospitals Found".needTranslation.toText16(weight: FontWeight.w500, color: AppColors.greyTextColor),
|
||||||
|
)
|
||||||
|
: ListView.separated(
|
||||||
|
itemCount: hmgServicesViewModel.filteredHospitalsList.length,
|
||||||
|
separatorBuilder: (context, index) => SizedBox(height: 12.h),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final hospital = hmgServicesViewModel.filteredHospitalsList[index];
|
||||||
|
return CmcHospitalListItem(
|
||||||
|
hospital: hospital,
|
||||||
|
isLocationEnabled: isLocationEnabled,
|
||||||
|
onPress: () {
|
||||||
|
hmgServicesViewModel.setSelectedHospital(hospital);
|
||||||
|
onHospitalSelected(hospital);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
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/my_appointments/models/resp_models/hospital_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
|
||||||
|
|
||||||
|
class CmcHospitalListItem extends StatelessWidget {
|
||||||
|
final HospitalsModel hospital;
|
||||||
|
final VoidCallback onPress;
|
||||||
|
final bool isLocationEnabled;
|
||||||
|
|
||||||
|
const CmcHospitalListItem({
|
||||||
|
super.key,
|
||||||
|
required this.hospital,
|
||||||
|
required this.onPress,
|
||||||
|
this.isLocationEnabled = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appState = getIt.get<AppState>();
|
||||||
|
final bool isArabic = appState.isArabic();
|
||||||
|
final String hospitalName = isArabic ? (hospital.nameN ?? hospital.name ?? '') : (hospital.name ?? '');
|
||||||
|
|
||||||
|
return InkWell(
|
||||||
|
onTap: onPress,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.h,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 8.h,
|
||||||
|
children: [
|
||||||
|
_buildHospitalName(hospitalName),
|
||||||
|
_buildDistanceInfo(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Transform.flip(
|
||||||
|
flipX: isArabic,
|
||||||
|
child: Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.forward_arrow_icon_small,
|
||||||
|
iconColor: AppColors.blackColor,
|
||||||
|
width: 18.h,
|
||||||
|
height: 13.h,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(16.h, 16.h),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHospitalName(String hospitalName) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Utils.buildSvgWithAssets(
|
||||||
|
icon: (hospital.isHMC == true) ? AppAssets.hmc : AppAssets.hmg,
|
||||||
|
).paddingOnly(right: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
hospitalName,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16,
|
||||||
|
color: AppColors.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDistanceInfo() {
|
||||||
|
log("hospital: ${hospital.distanceInKilometers}");
|
||||||
|
final distanceText = hospital.distanceInKilometers != null ? hospital.distanceInKilometers!.toStringAsFixed(1) : "0";
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
spacing: 4.w,
|
||||||
|
children: [
|
||||||
|
Visibility(
|
||||||
|
visible: (hospital.distanceInKilometers != null && hospital.distanceInKilometers! > 0),
|
||||||
|
child: AppCustomChipWidget(
|
||||||
|
labelText: "$distanceText km".needTranslation,
|
||||||
|
icon: AppAssets.location_red,
|
||||||
|
iconColor: AppColors.errorColor,
|
||||||
|
backgroundColor: AppColors.secondaryLightRedColor,
|
||||||
|
textColor: AppColors.errorColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Visibility(
|
||||||
|
visible: (hospital.distanceInKilometers == null || hospital.distanceInKilometers == 0),
|
||||||
|
child: AppCustomChipWidget(
|
||||||
|
labelText: " Distance not available".needTranslation,
|
||||||
|
textColor: AppColors.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Visibility(
|
||||||
|
// visible: !isLocationEnabled,
|
||||||
|
// child: AppCustomChipWidget(
|
||||||
|
// labelText: "Location turned off".needTranslation,
|
||||||
|
// deleteIcon: AppAssets.location_unavailable,
|
||||||
|
// deleteIconSize: Size(9.w, 12.h),
|
||||||
|
// textColor: AppColors.blackColor,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/widgets/cmc_hospital_bottom_sheet_body.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.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/route_extensions.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/order_update_req_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.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/loader/bottomsheet_loader.dart';
|
||||||
|
|
||||||
|
class CmcUiSelectionHelper {
|
||||||
|
static void showHospitalSelectionBottomSheet({
|
||||||
|
required BuildContext context,
|
||||||
|
required Function(dynamic) onHospitalSelected,
|
||||||
|
}) {
|
||||||
|
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
title: "Select Hospital".needTranslation,
|
||||||
|
child: CmcHospitalBottomSheetBody(
|
||||||
|
onHospitalSelected: (hospital) {
|
||||||
|
hmgServicesViewModel.setSelectedHospitalForOrder(hospital);
|
||||||
|
onHospitalSelected(hospital);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showCancelConfirmationDialog({
|
||||||
|
required BuildContext context,
|
||||||
|
required GetCMCAllOrdersResponseModel order,
|
||||||
|
}) {
|
||||||
|
final HmgServicesViewModel hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
|
||||||
|
return showCommonBottomSheetWithoutHeight(
|
||||||
|
title: LocaleKeys.notice.tr(context: context),
|
||||||
|
context,
|
||||||
|
child: Utils.getWarningWidget(
|
||||||
|
loadingText: "Are you sure you want to cancel this order?".needTranslation,
|
||||||
|
isShowActionButtons: true,
|
||||||
|
onCancelTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
onConfirmTap: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
LoaderBottomSheet.showLoader();
|
||||||
|
|
||||||
|
final requestModel = OrderUpdateRequestModel(
|
||||||
|
presOrderID: order.iD,
|
||||||
|
rejectionReason: "Cancelled by user",
|
||||||
|
presOrderStatus: 4, // Cancelled status
|
||||||
|
editedBy: 3,
|
||||||
|
);
|
||||||
|
|
||||||
|
await hmgServicesViewModel.updateCmcPresOrder(
|
||||||
|
requestModel: requestModel,
|
||||||
|
onSuccess: (_) async {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Utils.getSuccessWidget(loadingText: "Order has been cancelled successfully".needTranslation),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
height: 56.h,
|
||||||
|
text: LocaleKeys.ok.tr(),
|
||||||
|
onPressed: () {
|
||||||
|
context.pop();
|
||||||
|
context.pop();
|
||||||
|
hmgServicesViewModel.getAllCmcOrders();
|
||||||
|
},
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isCloseButtonVisible: false,
|
||||||
|
isDismissible: false,
|
||||||
|
isFullScreen: false,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onError: (error) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,400 @@
|
|||||||
|
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/book_appointments/book_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/contact_us/models/feedback_type.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.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/contact_us/widgets/feedback_appointment_selection.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/custom_tab_bar.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/image_picker.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class FeedbackPage extends StatelessWidget {
|
||||||
|
FeedbackPage({super.key});
|
||||||
|
|
||||||
|
late ContactUsViewModel contactUsViewModel;
|
||||||
|
late MedicalFileViewModel medicalFileViewModel;
|
||||||
|
|
||||||
|
final TextEditingController subjectTextController = TextEditingController();
|
||||||
|
final TextEditingController messageTextController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
contactUsViewModel = Provider.of<ContactUsViewModel>(context, listen: false);
|
||||||
|
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.bgScaffoldColor,
|
||||||
|
body: Consumer<ContactUsViewModel>(builder: (context, contactUsVM, child) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CollapsingListView(
|
||||||
|
isLeading: Navigator.canPop(context),
|
||||||
|
title: LocaleKeys.feedback.tr(),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
CustomTabBar(
|
||||||
|
activeTextColor: AppColors.primaryRedColor,
|
||||||
|
activeBackgroundColor: AppColors.primaryRedColor.withValues(alpha: .1),
|
||||||
|
tabs: [
|
||||||
|
CustomTabBarModel(null, "Send".needTranslation),
|
||||||
|
CustomTabBarModel(null, "Status".needTranslation),
|
||||||
|
],
|
||||||
|
onTabChange: (index) {
|
||||||
|
contactUsViewModel.setIsSendFeedbackTabSelected(index == 0);
|
||||||
|
},
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
getSelectedTabWidget(context).paddingSymmetrical(24.h, 16.w),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
customBorder: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(24.h),
|
||||||
|
topRight: Radius.circular(24.h),
|
||||||
|
),
|
||||||
|
hasShadow: true,
|
||||||
|
),
|
||||||
|
child: CustomButton(
|
||||||
|
text: LocaleKeys.submit.tr(context: context),
|
||||||
|
onPressed: () async {
|
||||||
|
if (subjectTextController.text.isEmpty) {
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Utils.getErrorWidget(loadingText: LocaleKeys.emptySubject.tr(context: context)),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (messageTextController.text.isEmpty) {
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Utils.getErrorWidget(loadingText: LocaleKeys.emptyMessage.tr(context: context)),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoaderBottomSheet.showLoader(loadingText: "Sending Feedback...".needTranslation);
|
||||||
|
contactUsViewModel.insertCOCItem(
|
||||||
|
subject: subjectTextController.text,
|
||||||
|
message: messageTextController.text,
|
||||||
|
onSuccess: (val) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
subjectTextController.clear();
|
||||||
|
messageTextController.clear();
|
||||||
|
contactUsViewModel.setPatientFeedbackSelectedAppointment(null);
|
||||||
|
showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.success.tr(context: context)), callBackFunc: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: (err) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Utils.getSuccessWidget(loadingText: err),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
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.feedback,
|
||||||
|
iconColor: AppColors.whiteColor,
|
||||||
|
iconSize: 20.h,
|
||||||
|
).paddingSymmetrical(24.h, 24.h),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getSelectedTabWidget(BuildContext context) {
|
||||||
|
if (contactUsViewModel.isSendFeedbackTabSelected) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.likeToHear.tr().toText14(weight: FontWeight.w500),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 16.r,
|
||||||
|
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.ask_doctor_icon, width: 24.w, height: 24.h, iconColor: AppColors.greyTextColor),
|
||||||
|
SizedBox(width: 12.w),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
LocaleKeys.feedbackType.tr().toText16(color: AppColors.textColor, weight: FontWeight.w500),
|
||||||
|
(getIt.get<AppState>().isArabic() ? contactUsViewModel.selectedFeedbackType.nameAR : contactUsViewModel.selectedFeedbackType.nameEN)
|
||||||
|
.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h),
|
||||||
|
],
|
||||||
|
).onPress(() {
|
||||||
|
showCommonBottomSheetWithoutHeight(context,
|
||||||
|
title: "Select Feedback Type".needTranslation,
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24),
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: contactUsViewModel.feedbackTypeList.length,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
padding: EdgeInsets.only(top: 8, bottom: 8),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (innerContext, index) {
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
listTileTheme: ListTileThemeData(horizontalTitleGap: 4),
|
||||||
|
),
|
||||||
|
child: RadioListTile<FeedbackType>(
|
||||||
|
title: Text(
|
||||||
|
getIt.get<AppState>().isArabic() ? contactUsViewModel.feedbackTypeList[index].nameAR : contactUsViewModel.feedbackTypeList[index].nameEN,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.h,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
value: contactUsViewModel.feedbackTypeList[index],
|
||||||
|
fillColor: WidgetStateProperty.resolveWith((states) {
|
||||||
|
if (states.contains(WidgetState.selected)) {
|
||||||
|
return AppColors.primaryRedColor;
|
||||||
|
}
|
||||||
|
return Color(0xffEEEEEE);
|
||||||
|
}),
|
||||||
|
contentPadding: EdgeInsets.only(left: 12.h, right: 12.h),
|
||||||
|
groupValue: contactUsViewModel.selectedFeedbackType,
|
||||||
|
onChanged: (FeedbackType? newValue) async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
contactUsViewModel.setSelectedFeedbackType(newValue!);
|
||||||
|
if (contactUsViewModel.selectedFeedbackType.id == 1) {
|
||||||
|
LoaderBottomSheet.showLoader(loadingText: "Loading appointments list...".needTranslation);
|
||||||
|
await medicalFileViewModel.getPatientMedicalReportAppointmentsList(onSuccess: (val) async {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
bool? value = await Navigator.of(context).push(
|
||||||
|
CustomPageRoute(
|
||||||
|
page: FeedbackAppointmentSelection(),
|
||||||
|
fullScreenDialog: true,
|
||||||
|
direction: AxisDirection.down,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (value != null) {
|
||||||
|
// showConfirmRequestMedicalReportBottomSheet();
|
||||||
|
}
|
||||||
|
}, onError: (err) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Utils.getErrorWidget(loadingText: "You do not have any appointments to submit a feedback.".needTranslation),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
contactUsViewModel.setPatientFeedbackSelectedAppointment(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true);
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (contactUsViewModel.patientFeedbackSelectedAppointment != null) ...[
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
"Selected Appointment:".needTranslation.toText16(isBold: true),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.r,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(16.h),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Image.network(
|
||||||
|
contactUsViewModel.patientFeedbackSelectedAppointment!.doctorImageURL!,
|
||||||
|
width: 63.h,
|
||||||
|
height: 63.h,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
).circle(100).toShimmer2(isShow: false),
|
||||||
|
SizedBox(width: 16.h),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
(contactUsViewModel.patientFeedbackSelectedAppointment!.doctorNameObj!).toText16(isBold: true, maxlines: 1).toShimmer2(isShow: false),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Wrap(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
spacing: 3.h,
|
||||||
|
runSpacing: 4.h,
|
||||||
|
children: [
|
||||||
|
AppCustomChipWidget(labelText: contactUsViewModel.patientFeedbackSelectedAppointment!.clinicName!).toShimmer2(isShow: false),
|
||||||
|
AppCustomChipWidget(labelText: contactUsViewModel.patientFeedbackSelectedAppointment!.projectName!).toShimmer2(isShow: false),
|
||||||
|
AppCustomChipWidget(
|
||||||
|
icon: AppAssets.appointment_calendar_icon,
|
||||||
|
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(contactUsViewModel.patientFeedbackSelectedAppointment!.appointmentDate), false),
|
||||||
|
).toShimmer2(isShow: false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
TextInputWidget(
|
||||||
|
labelText: "Subject".needTranslation,
|
||||||
|
hintText: "Enter subject here".needTranslation,
|
||||||
|
controller: subjectTextController,
|
||||||
|
isEnable: true,
|
||||||
|
prefix: null,
|
||||||
|
autoFocus: false,
|
||||||
|
isBorderAllowed: false,
|
||||||
|
keyboardType: TextInputType.text,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: ResponsiveExtension(10).h,
|
||||||
|
horizontal: ResponsiveExtension(15).h,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
TextInputWidget(
|
||||||
|
labelText: "Message".needTranslation,
|
||||||
|
hintText: "Enter message here".needTranslation,
|
||||||
|
controller: messageTextController,
|
||||||
|
isEnable: true,
|
||||||
|
prefix: null,
|
||||||
|
autoFocus: false,
|
||||||
|
isBorderAllowed: false,
|
||||||
|
isMultiline: true,
|
||||||
|
keyboardType: TextInputType.text,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: ResponsiveExtension(10).h,
|
||||||
|
horizontal: ResponsiveExtension(15).h,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
CustomButton(
|
||||||
|
text: LocaleKeys.selectAttachment.tr(context: context),
|
||||||
|
onPressed: () async {
|
||||||
|
ImageOptions.showImageOptionsNew(
|
||||||
|
context,
|
||||||
|
true,
|
||||||
|
(String image, file) {
|
||||||
|
print(image);
|
||||||
|
print(file);
|
||||||
|
Navigator.pop(context);
|
||||||
|
contactUsViewModel.addFeedbackAttachment(image);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
backgroundColor: AppColors.secondaryLightRedColor,
|
||||||
|
borderColor: AppColors.secondaryLightRedColor,
|
||||||
|
textColor: AppColors.primaryRedColor,
|
||||||
|
fontSize: 14.f,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 10.r,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
||||||
|
height: isTablet || isFoldable ? 46.h : 40.h,
|
||||||
|
icon: AppAssets.file_icon,
|
||||||
|
iconColor: AppColors.primaryRedColor,
|
||||||
|
iconSize: 16.h,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
contactUsViewModel.feedbackAttachmentList.isNotEmpty
|
||||||
|
? Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 12.r,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: EdgeInsets.all(16.h),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: contactUsViewModel.feedbackAttachmentList.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.attach_file,
|
||||||
|
color: Color(0xff2B353E),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
"Image ${index + 1}".toText14().paddingOnly(bottom: 8.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.cancel_circle_icon).onPress(() {
|
||||||
|
contactUsViewModel.removeFeedbackAttachment(contactUsViewModel.feedbackAttachmentList[index]);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: SizedBox.shrink(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,27 +1,176 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.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';
|
||||||
|
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/contact_us/contact_us_view_model.dart';
|
||||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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:provider/provider.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class LiveChatPage extends StatelessWidget {
|
class LiveChatPage extends StatelessWidget {
|
||||||
const LiveChatPage({super.key});
|
LiveChatPage({super.key});
|
||||||
|
|
||||||
|
String chatURL = "";
|
||||||
|
|
||||||
|
late AppState appState;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
appState = getIt.get<AppState>();
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: AppColors.bgScaffoldColor,
|
backgroundColor: AppColors.bgScaffoldColor,
|
||||||
body: Column(
|
body: Consumer<ContactUsViewModel>(builder: (context, contactUsVM, child) {
|
||||||
children: [
|
return Column(
|
||||||
Expanded(
|
children: [
|
||||||
child: CollapsingListView(
|
Expanded(
|
||||||
title: LocaleKeys.liveChat.tr(),
|
child: CollapsingListView(
|
||||||
child: SingleChildScrollView(),
|
title: LocaleKeys.liveChat.tr(),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
ListView.separated(
|
||||||
|
padding: EdgeInsets.only(top: 16.h),
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: contactUsVM.isLiveChatProjectsListLoading ? 5 : contactUsVM.liveChatProjectsList.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return contactUsVM.isLiveChatProjectsListLoading
|
||||||
|
? Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
|
||||||
|
child: Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.h,
|
||||||
|
hasShadow: true,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(14.h),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Image.network(
|
||||||
|
"https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
|
||||||
|
width: 63.h,
|
||||||
|
height: 63.h,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
).circle(100).toShimmer2(isShow: true),
|
||||||
|
SizedBox(width: 16.h),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Dr John Smith".toText16(isBold: true).toShimmer2(isShow: true),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Wrap(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
spacing: 3.h,
|
||||||
|
runSpacing: 4.h,
|
||||||
|
children: [
|
||||||
|
AppCustomChipWidget(labelText: "").toShimmer2(isShow: true, width: 16.h),
|
||||||
|
AppCustomChipWidget(labelText: "").toShimmer2(isShow: true, width: 16.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).paddingSymmetrical(24.h, 0.h)
|
||||||
|
: 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,
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: contactUsVM.selectedLiveChatProjectIndex == index ? AppColors.primaryRedColor : AppColors.whiteColor,
|
||||||
|
borderRadius: 16.r,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
("${appState.isArabic() ? contactUsVM.liveChatProjectsList[index].projectNameN! : contactUsVM.liveChatProjectsList[index].projectName!}\n${contactUsVM.liveChatProjectsList[index].distanceInKilometers!} KM")
|
||||||
|
.needTranslation
|
||||||
|
.toText14(isBold: true, color: contactUsVM.selectedLiveChatProjectIndex == index ? AppColors.whiteColor : AppColors.textColor),
|
||||||
|
Transform.flip(
|
||||||
|
flipX: getIt.get<AppState>().isArabic(),
|
||||||
|
child: Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.forward_arrow_icon_small,
|
||||||
|
iconColor: contactUsVM.selectedLiveChatProjectIndex == index ? AppColors.whiteColor : AppColors.textColor,
|
||||||
|
width: 18.h,
|
||||||
|
height: 13.h,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(16.h, 16.h),
|
||||||
|
).onPress(() {
|
||||||
|
contactUsVM.setSelectedLiveChatProjectIndex(index);
|
||||||
|
chatURL =
|
||||||
|
"https://chat.hmg.com/Index.aspx?Name=${appState.getAuthenticatedUser()!.firstName}&PatientID=${appState.getAuthenticatedUser()!.patientId}&MobileNo=${appState.getAuthenticatedUser()!.mobileNumber}&Language=${appState.isArabic() ? 'ar' : 'en'}&WorkGroup=${contactUsVM.liveChatProjectsList[index].value}";
|
||||||
|
debugPrint("Chat URL: $chatURL");
|
||||||
|
}),
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: true,
|
||||||
|
),
|
||||||
|
child: CustomButton(
|
||||||
|
text: LocaleKeys.liveChat.tr(context: context),
|
||||||
|
onPressed: () async {
|
||||||
|
Uri uri = Uri.parse(chatURL);
|
||||||
|
launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: "");
|
||||||
|
},
|
||||||
|
backgroundColor: contactUsVM.selectedLiveChatProjectIndex == -1 ? AppColors.greyColor : AppColors.primaryRedColor,
|
||||||
|
borderColor: contactUsVM.selectedLiveChatProjectIndex == -1 ? AppColors.greyColor : AppColors.primaryRedColor,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
borderRadius: 12,
|
||||||
|
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||||
|
height: 50.h,
|
||||||
|
).paddingSymmetrical(24.h, 24.h),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
Container()
|
);
|
||||||
],
|
}),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
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/book_appointments/book_appointments_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/contact_us/contact_us_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/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/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class FeedbackAppointmentSelection extends StatelessWidget {
|
||||||
|
FeedbackAppointmentSelection({super.key});
|
||||||
|
|
||||||
|
late MedicalFileViewModel medicalFileViewModel;
|
||||||
|
late ContactUsViewModel contactUsViewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
|
||||||
|
contactUsViewModel = Provider.of<ContactUsViewModel>(context, listen: false);
|
||||||
|
return CollapsingListView(
|
||||||
|
title: LocaleKeys.feedback.tr(),
|
||||||
|
isClose: true,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ListView.separated(
|
||||||
|
padding: EdgeInsets.only(top: 24.h),
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: medicalFileViewModel.patientMedicalReportAppointmentHistoryList.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return 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,
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
|
||||||
|
child: AppointmentCard(
|
||||||
|
patientAppointmentHistoryResponseModel: medicalFileViewModel.patientMedicalReportAppointmentHistoryList[index],
|
||||||
|
myAppointmentsViewModel: Provider.of<MyAppointmentsViewModel>(context, listen: false),
|
||||||
|
bookAppointmentsViewModel: Provider.of<BookAppointmentsViewModel>(context, listen: false),
|
||||||
|
medicalFileViewModel: medicalFileViewModel,
|
||||||
|
contactUsViewModel: contactUsViewModel,
|
||||||
|
isLoading: false,
|
||||||
|
isFromHomePage: false,
|
||||||
|
isFromMedicalReport: true,
|
||||||
|
isForFeedback: true,
|
||||||
|
),
|
||||||
|
).paddingSymmetrical(24.h, 0.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,633 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
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_export.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/emergency_services/emergency_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/emergency_services/models/AmbulanceCallingPlace.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_doctor_card.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/AddressItem.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/appointment_bottom_sheet.dart' show AppointmentBottomSheet;
|
||||||
|
import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/location_input_bottom_sheet.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/CustomSwitch.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/ExpandableBottomSheet.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/model/BottomSheetType.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/map/HMSMap.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/map/map.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../../widgets/common_bottom_sheet.dart';
|
||||||
|
|
||||||
|
class RrtMapScreen extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
floatingActionButton: Visibility(
|
||||||
|
visible: context.watch<EmergencyServicesViewModel>().bottomSheetType ==
|
||||||
|
BottomSheetType.FIXED,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.only(end: 8.h, bottom: 68.h),
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor, borderRadius: 12.h),
|
||||||
|
child: Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.locate_me, width: 24.h, height: 24.h)
|
||||||
|
.paddingAll(12.h)
|
||||||
|
.onPress(() {
|
||||||
|
context
|
||||||
|
.read<EmergencyServicesViewModel>()
|
||||||
|
.moveToCurrentLocation();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomSheet: ExpandableBottomSheet(
|
||||||
|
bottomSheetType:
|
||||||
|
context.watch<EmergencyServicesViewModel>().bottomSheetType,
|
||||||
|
children: {
|
||||||
|
BottomSheetType.EXPANDED: ExpanedBottomSheet(context),
|
||||||
|
BottomSheetType.FIXED: FixedBottomSheet(context),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
if (context.read<EmergencyServicesViewModel>().isGMSAvailable)
|
||||||
|
GMSMap(
|
||||||
|
currentLocation:
|
||||||
|
context.read<EmergencyServicesViewModel>().getGMSLocation(),
|
||||||
|
onCameraMoved: (value) => context
|
||||||
|
.read<LocationViewModel>()
|
||||||
|
.handleGMSMapCameraMoved(value),
|
||||||
|
onCameraIdle:
|
||||||
|
context.read<LocationViewModel>().handleOnCameraIdle,
|
||||||
|
myLocationEnabled: true,
|
||||||
|
inputController:
|
||||||
|
context.read<EmergencyServicesViewModel>().gmsController,
|
||||||
|
showCenterMarker: true,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
HMSMap(
|
||||||
|
currentLocation:
|
||||||
|
context.read<EmergencyServicesViewModel>().getHMSLocation(),
|
||||||
|
onCameraMoved: (value) => context
|
||||||
|
.read<LocationViewModel>()
|
||||||
|
.handleHMSMapCameraMoved(value),
|
||||||
|
onCameraIdle:
|
||||||
|
context.read<LocationViewModel>().handleOnCameraIdle,
|
||||||
|
myLocationEnabled: false,
|
||||||
|
inputController:
|
||||||
|
context.read<EmergencyServicesViewModel>().hmsController,
|
||||||
|
showCenterMarker: true,
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: AlignmentDirectional.topStart,
|
||||||
|
child: Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h)
|
||||||
|
.onPress(() {
|
||||||
|
context
|
||||||
|
.read<EmergencyServicesViewModel>()
|
||||||
|
.flushPickupInformation();
|
||||||
|
Navigator.pop(context);
|
||||||
|
}),
|
||||||
|
).paddingOnly(top: 51.h, left: 24.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget FixedBottomSheet(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onVerticalDragUpdate: (details){
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
spacing: 24.h,
|
||||||
|
children: [
|
||||||
|
inputFields(context).paddingSymmetrical(16.h, 0.h),
|
||||||
|
SizedBox(
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.scaffoldBgColor,
|
||||||
|
customBorder: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(24.h),
|
||||||
|
topRight: Radius.circular(24.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 24.h,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
spacing: 4.h,
|
||||||
|
children: [
|
||||||
|
"Select Location".needTranslation.toText21(
|
||||||
|
weight: FontWeight.w600,
|
||||||
|
color: AppColors.textColor,
|
||||||
|
),
|
||||||
|
"Please select the location".needTranslation.toText12(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
CustomButton(
|
||||||
|
text: "Submit Request".needTranslation,
|
||||||
|
onPressed: () {
|
||||||
|
LocationViewModel locationViewModel = context.read<LocationViewModel>();
|
||||||
|
GeocodeResponse? response = locationViewModel.geocodeResponse;
|
||||||
|
PlaceDetails? placeDetails = locationViewModel.placeDetails;
|
||||||
|
PlacePrediction? placePrediction = locationViewModel.selectedPrediction;
|
||||||
|
context.read<EmergencyServicesViewModel>().submitRRTRequest(response?.results.first, placeDetails, placePrediction);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
).paddingOnly(top: 24.h, bottom: 32.h, left: 24.h, right: 24.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget ExpanedBottomSheet(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onVerticalDragUpdate: (details){
|
||||||
|
if(details.delta.dy>0){
|
||||||
|
context.read<EmergencyServicesViewModel>().updateBottomSheetState(BottomSheetType.FIXED);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.scaffoldBgColor,
|
||||||
|
customBorder: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(24.h),
|
||||||
|
topRight: Radius.circular(24.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 16.h,
|
||||||
|
children: [
|
||||||
|
|
||||||
|
hospitalAndPickUpSection(context),
|
||||||
|
|
||||||
|
|
||||||
|
],
|
||||||
|
).paddingOnly(top: 24.h, bottom: 32.h,left: 24.h, right: 24.h),
|
||||||
|
|
||||||
|
bottomPriceContent(context)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
locationsSections(BuildContext context) {
|
||||||
|
return DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
),
|
||||||
|
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
|
ListView.separated(
|
||||||
|
separatorBuilder: (_, __) => Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Divider(
|
||||||
|
color: AppColors.bottomNAVBorder,
|
||||||
|
height: 1,
|
||||||
|
thickness: 1,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: 3,
|
||||||
|
itemBuilder: (__, index) {
|
||||||
|
if (index ==
|
||||||
|
2) // todo means the end of the list so handle as per the viewmodel
|
||||||
|
{
|
||||||
|
return CustomButton(
|
||||||
|
height: 40.h,
|
||||||
|
backgroundColor: AppColors.lightRedButtonColor,
|
||||||
|
borderColor: Colors.transparent,
|
||||||
|
text: "Add new address".needTranslation,
|
||||||
|
textColor: AppColors.primaryRedColor,
|
||||||
|
iconColor: AppColors.primaryRedColor,
|
||||||
|
onPressed: () {},
|
||||||
|
icon: AppAssets.add_icon);
|
||||||
|
} else {
|
||||||
|
return AddressItem(
|
||||||
|
isSelected: index == 0,
|
||||||
|
address:
|
||||||
|
"Flat No 301, Building No 12, Palm Spring Apartment, Sector 45, Gurugram, Haryana 122003",
|
||||||
|
title: index == 0
|
||||||
|
? "Home".needTranslation
|
||||||
|
: "Work".needTranslation,
|
||||||
|
onTap: () {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]).paddingAll(16.h),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
hospitalAndPickUpSection(BuildContext context) {
|
||||||
|
return DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.r,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 16.h,
|
||||||
|
children: [
|
||||||
|
// Row(
|
||||||
|
// children: [
|
||||||
|
// hospitalAndPickUpItemContent(
|
||||||
|
// title: "Select Hospital".needTranslation,
|
||||||
|
// subTitle: "hospital".needTranslation,
|
||||||
|
// leadingIcon: AppAssets.hospital,
|
||||||
|
// ),
|
||||||
|
// Utils.buildSvgWithAssets(icon: AppAssets.down_cheveron,
|
||||||
|
// width: 24.h, height: 24.h)
|
||||||
|
// .paddingAll(16.h)
|
||||||
|
// ],
|
||||||
|
// ).onPress((){
|
||||||
|
// showHospitalBottomSheet(context);
|
||||||
|
// }),
|
||||||
|
// SizedBox(height: 16.h),
|
||||||
|
// Divider(
|
||||||
|
// color: AppColors.bottomNAVBorder,
|
||||||
|
// height: 1,
|
||||||
|
// thickness: 1,
|
||||||
|
// ),
|
||||||
|
// SizedBox(height: 16.h),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
hospitalAndPickUpItemContent(
|
||||||
|
title: "Pick".needTranslation,
|
||||||
|
subTitle: "Inside the home".needTranslation,
|
||||||
|
leadingIcon: AppAssets.pickup_bed,
|
||||||
|
),
|
||||||
|
CustomSwitch(
|
||||||
|
value: context
|
||||||
|
.watch<EmergencyServicesViewModel>()
|
||||||
|
.pickupFromInsideTheLocation,
|
||||||
|
onChanged: (value){
|
||||||
|
context
|
||||||
|
.read<EmergencyServicesViewModel>()
|
||||||
|
.updateThePickupPlaceFromLocation(value);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
hospitalAndPickUpItemContent(
|
||||||
|
title: '',
|
||||||
|
subTitle: "Have any appointment".needTranslation,
|
||||||
|
leadingIcon: AppAssets.appointment_checkin_icon,
|
||||||
|
),
|
||||||
|
CustomSwitch(
|
||||||
|
value: context
|
||||||
|
.watch<EmergencyServicesViewModel>()
|
||||||
|
.haveAnAppointment,
|
||||||
|
onChanged: (value) async {
|
||||||
|
// if (value) {
|
||||||
|
// openAppointmentList(context);
|
||||||
|
// }
|
||||||
|
await context.read<EmergencyServicesViewModel>()
|
||||||
|
.updateAppointment(value);
|
||||||
|
if (context.read<EmergencyServicesViewModel>().appointments?.isNotEmpty == true) {
|
||||||
|
openAppointmentList(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingAll(16.h),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
leadingIcon(String leadingIcon) {
|
||||||
|
return Container(
|
||||||
|
height: 40.h,
|
||||||
|
width: 40.h,
|
||||||
|
margin: EdgeInsets.only(right: 10.h),
|
||||||
|
padding: EdgeInsets.all(8.h),
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
borderRadius: 12.h,
|
||||||
|
color: AppColors.greyColor,
|
||||||
|
),
|
||||||
|
child: Utils.buildSvgWithAssets(icon: leadingIcon),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
hospitalAndPickUpItemContent({
|
||||||
|
required String title,
|
||||||
|
required String subTitle,
|
||||||
|
required String leadingIcon,
|
||||||
|
}) {
|
||||||
|
return Expanded(
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
this.leadingIcon(leadingIcon),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Visibility(
|
||||||
|
visible: title.isNotEmpty,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
title.toText12(
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
SizedBox(height: 2.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subTitle.toText14(
|
||||||
|
color: AppColors.textColor,
|
||||||
|
weight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomPriceContent(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.scaffoldBgColor,
|
||||||
|
customBorder: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(24.h),
|
||||||
|
topRight: Radius.circular(24.h),
|
||||||
|
),
|
||||||
|
hasShadow: true
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 12.h,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 4.h,
|
||||||
|
children: [
|
||||||
|
"Total amount to pay".needTranslation.toText18(
|
||||||
|
weight: FontWeight.w600,
|
||||||
|
color: AppColors.textColor,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.warning,
|
||||||
|
height: 18.h, width: 18.h),
|
||||||
|
SizedBox(width: 4.h,),
|
||||||
|
"Amount will be paid at the hospital"
|
||||||
|
.needTranslation
|
||||||
|
.toText12(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Utils.getPaymentAmountWithSymbol(
|
||||||
|
(Utils.formatNumberToInternationalFormat(context
|
||||||
|
.read<EmergencyServicesViewModel>()
|
||||||
|
.getTotalPrice() ??
|
||||||
|
0))
|
||||||
|
.toText24(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.textColor,
|
||||||
|
letterSpacing: -2),
|
||||||
|
AppColors.blackColor,
|
||||||
|
17.h)
|
||||||
|
|
||||||
|
// Utils.getPaymentAmountWithSymbol2(context.read<EmergencyServicesViewModel>().selectedTransportOption?.priceTotal??"0", letterSpacing: -2)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
CustomButton(
|
||||||
|
text: "Submit Request".needTranslation,
|
||||||
|
onPressed: () {
|
||||||
|
LocationViewModel locationViewModel = context.read<LocationViewModel>();
|
||||||
|
GeocodeResponse? response = locationViewModel.geocodeResponse;
|
||||||
|
PlaceDetails? placeDetails = locationViewModel.placeDetails;
|
||||||
|
PlacePrediction? placePrediction = locationViewModel.selectedPrediction;
|
||||||
|
context.read<EmergencyServicesViewModel>().submitAmbulanceRequest(response?.results.first, placeDetails, placePrediction);
|
||||||
|
})
|
||||||
|
],
|
||||||
|
).paddingOnly(top: 24.h, bottom: 12.h, left: 24.h, right: 24.h),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showHospitalBottomSheet(BuildContext context){
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
title:
|
||||||
|
LocaleKeys.selectHospital.tr(),
|
||||||
|
context,
|
||||||
|
child: Consumer<EmergencyServicesViewModel>(
|
||||||
|
builder:(_,vm,__)=> HospitalBottomSheetBody(
|
||||||
|
searchText: vm.searchController,
|
||||||
|
displayList: vm.displayList,
|
||||||
|
onFacilityClicked: (value) {
|
||||||
|
vm.setSelectedFacility(value);
|
||||||
|
vm.getDisplayList();
|
||||||
|
},
|
||||||
|
onHospitalClicked: (hospital) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
vm.setSelectedHospital(hospital);
|
||||||
|
},
|
||||||
|
onHospitalSearch: (value) {
|
||||||
|
vm.searchHospitals(value ?? "");
|
||||||
|
},
|
||||||
|
selectedFacility:
|
||||||
|
vm.selectedFacility,
|
||||||
|
hmcCount: vm.hmcCount,
|
||||||
|
hmgCount: vm.hmgCount,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
hasBottomPadding: false,
|
||||||
|
backgroundColor: AppColors.bottomSheetBgColor,
|
||||||
|
callBackFunc: () {
|
||||||
|
context.read<EmergencyServicesViewModel>().clearSearchText();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
///it will show the places field first and then hospital field
|
||||||
|
PlaceFirstThanHospitalField(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 16.h,
|
||||||
|
children: [
|
||||||
|
textPlaceInput(context),
|
||||||
|
hospitalField(context),
|
||||||
|
],
|
||||||
|
).paddingOnly(right: 24.h, left: 24.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
HospitalFieldFirstThanPlaces(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 16.h,
|
||||||
|
children: [hospitalField(context), textPlaceInput(context)],
|
||||||
|
).paddingOnly(right: 24.h, left: 24.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
textPlaceInput(context) {
|
||||||
|
return Consumer<LocationViewModel>(builder: (_, vm, __) {
|
||||||
|
print(
|
||||||
|
"the data is ${vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description}");
|
||||||
|
return SizedBox(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
child: TextInputWidget(
|
||||||
|
labelText: "Enter Pickup Location Manually".needTranslation,
|
||||||
|
hintText: "Enter Pickup Location".needTranslation,
|
||||||
|
controller: TextEditingController(
|
||||||
|
text: vm.geocodeResponse?.results.first.formattedAddress ??
|
||||||
|
vm.selectedPrediction?.description,
|
||||||
|
),
|
||||||
|
leadingIcon: AppAssets.location_pickup,
|
||||||
|
isAllowLeadingIcon: true,
|
||||||
|
isEnable: false,
|
||||||
|
prefix: null,
|
||||||
|
autoFocus: false,
|
||||||
|
isBorderAllowed: false,
|
||||||
|
keyboardType: TextInputType.text,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: ResponsiveExtension(10).h,
|
||||||
|
horizontal: ResponsiveExtension(15).h,
|
||||||
|
),
|
||||||
|
).onPress(() {
|
||||||
|
openLocationInputBottomSheet(context);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
///decide which field to show first based on the selected calling place
|
||||||
|
Widget inputFields(BuildContext context) {
|
||||||
|
return textPlaceInput(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
openLocationInputBottomSheet(BuildContext context) {
|
||||||
|
context.read<LocationViewModel>().flushSearchPredictions();
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
title: "".needTranslation,
|
||||||
|
context,
|
||||||
|
child: SizedBox(
|
||||||
|
height: MediaQuery.sizeOf(context).height * .8,
|
||||||
|
child: LocationInputBottomSheet(),
|
||||||
|
),
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
hasBottomPadding: false,
|
||||||
|
backgroundColor: AppColors.bottomSheetBgColor,
|
||||||
|
callBackFunc: () {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
hospitalField(BuildContext context) {
|
||||||
|
return DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor, borderRadius: 12.h),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
hospitalAndPickUpItemContent(
|
||||||
|
title: "Select Hospital".needTranslation,
|
||||||
|
subTitle: context
|
||||||
|
.read<EmergencyServicesViewModel>()
|
||||||
|
.getSelectedHospitalName() ??
|
||||||
|
"Select Hospital".needTranslation,
|
||||||
|
leadingIcon: AppAssets.hospital,
|
||||||
|
),
|
||||||
|
Utils.buildSvgWithAssets(
|
||||||
|
icon: AppAssets.down_cheveron, width: 24.h, height: 24.h)
|
||||||
|
.paddingAll(16.h)
|
||||||
|
],
|
||||||
|
).onPress(() {
|
||||||
|
print("the item is clicked");
|
||||||
|
showHospitalBottomSheet(context);
|
||||||
|
}).paddingSymmetrical(
|
||||||
|
10.w,
|
||||||
|
12.h,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openAppointmentList(BuildContext context) {
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
title: "Select Appointment".needTranslation,
|
||||||
|
context,
|
||||||
|
child: SizedBox(
|
||||||
|
height: MediaQuery.sizeOf(context).height * .5,
|
||||||
|
child: AppointmentBottomSheet(
|
||||||
|
list: context.read<EmergencyServicesViewModel>().appointments!,
|
||||||
|
onAppointmentSelection: (appointment) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
context.read<EmergencyServicesViewModel>().setSelectedAppointment(appointment);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
hasBottomPadding: false,
|
||||||
|
backgroundColor: AppColors.bottomSheetBgColor,
|
||||||
|
callBackFunc: () {
|
||||||
|
context.read<EmergencyServicesViewModel>().checkHasAppointment();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.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/emergency_services/emergency_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class TermsAndCondition extends StatelessWidget {
|
||||||
|
final String termsAndCondition;
|
||||||
|
const TermsAndCondition({super.key, required this.termsAndCondition});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
|
||||||
|
Expanded(
|
||||||
|
child: CollapsingListView(
|
||||||
|
title: "Terms And Condition".needTranslation,
|
||||||
|
child:DecoratedBox(decoration:RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 20.h,
|
||||||
|
hasShadow: true,
|
||||||
|
),child: HtmlWidget(termsAndCondition).paddingAll(16.h)).paddingAll(12.h)))]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/app_export.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/utils/date_util.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/emergency_services/emergency_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/RRTServiceData.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/emergency_services/history/widget/RequestStatus.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:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../../../core/utils/utils.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class RRTItem extends StatelessWidget {
|
||||||
|
final GetCMCAllOrdersResponseModel order;
|
||||||
|
|
||||||
|
const RRTItem({super.key, required this.order});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DecoratedBox(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
hasShadow: true,
|
||||||
|
customBorder: BorderRadius.all(
|
||||||
|
Radius.circular(20.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 8.h,
|
||||||
|
children: [
|
||||||
|
RequestStatus(status: order.statusId ?? 0),
|
||||||
|
"Req ID: ${order.iD}".toText16(color: AppColors.textColor, weight: FontWeight.w600),
|
||||||
|
Row(
|
||||||
|
spacing: 4.w,
|
||||||
|
children: [
|
||||||
|
chip( Utils.getDayMonthYearDateFormatted(DateUtil.convertStringToDate(order.time)), AppAssets.calendar, AppColors.blackBgColor),
|
||||||
|
chip("Rapid Response Team(RRT)".needTranslation, AppAssets.ic_rrt_vehicle, AppColors.blackBgColor),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 4.h),
|
||||||
|
if (order.statusId == 1 || order.statusId == 2)
|
||||||
|
CustomButton(
|
||||||
|
text: "Cancel Request".needTranslation,
|
||||||
|
onPressed: () async {
|
||||||
|
openCancelOrderBottomSheet(context);
|
||||||
|
},
|
||||||
|
backgroundColor: AppColors.primaryRedColor,
|
||||||
|
borderColor: AppColors.primaryRedColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
icon: AppAssets.cancel,
|
||||||
|
iconSize: 20.h,
|
||||||
|
height: 40.h,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingAll(16.h),
|
||||||
|
).paddingOnly(bottom: 16.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
chip(String title, String iconString, Color iconColor) {
|
||||||
|
return AppCustomChipWidget(
|
||||||
|
labelText: title,
|
||||||
|
icon: iconString,
|
||||||
|
iconColor: iconColor,
|
||||||
|
iconSize: 12.h,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
openCancelOrderBottomSheet(BuildContext context) {
|
||||||
|
context.read<EmergencyServicesViewModel>().cancelRRTOrder(order.iD);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,248 @@
|
|||||||
|
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/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/hmg_services/hmg_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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:provider/provider.dart';
|
||||||
|
|
||||||
|
class HhcOrderDetailPage extends StatefulWidget {
|
||||||
|
const HhcOrderDetailPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HhcOrderDetailPage> createState() => _HhcOrderDetailPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HhcOrderDetailPageState extends State<HhcOrderDetailPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
scheduleMicrotask(() async {
|
||||||
|
await hmgServicesViewModel.getAllHhcOrders();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _getStatusColor(int? statusId) {
|
||||||
|
switch (statusId) {
|
||||||
|
case 1: // Pending
|
||||||
|
return const Color(0xffCC9B14);
|
||||||
|
case 2: // Processing
|
||||||
|
return const Color(0xff2E303A);
|
||||||
|
case 3: // Completed
|
||||||
|
return const Color(0xff359846);
|
||||||
|
case 4: // Cancelled
|
||||||
|
case 6: // Rejected
|
||||||
|
case 7: // Rejected
|
||||||
|
return const Color(0xffD02127);
|
||||||
|
default:
|
||||||
|
return AppColors.greyColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatDate(String? dateString) {
|
||||||
|
if (dateString == null) return '';
|
||||||
|
try {
|
||||||
|
final date = DateTime.parse(dateString);
|
||||||
|
return DateFormat('MMM dd, yyyy').format(date);
|
||||||
|
} catch (e) {
|
||||||
|
return dateString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildLoadingShimmer() {
|
||||||
|
return ListView.separated(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: 3,
|
||||||
|
separatorBuilder: (_, __) => SizedBox(height: 12.h),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _buildOrderCard(GetCMCAllOrdersResponseModel(), isLoading: true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildOrderCard(GetCMCAllOrdersResponseModel order, {bool isLoading = false}) {
|
||||||
|
final statusColor = _getStatusColor(order.statusId);
|
||||||
|
final canCancel = order.statusId == 1 || order.statusId == 2;
|
||||||
|
|
||||||
|
return AnimatedContainer(
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: true,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Status and Date Row
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: statusColor.withValues(alpha: 0.1),
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: (isLoading ? "Processing" : order.statusText ?? '')
|
||||||
|
.toText12(
|
||||||
|
color: statusColor,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
)
|
||||||
|
.toShimmer2(isShow: isLoading),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
(isLoading ? "Jan 15, 2024" : _formatDate(order.created))
|
||||||
|
.toText12(
|
||||||
|
color: AppColors.textColorLight,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
)
|
||||||
|
.toShimmer2(isShow: isLoading),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
|
||||||
|
// Request ID
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
if (!isLoading) ...[
|
||||||
|
"Request ID:".needTranslation.toText14(
|
||||||
|
color: AppColors.textColorLight,
|
||||||
|
weight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
SizedBox(width: 4.w),
|
||||||
|
],
|
||||||
|
(isLoading ? "12345" : "${order.iD ?? '-'}").toText16(isBold: true).toShimmer2(isShow: isLoading),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(height: 12.h),
|
||||||
|
|
||||||
|
// Chips for Hospital, Service, and Amount
|
||||||
|
Wrap(
|
||||||
|
spacing: 6.w,
|
||||||
|
runSpacing: 6.h,
|
||||||
|
children: [
|
||||||
|
// Service
|
||||||
|
if (order.serviceText != null || isLoading)
|
||||||
|
AppCustomChipWidget(
|
||||||
|
icon: AppAssets.servicesBottom,
|
||||||
|
labelText: isLoading ? "Service Name" : order.serviceText ?? '-',
|
||||||
|
).toShimmer2(isShow: isLoading),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Cancel Button
|
||||||
|
if (canCancel || isLoading) ...[
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
text: "Cancel Order".needTranslation,
|
||||||
|
onPressed: isLoading ? () {} : () => HhcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order),
|
||||||
|
backgroundColor: AppColors.primaryRedColor,
|
||||||
|
borderColor: AppColors.primaryRedColor,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
fontSize: 14.f,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
borderRadius: 10.r,
|
||||||
|
height: 44.h,
|
||||||
|
).toShimmer2(isShow: isLoading),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildEmptyState() {
|
||||||
|
return Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 40.h),
|
||||||
|
child: Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 12.r,
|
||||||
|
hasShadow: false,
|
||||||
|
),
|
||||||
|
child: Utils.getNoDataWidget(
|
||||||
|
context,
|
||||||
|
noDataText: "You don't have any Home Health Care orders yet.".needTranslation,
|
||||||
|
isSmallWidget: true,
|
||||||
|
width: 62.w,
|
||||||
|
height: 62.h,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CollapsingListView(
|
||||||
|
title: "HHC Orders".needTranslation,
|
||||||
|
isLeading: true,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Consumer<HmgServicesViewModel>(
|
||||||
|
builder: (context, viewModel, child) {
|
||||||
|
if (viewModel.isHhcOrdersLoading) {
|
||||||
|
return _buildLoadingShimmer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel.hhcOrdersList.isEmpty) {
|
||||||
|
return _buildEmptyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView.separated(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: viewModel.hhcOrdersList.length,
|
||||||
|
separatorBuilder: (_, __) => SizedBox(height: 12.h),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final order = viewModel.hhcOrdersList.reversed.toList()[index];
|
||||||
|
|
||||||
|
return AnimationConfiguration.staggeredList(
|
||||||
|
position: index,
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
child: SlideAnimation(
|
||||||
|
verticalOffset: 100.0,
|
||||||
|
child: FadeInAnimation(
|
||||||
|
child: _buildOrderCard(order),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetrical(24.w, 0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,414 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.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/hmg_services/hmg_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_order_detail_page.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_selection_review_page.dart';
|
||||||
|
import 'package:hmg_patient_app_new/presentation/home_health_care/widgets/hhc_ui_selection_helper.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shimmer/shimmer.dart';
|
||||||
|
|
||||||
|
class HhcProceduresPage extends StatefulWidget {
|
||||||
|
const HhcProceduresPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HhcProceduresPage> createState() => _HhcProceduresPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HhcProceduresPageState extends State<HhcProceduresPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final HmgServicesViewModel hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
final AppState appState = getIt.get<AppState>();
|
||||||
|
|
||||||
|
scheduleMicrotask(() async {
|
||||||
|
final user = appState.getAuthenticatedUser();
|
||||||
|
if (user != null) {
|
||||||
|
// Clear previous selections when entering the page
|
||||||
|
hmgServicesViewModel.clearHhcServicesSelection();
|
||||||
|
await hmgServicesViewModel.getAllHhcOrders();
|
||||||
|
await hmgServicesViewModel.getAllHhcServices(patientID: user.patientId ?? 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCMCAllOrdersResponseModel? _getPendingOrder(List<GetCMCAllOrdersResponseModel> orders) {
|
||||||
|
if (orders.isEmpty) return null;
|
||||||
|
|
||||||
|
// Find pending or processing orders (status 1 or 2)
|
||||||
|
for (var order in orders) {
|
||||||
|
if (order.statusId == 1 || order.statusId == 2) {
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPendingOrderCard(GetCMCAllOrdersResponseModel order) {
|
||||||
|
int status = order.statusId ?? 0;
|
||||||
|
String statusDisp = order.statusText ?? "";
|
||||||
|
Color statusColor;
|
||||||
|
|
||||||
|
if (status == 1) {
|
||||||
|
// pending
|
||||||
|
statusColor = AppColors.statusPendingColor;
|
||||||
|
} else if (status == 2) {
|
||||||
|
// processing
|
||||||
|
statusColor = AppColors.statusProcessingColor;
|
||||||
|
} else if (status == 3) {
|
||||||
|
// completed
|
||||||
|
statusColor = AppColors.statusCompletedColor;
|
||||||
|
} else {
|
||||||
|
// cancel / rejected
|
||||||
|
statusColor = AppColors.statusRejectedColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
final canCancel = order.statusId == 1 || order.statusId == 2;
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
margin: EdgeInsets.all(16.w),
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 24.h,
|
||||||
|
hasShadow: true,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Status and Date Row
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: statusColor.withValues(alpha: 0.1),
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: statusDisp.toText12(
|
||||||
|
color: statusColor,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
if (order.created != null)
|
||||||
|
DateFormat('MMM dd, yyyy').format(DateTime.parse(order.created!)).toText12(
|
||||||
|
color: AppColors.textColorLight,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
|
||||||
|
// Request ID
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
"Request ID:".needTranslation.toText14(color: AppColors.textColorLight, weight: FontWeight.w500),
|
||||||
|
SizedBox(width: 4.w),
|
||||||
|
"${order.iD ?? '-'}".toText16(isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(height: 12.h),
|
||||||
|
|
||||||
|
// Info message
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(12.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.infoBannerBgColor,
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppColors.infoBannerBorderColor,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.info_outline,
|
||||||
|
size: 20.w,
|
||||||
|
color: AppColors.infoBannerIconColor,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
Expanded(
|
||||||
|
child: "You have a pending order. Please wait for it to be processed.".needTranslation.toText12(
|
||||||
|
color: AppColors.infoBannerTextColor,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (canCancel) ...[
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
text: "Cancel Order".needTranslation,
|
||||||
|
onPressed: () => HhcUiSelectionHelper.showCancelConfirmationDialog(context: context, order: order),
|
||||||
|
backgroundColor: AppColors.primaryRedColor,
|
||||||
|
borderColor: AppColors.primaryRedColor,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
fontSize: 14.f,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
borderRadius: 10.r,
|
||||||
|
height: 44.h,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildServiceSelectionList(List<GetCMCServicesResponseModel> services) {
|
||||||
|
if (services.isEmpty) {
|
||||||
|
return Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(24.h),
|
||||||
|
child: Text(
|
||||||
|
'No services available'.needTranslation,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.h,
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Consumer<HmgServicesViewModel>(
|
||||||
|
builder: (context, viewModel, child) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
if (viewModel.selectedHhcServices.isNotEmpty) ...[
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 16.w),
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.primaryRedColor.withValues(alpha: 0.1),
|
||||||
|
borderRadius: 16.r,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Selected Services".needTranslation.toText12(
|
||||||
|
color: AppColors.textColorLight,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
"${viewModel.selectedHhcServices.length} service(s) selected".toText14(
|
||||||
|
isBold: true,
|
||||||
|
weight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
"Total Amount".needTranslation.toText12(
|
||||||
|
color: AppColors.textColorLight,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
Utils.getPaymentAmountWithSymbol(
|
||||||
|
viewModel.getHhcSelectedServicesTotal().toStringAsFixed(2).toText16(
|
||||||
|
isBold: true,
|
||||||
|
weight: FontWeight.bold,
|
||||||
|
color: AppColors.primaryRedColor,
|
||||||
|
),
|
||||||
|
AppColors.primaryRedColor,
|
||||||
|
14,
|
||||||
|
isSaudiCurrency: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
Text(
|
||||||
|
'Select Services'.needTranslation,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20.h,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.blackColor,
|
||||||
|
letterSpacing: -0.8,
|
||||||
|
),
|
||||||
|
).paddingOnly(left: 16.w, right: 16.w),
|
||||||
|
SizedBox(height: 12.h),
|
||||||
|
ListView.builder(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||||
|
itemCount: services.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final service = services[index];
|
||||||
|
final isSelected = viewModel.isHhcServiceSelected(service);
|
||||||
|
final isArabic = getIt.get<AppState>().isArabic();
|
||||||
|
final serviceName = isArabic ? (service.textN ?? service.text ?? '') : (service.text ?? '');
|
||||||
|
|
||||||
|
return AnimatedContainer(
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
margin: EdgeInsets.only(bottom: 12.h),
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 16.r,
|
||||||
|
hasShadow: true,
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () => viewModel.toggleHhcServiceSelection(service),
|
||||||
|
borderRadius: BorderRadius.circular(16.r),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Checkbox(
|
||||||
|
value: isSelected,
|
||||||
|
onChanged: (v) => viewModel.toggleHhcServiceSelection(service),
|
||||||
|
activeColor: AppColors.primaryRedColor,
|
||||||
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
),
|
||||||
|
SizedBox(width: 12.w),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
serviceName.toText16(
|
||||||
|
weight: FontWeight.w400,
|
||||||
|
color: AppColors.blackColor,
|
||||||
|
maxlines: 2,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Summary Section
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _proceedWithSelectedService() {
|
||||||
|
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
if (hmgServicesViewModel.selectedHhcServices.isNotEmpty) {
|
||||||
|
hmgServicesViewModel.setSelectedServiceForHhcOrder(hmgServicesViewModel.selectedHhcServices.first);
|
||||||
|
Navigator.of(context).pushReplacement(
|
||||||
|
CustomPageRoute(
|
||||||
|
page: HhcSelectionReviewPage(selectedServices: hmgServicesViewModel.selectedHhcServices),
|
||||||
|
direction: AxisDirection.left,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildLoadingShimmer() {
|
||||||
|
return ListView.separated(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
itemCount: 10,
|
||||||
|
separatorBuilder: (_, __) => SizedBox(height: 12.h),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Shimmer.fromColors(
|
||||||
|
baseColor: Colors.grey[300]!,
|
||||||
|
highlightColor: Colors.grey[100]!,
|
||||||
|
child: Container(
|
||||||
|
height: 80.h,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CollapsingListView(
|
||||||
|
title: "Home Health Care".needTranslation,
|
||||||
|
history: () => Navigator.of(context).push(CustomPageRoute(page: HhcOrderDetailPage(), direction: AxisDirection.up)),
|
||||||
|
bottomChild: Consumer<HmgServicesViewModel>(
|
||||||
|
builder: (context, hmgServicesViewModel, child) {
|
||||||
|
if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) return SizedBox.shrink();
|
||||||
|
final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList);
|
||||||
|
if (pendingOrder == null && hmgServicesViewModel.selectedHhcServices.isNotEmpty) {
|
||||||
|
return SafeArea(
|
||||||
|
top: false,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 12.h),
|
||||||
|
child: CustomButton(
|
||||||
|
borderWidth: 0,
|
||||||
|
text: "Next".needTranslation,
|
||||||
|
onPressed: _proceedWithSelectedService,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
borderRadius: 12.r,
|
||||||
|
borderColor: Colors.transparent,
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 14.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return SizedBox.shrink();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
child: Consumer<HmgServicesViewModel>(
|
||||||
|
builder: (context, hmgServicesViewModel, child) {
|
||||||
|
if (hmgServicesViewModel.isHhcOrdersLoading || hmgServicesViewModel.isHhcServicesLoading) {
|
||||||
|
return _buildLoadingShimmer();
|
||||||
|
}
|
||||||
|
final pendingOrder = _getPendingOrder(hmgServicesViewModel.hhcOrdersList);
|
||||||
|
if (pendingOrder != null) {
|
||||||
|
return _buildPendingOrderCard(pendingOrder);
|
||||||
|
} else {
|
||||||
|
return _buildServiceSelectionList(hmgServicesViewModel.hhcServicesList);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,244 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.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/route_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/hmg_services/hmg_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/cmc_create_new_order_req_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_services_resp_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/loader/bottomsheet_loader.dart';
|
||||||
|
import 'package:maps_launcher/maps_launcher.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class HhcSelectionReviewPage extends StatefulWidget {
|
||||||
|
final List<GetCMCServicesResponseModel> selectedServices;
|
||||||
|
|
||||||
|
const HhcSelectionReviewPage({super.key, required this.selectedServices});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HhcSelectionReviewPage> createState() => _HhcSelectionReviewPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HhcSelectionReviewPageState extends State<HhcSelectionReviewPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
// Initialize ViewModel state with selected services
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
if (widget.selectedServices.isNotEmpty) {
|
||||||
|
hmgServicesViewModel.setSelectedServiceForHhcOrder(widget.selectedServices.first);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appState = getIt.get<AppState>();
|
||||||
|
final isArabic = appState.isArabic();
|
||||||
|
|
||||||
|
return CollapsingListView(
|
||||||
|
title: "Summary".needTranslation,
|
||||||
|
bottomChild: _buildBottomButton(),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildSelectedServicesCard(isArabic),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSelectedServicesCard(bool isArabic) {
|
||||||
|
return Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
borderRadius: 16.r,
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
"Selected Services".needTranslation.toText14(
|
||||||
|
weight: FontWeight.w600,
|
||||||
|
color: AppColors.greyTextColor,
|
||||||
|
letterSpacing: -0.4,
|
||||||
|
),
|
||||||
|
SizedBox(height: 12.h),
|
||||||
|
...widget.selectedServices.map((service) {
|
||||||
|
final serviceName = isArabic ? (service.textN ?? service.text ?? '') : (service.text ?? '');
|
||||||
|
final price = service.priceTotal ?? 0.0;
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 4.h),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: serviceName.toText14(
|
||||||
|
weight: FontWeight.w600,
|
||||||
|
color: AppColors.blackColor,
|
||||||
|
letterSpacing: -0.5,
|
||||||
|
maxlines: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBottomButton() {
|
||||||
|
return SafeArea(
|
||||||
|
top: false,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.whiteColor,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromARGB(13, 0, 0, 0),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: Offset(0, -2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: CustomButton(
|
||||||
|
text: "Confirm".needTranslation,
|
||||||
|
onPressed: _handleConfirm,
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
backgroundColor: AppColors.successColor,
|
||||||
|
borderRadius: 12.r,
|
||||||
|
borderColor: Colors.transparent,
|
||||||
|
borderWidth: 0,
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 14.h),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _launchDirections(HospitalsModel selectedHospital) {
|
||||||
|
final double lat = double.parse(selectedHospital.latitude ?? "0.0");
|
||||||
|
final double lng = double.parse(selectedHospital.longitude ?? "0.0");
|
||||||
|
|
||||||
|
if (lat != 0.0 && lng != 0.0) {
|
||||||
|
MapsLauncher.launchCoordinates(
|
||||||
|
lat,
|
||||||
|
lng,
|
||||||
|
selectedHospital.name ?? "Hospital",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showSuccessBottomSheet(int requestId, HmgServicesViewModel hmgServicesViewModel) {
|
||||||
|
return showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Utils.getSuccessWidget(loadingText: "Your request has been successfully submitted.".needTranslation),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
"Here is your request #: ".needTranslation.toText14(
|
||||||
|
color: AppColors.textColorLight,
|
||||||
|
weight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
SizedBox(width: 4.w),
|
||||||
|
("$requestId").toText16(isBold: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
height: 56.h,
|
||||||
|
text: LocaleKeys.ok.tr(),
|
||||||
|
onPressed: () {
|
||||||
|
context.pop();
|
||||||
|
context.pop();
|
||||||
|
hmgServicesViewModel.getAllHhcOrders();
|
||||||
|
},
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isCloseButtonVisible: false,
|
||||||
|
isDismissible: false,
|
||||||
|
isFullScreen: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleConfirm() {
|
||||||
|
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
final appState = getIt.get<AppState>();
|
||||||
|
|
||||||
|
return showCommonBottomSheetWithoutHeight(
|
||||||
|
title: LocaleKeys.notice.tr(context: context),
|
||||||
|
context,
|
||||||
|
child: Utils.getWarningWidget(
|
||||||
|
loadingText: "Are you sure you want to submit this request?".needTranslation,
|
||||||
|
isShowActionButtons: true,
|
||||||
|
onCancelTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
onConfirmTap: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
LoaderBottomSheet.showLoader();
|
||||||
|
|
||||||
|
// Create the services list from all selected services
|
||||||
|
final servicesList = widget.selectedServices.map((selectedService) {
|
||||||
|
return PatientERCMCInsertServicesList(
|
||||||
|
recordID: selectedService.iD,
|
||||||
|
serviceID: selectedService.serviceID,
|
||||||
|
selectedServiceName: selectedService.text,
|
||||||
|
selectedServiceNameAR: selectedService.textN,
|
||||||
|
price: selectedService.price,
|
||||||
|
vAT: selectedService.priceVAT,
|
||||||
|
totalPrice: selectedService.priceTotal,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
// For HHC, we don't need hospital selection, use a default projectID or 0
|
||||||
|
await hmgServicesViewModel.addHhcOrder(
|
||||||
|
projectID: 0,
|
||||||
|
// HHC doesn't require hospital/project selection
|
||||||
|
orderServiceID: widget.selectedServices.first.orderServiceID ?? 4,
|
||||||
|
// HHC service ID
|
||||||
|
services: servicesList,
|
||||||
|
onSuccess: (requestId) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showSuccessBottomSheet(requestId, hmgServicesViewModel);
|
||||||
|
},
|
||||||
|
onError: (err) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.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/route_extensions.dart';
|
||||||
|
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/order_update_req_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_cmc_all_orders_resp_model.dart';
|
||||||
|
import 'package:hmg_patient_app_new/generated/locale_keys.g.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/loader/bottomsheet_loader.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class HhcUiSelectionHelper {
|
||||||
|
static void showCancelConfirmationDialog({
|
||||||
|
required BuildContext context,
|
||||||
|
required GetCMCAllOrdersResponseModel order,
|
||||||
|
}) {
|
||||||
|
final HmgServicesViewModel hmgServicesViewModel = context.read<HmgServicesViewModel>();
|
||||||
|
|
||||||
|
return showCommonBottomSheetWithoutHeight(
|
||||||
|
title: LocaleKeys.notice.tr(context: context),
|
||||||
|
context,
|
||||||
|
child: Utils.getWarningWidget(
|
||||||
|
loadingText: "Are you sure you want to cancel this order?".needTranslation,
|
||||||
|
isShowActionButtons: true,
|
||||||
|
onCancelTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
onConfirmTap: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
LoaderBottomSheet.showLoader();
|
||||||
|
|
||||||
|
final requestModel = OrderUpdateRequestModel(
|
||||||
|
presOrderID: order.iD,
|
||||||
|
rejectionReason: "Cancelled by user",
|
||||||
|
presOrderStatus: 4, // Cancelled status
|
||||||
|
editedBy: 3,
|
||||||
|
);
|
||||||
|
|
||||||
|
await hmgServicesViewModel.updateHhcPresOrder(
|
||||||
|
requestModel: requestModel,
|
||||||
|
onSuccess: (_) async {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
showCommonBottomSheetWithoutHeight(
|
||||||
|
context,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.w),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Utils.getSuccessWidget(loadingText: "Order has been cancelled successfully".needTranslation),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
height: 56.h,
|
||||||
|
text: LocaleKeys.ok.tr(),
|
||||||
|
onPressed: () {
|
||||||
|
context.pop();
|
||||||
|
hmgServicesViewModel.getAllHhcOrders();
|
||||||
|
},
|
||||||
|
textColor: AppColors.whiteColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isCloseButtonVisible: false,
|
||||||
|
isDismissible: false,
|
||||||
|
isFullScreen: false,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onError: (error) {
|
||||||
|
LoaderBottomSheet.hideLoader();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
callBackFunc: () {},
|
||||||
|
isFullScreen: false,
|
||||||
|
isCloseButtonVisible: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -1,23 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
|
||||||
|
|
||||||
class ServicesPage extends StatelessWidget {
|
|
||||||
const ServicesPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: AppColors.bgScaffoldColor,
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Appointments'),
|
|
||||||
backgroundColor: AppColors.bgScaffoldColor,
|
|
||||||
),
|
|
||||||
body: const Center(
|
|
||||||
child: Text(
|
|
||||||
'Appointments Page',
|
|
||||||
style: TextStyle(fontSize: 24),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue