feature/search_by_region
#38
Merged
Haroon6138
merged 4 commits from feature/search_by_region into master 1 month ago
@ -0,0 +1,5 @@
|
||||
<svg width="10" height="13" viewBox="0 0 10 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 2.85449C3.79188 2.85449 2.8125 3.83387 2.8125 5.04199C2.8125 6.25011 3.79188 7.22949 5 7.22949C6.20812 7.22949 7.1875 6.25011 7.1875 5.04199C7.1875 3.83387 6.20812 2.85449 5 2.85449ZM3.6875 5.04199C3.6875 4.31712 4.27513 3.72949 5 3.72949C5.72487 3.72949 6.3125 4.31712 6.3125 5.04199C6.3125 5.76687 5.72487 6.35449 5 6.35449C4.27513 6.35449 3.6875 5.76687 3.6875 5.04199Z" fill="#ED1C2B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 0.229492C2.38798 0.229492 0.1875 2.42783 0.1875 5.09268C0.1875 7.8228 2.43772 9.64709 4.31579 10.8329L4.32334 10.8377L4.33107 10.8422C4.5346 10.9593 4.76514 11.0212 5 11.0212C5.23486 11.0212 5.4654 10.9593 5.66893 10.8422L5.67567 10.8383L5.68227 10.8342C7.56769 9.65737 9.8125 7.81358 9.8125 5.09268C9.8125 2.42783 7.61202 0.229492 5 0.229492ZM1.0625 5.09268C1.0625 2.90553 2.87676 1.10449 5 1.10449C7.12324 1.10449 8.9375 2.90553 8.9375 5.09268C8.9375 7.29808 7.10717 8.91207 5.22662 10.0871C5.15694 10.1259 5.079 10.1462 5 10.1462C4.92132 10.1462 4.84369 10.1261 4.77422 10.0876C2.89372 8.89884 1.0625 7.30546 1.0625 5.09268Z" fill="#ED1C2B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 10.7295C1.73936 10.7295 1.93382 10.9217 1.93745 11.1602C1.94159 11.1712 1.96197 11.2114 2.04585 11.2775C2.16816 11.3739 2.37227 11.4798 2.66348 11.5769C3.24132 11.7695 4.06744 11.8962 5 11.8962C5.93256 11.8962 6.75868 11.7695 7.33652 11.5769C7.62773 11.4798 7.83184 11.3739 7.95415 11.2775C8.03803 11.2114 8.05841 11.1712 8.06255 11.1602C8.06618 10.9217 8.26064 10.7295 8.5 10.7295C8.74162 10.7295 8.9375 10.9254 8.9375 11.167C8.9375 11.5196 8.72273 11.7859 8.49575 11.9647C8.26385 12.1475 7.95539 12.2929 7.61322 12.407C6.92432 12.6366 6.00044 12.7712 5 12.7712C3.99956 12.7712 3.07568 12.6366 2.38678 12.407C2.04461 12.2929 1.73615 12.1475 1.50425 11.9647C1.27727 11.7859 1.0625 11.5196 1.0625 11.167C1.0625 10.9254 1.25838 10.7295 1.5 10.7295ZM8.06349 11.1572C8.06349 11.1571 8.06349 11.1572 8.06349 11.1572V11.1572Z" fill="#ED1C2B"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@ -0,0 +1,5 @@
|
||||
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.47635 0.357633C1.3055 0.186779 1.02849 0.186779 0.857633 0.357633C0.686779 0.528487 0.686779 0.805497 0.857633 0.976351L2.46119 2.57991C1.74908 3.50857 1.31283 4.60696 1.31283 5.87371C1.31283 7.46181 1.98475 8.7894 2.92684 9.88512C3.86488 10.9761 5.08602 11.856 6.2293 12.5637L6.23681 12.5684L6.24451 12.5727C6.47506 12.7029 6.73552 12.7712 7.00033 12.7712C7.26514 12.7712 7.52559 12.7029 7.75614 12.5727L7.76285 12.5689L7.76943 12.5649C8.63521 12.0351 9.66148 11.3872 10.4965 10.6152L12.5243 12.643C12.6952 12.8139 12.9722 12.8139 13.143 12.643C13.3139 12.4722 13.3139 12.1952 13.143 12.0243L8.48292 7.3642C8.47847 7.35955 8.47393 7.35501 8.46931 7.35059L5.56673 4.44802C5.5623 4.44339 5.55776 4.43884 5.5531 4.43438L1.47635 0.357633ZM4.72223 4.84095L3.08613 3.20485C2.51802 3.9791 2.18783 4.86436 2.18783 5.87371C2.18783 7.19521 2.74204 8.32806 3.59032 9.31467C4.44051 10.3035 5.57042 11.1262 6.68141 11.8145C6.77877 11.868 6.88851 11.8962 7.00033 11.8962C7.11248 11.8962 7.22255 11.8678 7.32013 11.814C8.18224 11.2864 9.12483 10.6862 9.87729 9.99601L8.07636 8.19508C7.73263 8.32898 7.33404 8.39615 7.00033 8.39615C5.63112 8.39615 4.52116 7.28619 4.52116 5.91698C4.52116 5.58326 4.58833 5.18468 4.72223 4.84095ZM7.36809 7.48681L5.4305 5.54922C5.40846 5.67294 5.39616 5.79917 5.39616 5.91698C5.39616 6.80294 6.11437 7.52115 7.00033 7.52115C7.11814 7.52115 7.24437 7.50884 7.36809 7.48681Z" fill="#2E3039"/>
|
||||
<path d="M7.0004 1.10449C6.13419 1.10449 5.31049 1.34359 4.59613 1.76103C4.38751 1.88294 4.11957 1.81265 3.99766 1.60403C3.87575 1.39541 3.94605 1.12747 4.15466 1.00556C4.99638 0.513701 5.97157 0.229492 7.0004 0.229492C10.0778 0.229492 12.6879 2.77256 12.6879 5.87369C12.6879 6.94853 12.3781 7.91037 11.8817 8.76226C11.76 8.97103 11.4922 9.04165 11.2834 8.92C11.0746 8.79834 11.004 8.53049 11.1257 8.32172C11.5556 7.58384 11.8129 6.77241 11.8129 5.87369C11.8129 3.26657 9.60535 1.10449 7.0004 1.10449Z" fill="#2E3039"/>
|
||||
<path d="M7.00038 4.31283C6.92215 4.31283 6.84547 4.31839 6.77066 4.32909C6.53147 4.36331 6.30984 4.19714 6.27562 3.95795C6.24141 3.71876 6.40758 3.49712 6.64677 3.46291C6.76248 3.44636 6.88056 3.43783 7.00038 3.43783C8.36959 3.43783 9.47955 4.54779 9.47955 5.91699C9.47955 6.03681 9.47102 6.15489 9.45446 6.27061C9.42025 6.5098 9.19861 6.67596 8.95942 6.64175C8.72023 6.60754 8.55407 6.3859 8.58828 6.14671C8.59898 6.07191 8.60455 5.99523 8.60455 5.91699C8.60455 5.03103 7.88634 4.31283 7.00038 4.31283Z" fill="#2E3039"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@ -0,0 +1,207 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:hmg_patient_app_new/core/cache_consts.dart' show CacheConst;
|
||||
import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils;
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart' show RegionList, PatientDoctorAppointmentList, DoctorList, PatientDoctorAppointmentListByRegion;
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
|
||||
|
||||
class DoctorMapper{
|
||||
static Future<RegionList> getMappedDoctor(List<DoctorList> doctorList,
|
||||
{bool isArabic = false}) async {
|
||||
RegionList regionList = RegionList();
|
||||
final lat = await Utils.getNumFromPrefs(CacheConst.userLat);
|
||||
final long = await Utils.getNumFromPrefs(CacheConst.userLat);
|
||||
|
||||
for (var element in doctorList) {
|
||||
String? region = element.getRegionName(isArabic);
|
||||
if (region == null) continue;
|
||||
|
||||
var regionDoctorList = regionList.registeredDoctorMap?.putIfAbsent(region, () => PatientDoctorAppointmentListByRegion());
|
||||
|
||||
List<PatientDoctorAppointmentList>? targetList = element.isHMC == true
|
||||
? regionDoctorList?.hmcDoctorList
|
||||
: regionDoctorList?.hmgDoctorList;
|
||||
|
||||
var doctorByHospital = targetList
|
||||
?.where((clinic) =>
|
||||
clinic.filterName ==
|
||||
element.getProjectCompleteNameWithLocale(isArabic: isArabic))
|
||||
.toList() ??
|
||||
[];
|
||||
|
||||
if (doctorByHospital.isNotEmpty) {
|
||||
doctorByHospital.first.patientDoctorAppointmentList?.add(element);
|
||||
} else {
|
||||
var newAppointment = PatientDoctorAppointmentList(
|
||||
filterName:
|
||||
element.getProjectCompleteNameWithLocale(isArabic: isArabic),
|
||||
distanceInKMs: element.projectDistanceInKiloMeters.toString(),
|
||||
projectTopName: element.projectTopName,
|
||||
projectBottomName: element.projectBottomName,
|
||||
patientDoctorAppointment: element,
|
||||
isHMC: element.isHMC
|
||||
);
|
||||
if(element.projectDistanceInKiloMeters!= null ){
|
||||
if(regionDoctorList!.distance>element.projectDistanceInKiloMeters){
|
||||
regionDoctorList.distance = element.projectDistanceInKiloMeters;
|
||||
}
|
||||
if (element.isHMC == true &&
|
||||
element.projectDistanceInKiloMeters <
|
||||
regionDoctorList.hmcDistance) {
|
||||
regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters;
|
||||
} else if (element.projectDistanceInKiloMeters <
|
||||
regionDoctorList.hmgDistance) {
|
||||
regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters;
|
||||
}
|
||||
}else
|
||||
if (lat != 0&&
|
||||
long != 0 && element.latitude != null && element.longitude != null) {
|
||||
|
||||
|
||||
double distance = calculateDistance(lat.toDouble(), long.toDouble(), double.parse(element.latitude!), double.parse(element.longitude!));
|
||||
if(distance<0){
|
||||
distance *= -1;
|
||||
}
|
||||
if(regionDoctorList!.distance>distance){
|
||||
regionDoctorList.distance = distance;
|
||||
}
|
||||
if (element.isHMC == true &&
|
||||
element.projectDistanceInKiloMeters <
|
||||
regionDoctorList.hmcDistance) {
|
||||
regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters;
|
||||
} else if (element.projectDistanceInKiloMeters <
|
||||
regionDoctorList.hmgDistance) {
|
||||
regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters;
|
||||
}
|
||||
}
|
||||
targetList?.add(newAppointment);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
regionDoctorList?.hmcSize = regionDoctorList.hmcDoctorList?.length ?? 0;
|
||||
regionDoctorList?.hmgSize = regionDoctorList.hmgDoctorList?.length ?? 0;
|
||||
|
||||
regionList.registeredDoctorMap?[region] = regionDoctorList;
|
||||
}
|
||||
|
||||
return regionList;
|
||||
}
|
||||
static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
var pi = 3.142;
|
||||
const double R = 6371;
|
||||
double dLat = (lat2 - lat1) * pi / 180;
|
||||
double dLon = (lon2 - lon1) * pi / 180;
|
||||
double a = sin(dLat / 2) * sin(dLat / 2) +
|
||||
cos(lat1 * pi / 180) * cos(lat2 * pi / 180) * sin(dLon / 2) * sin(dLon / 2);
|
||||
double c = 2 * atan2(sqrt(a), sqrt(1 - a));
|
||||
return R * c;
|
||||
}
|
||||
|
||||
static Future<RegionList> sortList(bool isGPSEnabled, RegionList unsorted, ) async {
|
||||
if(isGPSEnabled){
|
||||
if(unsorted.registeredDoctorMap == null) return unsorted;
|
||||
var sortedMap = Map.fromEntries(
|
||||
unsorted.registeredDoctorMap!.entries.toList()
|
||||
..sort((a, b) => a.value!.distance.compareTo(b.value!.distance)),
|
||||
);
|
||||
|
||||
unsorted.registeredDoctorMap = sortedMap;
|
||||
return unsorted;
|
||||
|
||||
}
|
||||
|
||||
List<String>? keys = unsorted.registeredDoctorMap?.keys.toList();
|
||||
keys?.sort();
|
||||
|
||||
if (keys == null) return unsorted;
|
||||
Map<String, PatientDoctorAppointmentListByRegion> sortedMap = {};
|
||||
for (var key in keys) {
|
||||
sortedMap[key] = unsorted.registeredDoctorMap![key]!;
|
||||
}
|
||||
unsorted.registeredDoctorMap = sortedMap;
|
||||
return unsorted;
|
||||
}
|
||||
|
||||
static Future<RegionList> getMappedHospitals(
|
||||
List<HospitalsModel> hospitalList, {
|
||||
bool isArabic = false,
|
||||
}) async {
|
||||
final regionList = RegionList();
|
||||
final lat = await Utils.getNumFromPrefs(CacheConst.userLat);
|
||||
final long = await Utils.getNumFromPrefs(CacheConst.userLat);
|
||||
for (final hospital in hospitalList) {
|
||||
final region = hospital.getRegionName(isArabic);
|
||||
if (region == null) continue;
|
||||
|
||||
final regionData = regionList.registeredDoctorMap?.putIfAbsent(
|
||||
region,
|
||||
() => PatientDoctorAppointmentListByRegion(),
|
||||
);
|
||||
|
||||
List<PatientDoctorAppointmentList>? targetList = hospital.isHMC == true
|
||||
? regionData?.hmcDoctorList
|
||||
: regionData?.hmgDoctorList;
|
||||
|
||||
List<PatientDoctorAppointmentList> existingEntry = targetList
|
||||
?.where(
|
||||
(entry) => entry.filterName == hospital.getName(isArabic),
|
||||
)
|
||||
.toList() ??
|
||||
[];
|
||||
|
||||
if (existingEntry.isNotEmpty) {
|
||||
existingEntry.first.hospitalList.add(hospital);
|
||||
} else {
|
||||
final newEntry = PatientDoctorAppointmentList(
|
||||
filterName: hospital.name,
|
||||
distanceInKMs: hospital.distanceInKilometers?.toString(),
|
||||
projectTopName: hospital.name,
|
||||
projectBottomName: hospital.name,
|
||||
model: hospital,
|
||||
isHMC: hospital.isHMC);
|
||||
|
||||
final distance = hospital.distanceInKilometers;
|
||||
|
||||
if (distance != null) {
|
||||
if (regionData!.distance > distance) {
|
||||
regionData.distance = distance;
|
||||
}
|
||||
if (hospital.isHMC == true && distance < regionData.hmcDistance) {
|
||||
regionData.hmcDistance = distance;
|
||||
} else if (distance < regionData.hmgDistance) {
|
||||
regionData.hmgDistance = distance;
|
||||
}
|
||||
} else if ( lat != 0&&
|
||||
long != 0 &&
|
||||
hospital.latitude != null &&
|
||||
hospital.longitude != null) {
|
||||
double calculatedDistance = calculateDistance(
|
||||
lat.toDouble(),
|
||||
long.toDouble(),
|
||||
double.parse(hospital.latitude!),
|
||||
double.parse(hospital.longitude!),
|
||||
).abs();
|
||||
|
||||
if (regionData!.distance > calculatedDistance) {
|
||||
regionData.distance = calculatedDistance;
|
||||
}
|
||||
if (hospital.isHMC == true &&
|
||||
calculatedDistance < regionData.hmcDistance) {
|
||||
regionData.hmcDistance = calculatedDistance;
|
||||
} else if (calculatedDistance < regionData.hmgDistance) {
|
||||
regionData.hmgDistance = calculatedDistance;
|
||||
}
|
||||
}
|
||||
targetList?.add(newEntry);
|
||||
}
|
||||
|
||||
regionData?.hmcSize = regionData.hmcDoctorList?.length ?? 0;
|
||||
regionData?.hmgSize = regionData.hmgDoctorList?.length ?? 0;
|
||||
regionList.registeredDoctorMap?[region] = regionData;
|
||||
}
|
||||
|
||||
return regionList;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
import 'package:flutter/foundation.dart' show ChangeNotifier;
|
||||
|
||||
enum AppointmentViaRegionState {
|
||||
REGION_SELECTION,
|
||||
TYPE_SELECTION,
|
||||
HOSPITAL_SELECTION,
|
||||
CLINIC_SELECTION,
|
||||
DOCTOR_SELECTION
|
||||
}
|
||||
|
||||
class AppointmentViaRegionViewmodel extends ChangeNotifier {
|
||||
String? selectedRegionId;
|
||||
String? selectedFacilityType;
|
||||
AppointmentViaRegionState bottomSheetState =
|
||||
AppointmentViaRegionState.REGION_SELECTION;
|
||||
|
||||
void setSelectedRegionId(String? regionId) {
|
||||
selectedRegionId = regionId;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setFacility(String? facility) {
|
||||
selectedFacilityType = facility;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setBottomSheetState(AppointmentViaRegionState state) {
|
||||
bottomSheetState = state;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void handleBackPress() {
|
||||
switch (bottomSheetState) {
|
||||
case AppointmentViaRegionState.REGION_SELECTION:
|
||||
// Do nothing or exit the bottom sheet
|
||||
break;
|
||||
case AppointmentViaRegionState.TYPE_SELECTION:
|
||||
setBottomSheetState(AppointmentViaRegionState.REGION_SELECTION);
|
||||
setSelectedRegionId(null);
|
||||
break;
|
||||
case AppointmentViaRegionState.HOSPITAL_SELECTION:
|
||||
setBottomSheetState(AppointmentViaRegionState.TYPE_SELECTION);
|
||||
break;
|
||||
|
||||
// case AppointmentViaRegionState.HOSPITAL_SELECTION:
|
||||
// case AppointmentViaRegionState.CLINIC_SELECTION:
|
||||
// setBottomSheetState(AppointmentViaRegionState.TYPE_SELECTION);
|
||||
// setFacility(null);
|
||||
// break;
|
||||
// case AppointmentViaRegionState.DOCTOR_SELECTION:
|
||||
// if (selectedFacilityType == 'Hospital') {
|
||||
// setBottomSheetState(AppointmentViaRegionState.HOSPITAL_SELECTION);
|
||||
// } else if (selectedFacilityType == 'Medical Center') {
|
||||
// setBottomSheetState(AppointmentViaRegionState.CLINIC_SELECTION);
|
||||
// }
|
||||
// break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
void flush() {
|
||||
setSelectedRegionId(null);
|
||||
setFacility(null);
|
||||
setBottomSheetState(AppointmentViaRegionState.REGION_SELECTION);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
enum FacilitySelection{
|
||||
ALL('ALL'),
|
||||
HMG('hmg'),
|
||||
HMC('hmc');
|
||||
|
||||
final String value;
|
||||
const FacilitySelection(this.value);
|
||||
}
|
||||
@ -0,0 +1,274 @@
|
||||
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
|
||||
|
||||
class DoctorList {
|
||||
int? clinicID;
|
||||
dynamic appointmentNo;
|
||||
String? clinicName;
|
||||
String? doctorTitle;
|
||||
num? iD;
|
||||
String? name;
|
||||
int? projectID;
|
||||
String? projectName;
|
||||
int? actualDoctorRate;
|
||||
num? clinicRoomNo;
|
||||
dynamic date;
|
||||
dynamic appointmentDate;
|
||||
dynamic dayName;
|
||||
int? doctorID;
|
||||
String? doctorImageURL;
|
||||
dynamic doctorProfile;
|
||||
dynamic doctorProfileInfo;
|
||||
int? doctorRate;
|
||||
num? gender;
|
||||
String? genderDescription;
|
||||
bool? isAppointmentAllowed;
|
||||
bool? isDoctorAllowVedioCall;
|
||||
bool? isDoctorDummy;
|
||||
bool? isLiveCare;
|
||||
bool? isLiveCareClinic;
|
||||
bool? isDoctorHasPrePostImages;
|
||||
String? latitude;
|
||||
String? longitude;
|
||||
String? nationalityFlagURL;
|
||||
String? nationalityID;
|
||||
String? nationalityName;
|
||||
dynamic nearestFreeSlot;
|
||||
int? noOfPatientsRate;
|
||||
num? originalClinicID;
|
||||
num? personRate;
|
||||
dynamic projectDistanceInKiloMeters;
|
||||
String? qR;
|
||||
dynamic qRString;
|
||||
num? rateNumber;
|
||||
dynamic serviceID;
|
||||
String? setupID;
|
||||
List<String>? speciality;
|
||||
List<String>? specialityN;
|
||||
dynamic workingHours;
|
||||
dynamic decimalDoctorRate;
|
||||
String? projectBottomName;
|
||||
String? projectTopName;
|
||||
bool? isHMC;
|
||||
String? region;
|
||||
String? regionArabic;
|
||||
String? regionEnglish;
|
||||
String? regionID;
|
||||
|
||||
DoctorList(
|
||||
{this.clinicID,
|
||||
this.appointmentNo,
|
||||
this.clinicName,
|
||||
this.doctorTitle,
|
||||
this.iD,
|
||||
this.name,
|
||||
this.projectID,
|
||||
this.projectName,
|
||||
this.actualDoctorRate,
|
||||
this.clinicRoomNo,
|
||||
this.date,
|
||||
this.appointmentDate,
|
||||
this.dayName,
|
||||
this.doctorID,
|
||||
this.doctorImageURL,
|
||||
this.doctorProfile,
|
||||
this.doctorProfileInfo,
|
||||
this.doctorRate,
|
||||
this.gender,
|
||||
this.genderDescription,
|
||||
this.isAppointmentAllowed,
|
||||
this.isDoctorAllowVedioCall,
|
||||
this.isDoctorDummy,
|
||||
this.isLiveCare,
|
||||
this.isLiveCareClinic,
|
||||
this.isDoctorHasPrePostImages,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.nationalityFlagURL,
|
||||
this.nationalityID,
|
||||
this.nationalityName,
|
||||
this.nearestFreeSlot,
|
||||
this.noOfPatientsRate,
|
||||
this.originalClinicID,
|
||||
this.personRate,
|
||||
this.projectDistanceInKiloMeters,
|
||||
this.qR,
|
||||
this.qRString,
|
||||
this.rateNumber,
|
||||
this.serviceID,
|
||||
this.setupID,
|
||||
this.speciality,
|
||||
this.specialityN,
|
||||
this.workingHours,
|
||||
this.decimalDoctorRate,
|
||||
this.projectBottomName,
|
||||
this.projectTopName,
|
||||
this.isHMC,
|
||||
this.region,
|
||||
this.regionArabic,
|
||||
this.regionEnglish,
|
||||
this.regionID,
|
||||
});
|
||||
|
||||
DoctorList.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
) {
|
||||
clinicID = json['ClinicID'];
|
||||
appointmentNo = json['AppointmentNo'];
|
||||
clinicName = json['ClinicName'];
|
||||
doctorTitle = json['DoctorTitle'];
|
||||
iD = json['ID'];
|
||||
name = json['DoctorName'] ?? json['Name'];
|
||||
projectID = json['ProjectID'];
|
||||
projectName = json['ProjectName'];
|
||||
actualDoctorRate = json['ActualDoctorRate'];
|
||||
clinicRoomNo = json['ClinicRoomNo'];
|
||||
date = json['Date'];
|
||||
appointmentDate = json['AppointmentDate'];
|
||||
dayName = json['DayName'];
|
||||
doctorID = json['DoctorID'];
|
||||
doctorImageURL = json['DoctorImageURL'];
|
||||
doctorProfile = json['DoctorProfile'];
|
||||
doctorProfileInfo = json['DoctorProfileInfo'];
|
||||
doctorRate = json['DoctorRate'];
|
||||
gender = json['Gender'];
|
||||
genderDescription = json['GenderDescription'];
|
||||
isAppointmentAllowed = json['IsAppointmentAllowed'];
|
||||
isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall'];
|
||||
isDoctorDummy = json['IsDoctorDummy'];
|
||||
isLiveCare = json['IsLiveCare'];
|
||||
isLiveCareClinic = json['IsLiveCareClinic'];
|
||||
isDoctorHasPrePostImages = json['IsDoctorHasPrePostImages'];
|
||||
latitude = json['Latitude'];
|
||||
longitude = json['Longitude'];
|
||||
nationalityFlagURL = json['NationalityFlagURL'];
|
||||
nationalityID = json['NationalityID'];
|
||||
nationalityName = json['NationalityName'];
|
||||
nearestFreeSlot = json['NearestFreeSlot'];
|
||||
noOfPatientsRate = json['NoOfPatientsRate'];
|
||||
originalClinicID = json['OriginalClinicID'];
|
||||
personRate = json['PersonRate'];
|
||||
projectDistanceInKiloMeters = json['ProjectDistanceInKiloMeters'];
|
||||
qR = json['QR'];
|
||||
qRString = json['QRString'];
|
||||
rateNumber = json['RateNumber'];
|
||||
serviceID = json['ServiceID'];
|
||||
setupID = json['SetupID'];
|
||||
if (json.containsKey('Speciality') && json['Speciality'] != null) speciality = json['Speciality'].cast<String>();
|
||||
if (json.containsKey('SpecialityN') && json['SpecialityN'] != null) specialityN = json['SpecialityN'].cast<String>();
|
||||
workingHours = json['WorkingHours'];
|
||||
decimalDoctorRate = json['DecimalDoctorRate'];
|
||||
projectBottomName = json['ProjectNameBottom'];
|
||||
projectTopName = json['ProjectNameTop'];
|
||||
this.isHMC = json["IsHMC"];
|
||||
this.regionArabic = json['RegionNameN'];
|
||||
this.regionEnglish = json['RegionName'];
|
||||
}
|
||||
|
||||
String? getRegionName(bool isArabic) {
|
||||
if (isArabic) {
|
||||
return regionArabic;
|
||||
}
|
||||
return regionEnglish;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['ClinicID'] = this.clinicID;
|
||||
data['AppointmentNo'] = this.appointmentNo;
|
||||
data['ClinicName'] = this.clinicName;
|
||||
data['DoctorTitle'] = this.doctorTitle;
|
||||
data['ID'] = this.iD;
|
||||
data['Name'] = this.name;
|
||||
data['ProjectID'] = this.projectID;
|
||||
data['ProjectName'] = this.projectName;
|
||||
data['ActualDoctorRate'] = this.actualDoctorRate;
|
||||
data['ClinicRoomNo'] = this.clinicRoomNo;
|
||||
data['Date'] = this.date;
|
||||
data['DayName'] = this.dayName;
|
||||
data['DoctorID'] = this.doctorID;
|
||||
data['DoctorImageURL'] = this.doctorImageURL;
|
||||
data['DoctorProfile'] = this.doctorProfile;
|
||||
data['DoctorProfileInfo'] = this.doctorProfileInfo;
|
||||
data['DoctorRate'] = this.doctorRate;
|
||||
data['Gender'] = this.gender;
|
||||
data['GenderDescription'] = this.genderDescription;
|
||||
data['IsAppointmentAllowed'] = this.isAppointmentAllowed;
|
||||
data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall;
|
||||
data['IsDoctorDummy'] = this.isDoctorDummy;
|
||||
data['IsLiveCare'] = this.isLiveCare;
|
||||
data['IsLiveCareClinic'] = this.isLiveCareClinic;
|
||||
data['IsDoctorHasPrePostImages'] = this.isDoctorHasPrePostImages;
|
||||
data['Latitude'] = this.latitude;
|
||||
data['Longitude'] = this.longitude;
|
||||
data['NationalityFlagURL'] = this.nationalityFlagURL;
|
||||
data['NationalityID'] = this.nationalityID;
|
||||
data['NationalityName'] = this.nationalityName;
|
||||
data['NearestFreeSlot'] = this.nearestFreeSlot;
|
||||
data['NoOfPatientsRate'] = this.noOfPatientsRate;
|
||||
data['OriginalClinicID'] = this.originalClinicID;
|
||||
data['PersonRate'] = this.personRate;
|
||||
data['ProjectDistanceInKiloMeters'] = this.projectDistanceInKiloMeters;
|
||||
data['QR'] = this.qR;
|
||||
data['QRString'] = this.qRString;
|
||||
data['RateNumber'] = this.rateNumber;
|
||||
data['ServiceID'] = this.serviceID;
|
||||
data['SetupID'] = this.setupID;
|
||||
data['Speciality'] = this.speciality;
|
||||
data['SpecialityN'] = this.specialityN;
|
||||
data['WorkingHours'] = this.workingHours;
|
||||
data['DecimalDoctorRate'] = this.decimalDoctorRate;
|
||||
return data;
|
||||
}
|
||||
|
||||
String getProjectCompleteName(){
|
||||
return "${this.projectTopName} ${this.projectBottomName}";
|
||||
}
|
||||
|
||||
String getProjectCompleteNameWithLocale({bool isArabic = false}) {
|
||||
if (isArabic) {
|
||||
return "${this.projectBottomName} ${this.projectTopName}";
|
||||
}
|
||||
return "${this.projectTopName} ${this.projectBottomName}";
|
||||
}
|
||||
}
|
||||
|
||||
class PatientDoctorAppointmentList {
|
||||
String? filterName = "";
|
||||
String? distanceInKMs = "";
|
||||
List<DoctorList>? patientDoctorAppointmentList = [];
|
||||
String? projectTopName = "";
|
||||
String? projectBottomName = "";
|
||||
bool? isHMC;
|
||||
List<HospitalsModel> hospitalList = [];
|
||||
|
||||
PatientDoctorAppointmentList(
|
||||
{this.filterName,
|
||||
this.distanceInKMs,
|
||||
this.projectTopName,
|
||||
this.projectBottomName,
|
||||
DoctorList? patientDoctorAppointment,
|
||||
HospitalsModel? model,
|
||||
this.isHMC = false}) {
|
||||
if (model != null) {
|
||||
hospitalList.add(model);
|
||||
}
|
||||
if (patientDoctorAppointment != null) {
|
||||
patientDoctorAppointmentList!.add(patientDoctorAppointment!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PatientDoctorAppointmentListByRegion {
|
||||
List<PatientDoctorAppointmentList>? hmgDoctorList = [];
|
||||
List<PatientDoctorAppointmentList>? hmcDoctorList = [];
|
||||
int hmcSize = 0;
|
||||
int hmgSize = 0;
|
||||
num distance = double.infinity;
|
||||
num hmgDistance = double.infinity;
|
||||
num hmcDistance = double.infinity;
|
||||
}
|
||||
|
||||
class RegionList {
|
||||
Map<String, PatientDoctorAppointmentListByRegion?>? registeredDoctorMap = {};
|
||||
}
|
||||
@ -0,0 +1,104 @@
|
||||
class HospitalsModel {
|
||||
String? desciption;
|
||||
dynamic desciptionN;
|
||||
dynamic iD;
|
||||
String? legalName;
|
||||
String? legalNameN;
|
||||
String? name;
|
||||
dynamic nameN;
|
||||
String? phoneNumber;
|
||||
String? setupID;
|
||||
dynamic distanceInKilometers;
|
||||
bool? isActive;
|
||||
String? latitude;
|
||||
String? longitude;
|
||||
dynamic mainProjectID;
|
||||
bool? projectOutSA;
|
||||
bool? usingInDoctorApp;
|
||||
bool? isHMC;
|
||||
String? region;
|
||||
String? regionArabic;
|
||||
String? regionEnglish;
|
||||
String? regionID;
|
||||
|
||||
HospitalsModel({
|
||||
this.desciption,
|
||||
this.desciptionN,
|
||||
this.iD,
|
||||
this.legalName,
|
||||
this.legalNameN,
|
||||
this.name,
|
||||
this.nameN,
|
||||
this.phoneNumber,
|
||||
this.setupID,
|
||||
this.distanceInKilometers,
|
||||
this.isActive,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.mainProjectID,
|
||||
this.projectOutSA,
|
||||
this.usingInDoctorApp,
|
||||
this.isHMC,
|
||||
this.region,
|
||||
this.regionArabic,
|
||||
this.regionEnglish,
|
||||
this.regionID,
|
||||
});
|
||||
|
||||
HospitalsModel.fromJson(Map<String, dynamic> json) {
|
||||
desciption = json['Desciption'];
|
||||
desciptionN = json['DesciptionN'];
|
||||
iD = json['ID'];
|
||||
legalName = json['LegalName'];
|
||||
legalNameN = json['LegalNameN'];
|
||||
name = json['Name'];
|
||||
nameN = json['NameN'];
|
||||
phoneNumber = json['PhoneNumber'];
|
||||
setupID = json['SetupID'];
|
||||
distanceInKilometers = json['DistanceInKilometers'];
|
||||
isActive = json['IsActive'];
|
||||
latitude = json['Latitude'];
|
||||
longitude = json['Longitude'];
|
||||
mainProjectID = json['MainProjectID'];
|
||||
projectOutSA = json['ProjectOutSA'];
|
||||
usingInDoctorApp = json['UsingInDoctorApp'];
|
||||
this.isHMC = json["IsHMC"];
|
||||
this.regionArabic = json['RegionNameN'];
|
||||
this.regionEnglish = json['RegionName'];
|
||||
}
|
||||
|
||||
String? getRegionName(bool isArabic) {
|
||||
if (isArabic) {
|
||||
return regionArabic;
|
||||
}
|
||||
return regionEnglish;
|
||||
}
|
||||
|
||||
String? getName(bool isArabic) {
|
||||
if (isArabic) {
|
||||
return "$nameN";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['Desciption'] = this.desciption;
|
||||
data['DesciptionN'] = this.desciptionN;
|
||||
data['ID'] = this.iD;
|
||||
data['LegalName'] = this.legalName;
|
||||
data['LegalNameN'] = this.legalNameN;
|
||||
data['Name'] = this.name;
|
||||
data['NameN'] = this.nameN;
|
||||
data['PhoneNumber'] = this.phoneNumber;
|
||||
data['SetupID'] = this.setupID;
|
||||
data['DistanceInKilometers'] = this.distanceInKilometers;
|
||||
data['IsActive'] = this.isActive;
|
||||
data['Latitude'] = this.latitude;
|
||||
data['Longitude'] = this.longitude;
|
||||
data['MainProjectID'] = this.mainProjectID;
|
||||
data['ProjectOutSA'] = this.projectOutSA;
|
||||
data['UsingInDoctorApp'] = this.usingInDoctorApp;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
|
||||
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
|
||||
class FacilitySelectionItem extends StatelessWidget {
|
||||
final String svgPath;
|
||||
final String title;
|
||||
final String subTitle;
|
||||
|
||||
const FacilitySelectionItem(
|
||||
{super.key,
|
||||
required this.svgPath,
|
||||
required this.subTitle,
|
||||
required this.title});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 20.h,
|
||||
hasShadow: false,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Utils.buildSvgWithAssets(
|
||||
icon: svgPath,
|
||||
width: 32,
|
||||
height: 32,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
SizedBox(height: 16,),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
info,
|
||||
Utils.buildSvgWithAssets(
|
||||
icon: AppAssets.forward_arrow_icon,
|
||||
iconColor: AppColors.blackColor,
|
||||
width: 18,
|
||||
height: 13,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
).paddingAll(16.h),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Widget get info => Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.h,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.blackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
subTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 12.h,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
import 'package:easy_localization/easy_localization.dart'
|
||||
show tr, StringTranslateExtension;
|
||||
import 'package:flutter/cupertino.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/extensions/string_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'
|
||||
show MyAppointmentsViewModel;
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_selection/facility_selection_item.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:provider/provider.dart' show Provider;
|
||||
|
||||
class FacilityTypeSelectionWidget extends StatelessWidget {
|
||||
late MyAppointmentsViewModel myAppointmentsViewModel;
|
||||
late AppointmentViaRegionViewmodel regionalViewModel;
|
||||
final String selectedRegion;
|
||||
|
||||
FacilityTypeSelectionWidget({super.key, required this.selectedRegion});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
|
||||
regionalViewModel = Provider.of<AppointmentViaRegionViewmodel>(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
LocaleKeys.selectFacility.tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 21,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.blackColor,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
LocaleKeys.selectFacilitiesSubTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 24.h),
|
||||
FacilitySelectionItem(
|
||||
svgPath: AppAssets.hmg,
|
||||
title: "HMG".needTranslation,
|
||||
subTitle: LocaleKeys.hospitalsWithCount.tr(namedArgs: {
|
||||
'count':
|
||||
"${myAppointmentsViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmgSize ?? 0}"
|
||||
}),
|
||||
).onPress(
|
||||
() {
|
||||
regionalViewModel.setFacility(FacilitySelection.HMG.name);
|
||||
regionalViewModel.setBottomSheetState(
|
||||
AppointmentViaRegionState.HOSPITAL_SELECTION);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
FacilitySelectionItem(
|
||||
svgPath: AppAssets.hmc,
|
||||
title: "HMC".needTranslation,
|
||||
subTitle: LocaleKeys.medicalCentersWithCount.tr(namedArgs: {
|
||||
'count':
|
||||
"${myAppointmentsViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmcSize ?? 0}"
|
||||
})).onPress(
|
||||
() {
|
||||
regionalViewModel.setFacility(FacilitySelection.HMC.name);
|
||||
regionalViewModel.setBottomSheetState(
|
||||
AppointmentViaRegionState.HOSPITAL_SELECTION);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
import 'package:easy_localization/easy_localization.dart'
|
||||
show tr, StringTranslateExtension;
|
||||
import 'package:flutter/material.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/my_appointments/appointment_via_region_viewmodel.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.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/hospital_bottom_sheet/hospital_list_items.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
|
||||
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class HospitalBottomSheetBody extends StatelessWidget {
|
||||
late MyAppointmentsViewModel appointmentsViewModel;
|
||||
late AppointmentViaRegionViewmodel regionalViewModel;
|
||||
final TextEditingController searchText = TextEditingController();
|
||||
|
||||
HospitalBottomSheetBody({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
appointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
|
||||
regionalViewModel = Provider.of<AppointmentViaRegionViewmodel>(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
LocaleKeys.selectHospital.tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 21,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.blackColor,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
LocaleKeys.selectHospitalSubTitle.tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
TextInputWidget(
|
||||
labelText: LocaleKeys.search.tr(),
|
||||
hintText: "Search Hospital".tr(),
|
||||
controller: searchText,
|
||||
onChange: (value) {
|
||||
appointmentsViewModel.filterHospitalListByString(value, regionalViewModel.selectedRegionId , regionalViewModel.selectedFacilityType ==
|
||||
FacilitySelection.HMG.name);
|
||||
},
|
||||
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: 24.h),
|
||||
// TypeSelectionWidget(
|
||||
// hmcCount: "0",
|
||||
// hmgCount: "0",
|
||||
// ),
|
||||
// SizedBox(height: 21.h),
|
||||
SizedBox(
|
||||
height: MediaQuery.sizeOf(context).height * .4,
|
||||
child: ListView.separated(
|
||||
itemBuilder: (_, index) => HospitalListItem(
|
||||
hospitalData: regionalViewModel.selectedFacilityType ==
|
||||
FacilitySelection.HMG.name
|
||||
? appointmentsViewModel
|
||||
.filteredHospitalList!
|
||||
.registeredDoctorMap![
|
||||
regionalViewModel.selectedRegionId!]!
|
||||
.hmgDoctorList![index]
|
||||
: appointmentsViewModel
|
||||
.filteredHospitalList
|
||||
?.registeredDoctorMap?[
|
||||
regionalViewModel.selectedRegionId!]
|
||||
?.hmcDoctorList?[index],
|
||||
isLocationEnabled: appointmentsViewModel.getLocationStatus(),
|
||||
),
|
||||
separatorBuilder: (_, __) => SizedBox(
|
||||
height: 16.h,
|
||||
),
|
||||
itemCount: (regionalViewModel.selectedFacilityType ==
|
||||
FacilitySelection.HMG.name
|
||||
? (appointmentsViewModel.filteredHospitalList?.registeredDoctorMap?[
|
||||
regionalViewModel.selectedRegionId]?.hmgDoctorList)
|
||||
: (appointmentsViewModel
|
||||
.filteredHospitalList
|
||||
?.registeredDoctorMap?[
|
||||
regionalViewModel.selectedRegionId]?.hmcDoctorList))?.length ??
|
||||
0),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
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/app_state.dart';
|
||||
import 'package:hmg_patient_app_new/core/dependencies.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
||||
import 'package:hmg_patient_app_new/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/doctor_list_api_response.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 HospitalListItem extends StatelessWidget {
|
||||
final PatientDoctorAppointmentList? hospitalData;
|
||||
final bool isLocationEnabled;
|
||||
|
||||
late AppState appState;
|
||||
|
||||
HospitalListItem(
|
||||
{super.key, required this.hospitalData, required this.isLocationEnabled});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
appState = getIt.get<AppState>();
|
||||
return 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: [hospitalName, distanceInfo],
|
||||
),
|
||||
),
|
||||
Utils.buildSvgWithAssets(
|
||||
icon: AppAssets.forward_arrow_icon,
|
||||
iconColor: AppColors.blackColor,
|
||||
width: 18,
|
||||
height: 13,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
],
|
||||
).paddingSymmetrical(16.h, 16.h),
|
||||
);
|
||||
}
|
||||
|
||||
Widget get hospitalName => Row(
|
||||
children: [
|
||||
Utils.buildSvgWithAssets(
|
||||
icon: (hospitalData?.isHMC == true) ? AppAssets.hmc : AppAssets.hmg,
|
||||
).paddingOnly(right: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
hospitalData?.filterName ?? "",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
color: AppColors.blackColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
Widget get distanceInfo => Row(
|
||||
|
||||
children: [
|
||||
Visibility(
|
||||
visible: (hospitalData?.distanceInKMs != "0"),
|
||||
child:
|
||||
|
||||
|
||||
AppCustomChipWidget(
|
||||
labelText:
|
||||
"${hospitalData?.distanceInKMs ?? ""} km".needTranslation,
|
||||
deleteIcon: AppAssets.location_red,
|
||||
deleteIconSize: Size(9, 12),
|
||||
backgroundColor: AppColors.secondaryLightRedColor,
|
||||
textColor: AppColors.errorColor,
|
||||
),
|
||||
|
||||
|
||||
),
|
||||
Visibility(
|
||||
visible: (hospitalData?.distanceInKMs == "0"),
|
||||
child: Row(
|
||||
children: [
|
||||
AppCustomChipWidget(
|
||||
labelText: "Distance not available".needTranslation,
|
||||
textColor: AppColors.blackColor,
|
||||
),
|
||||
SizedBox(width: 8.h,)
|
||||
|
||||
],
|
||||
)),
|
||||
Visibility(
|
||||
visible: !isLocationEnabled,
|
||||
child: AppCustomChipWidget(
|
||||
labelText: "Location turned off".needTranslation,
|
||||
deleteIcon: AppAssets.location_unavailable,
|
||||
deleteIconSize: Size(9, 12),
|
||||
textColor: AppColors.blackColor,
|
||||
)),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.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/facility_selection.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
|
||||
import 'package:provider/provider.dart' show Consumer;
|
||||
|
||||
class TypeSelectionWidget extends StatelessWidget {
|
||||
final String hmcCount;
|
||||
final String hmgCount;
|
||||
|
||||
const TypeSelectionWidget(
|
||||
{super.key, required this.hmcCount, required this.hmgCount});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<MyAppointmentsViewModel>(
|
||||
builder: (_, data, __) => Row(
|
||||
spacing: 8,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
AppCustomChipWidget(
|
||||
labelText: "All Facilities".needTranslation,
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(
|
||||
color: data.currentlySelectedFacility == FacilitySelection.ALL
|
||||
? AppColors.errorColor
|
||||
: AppColors.chipBorderColorOpacity20,
|
||||
width: 1,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
backgroundColor:
|
||||
data.currentlySelectedFacility == FacilitySelection.ALL
|
||||
? AppColors.secondaryLightRedColor
|
||||
: AppColors.whiteColor,
|
||||
textColor: data.currentlySelectedFacility == FacilitySelection.ALL
|
||||
? AppColors.errorColor
|
||||
: AppColors.blackColor,
|
||||
).onPress((){
|
||||
data.setSelectedFacility(FacilitySelection.ALL);
|
||||
}),
|
||||
AppCustomChipWidget(
|
||||
icon: AppAssets.hmg,
|
||||
iconHasColor: false,
|
||||
labelText: "Hospitals".needTranslation,
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(
|
||||
color: data.currentlySelectedFacility == FacilitySelection.HMG
|
||||
? AppColors.errorColor
|
||||
: AppColors.chipBorderColorOpacity20,
|
||||
width: 1,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
backgroundColor:
|
||||
data.currentlySelectedFacility == FacilitySelection.HMG
|
||||
? AppColors.secondaryLightRedColor
|
||||
: AppColors.whiteColor,
|
||||
textColor: data.currentlySelectedFacility == FacilitySelection.HMG
|
||||
? AppColors.errorColor
|
||||
: AppColors.blackColor,
|
||||
).onPress((){
|
||||
data.setSelectedFacility(FacilitySelection.HMG);
|
||||
}),
|
||||
AppCustomChipWidget(
|
||||
icon: AppAssets.hmc,
|
||||
iconHasColor: false,
|
||||
labelText: "Medical Centers".needTranslation,
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(
|
||||
color: data.currentlySelectedFacility == FacilitySelection.HMC
|
||||
? AppColors.errorColor
|
||||
: AppColors.chipBorderColorOpacity20,
|
||||
width: 1,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
backgroundColor:
|
||||
data.currentlySelectedFacility == FacilitySelection.HMC
|
||||
? AppColors.secondaryLightRedColor
|
||||
: AppColors.whiteColor,
|
||||
textColor: data.currentlySelectedFacility == FacilitySelection.HMC
|
||||
? AppColors.errorColor
|
||||
: AppColors.blackColor,
|
||||
).onPress((){
|
||||
data.setSelectedFacility(FacilitySelection.HMC);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors;
|
||||
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
|
||||
|
||||
class RegionListItem extends StatelessWidget {
|
||||
final String title;
|
||||
final String hmcCount;
|
||||
final String hmgCount;
|
||||
final String subTitle;
|
||||
|
||||
const RegionListItem(
|
||||
{super.key,
|
||||
required this.title,
|
||||
required this.subTitle,
|
||||
required this.hmcCount,
|
||||
required this.hmgCount});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 20.h,
|
||||
hasShadow: false,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
header,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 8.h,
|
||||
children: [
|
||||
placesCountItem(
|
||||
AppAssets.hmg, hmgCount, " ${LocaleKeys.hospital.tr()}"),
|
||||
placesCountItem(AppAssets.hmc, hmcCount,
|
||||
" ${LocaleKeys.medicalCenters.tr()}"),
|
||||
],
|
||||
),
|
||||
Utils.buildSvgWithAssets(
|
||||
icon: AppAssets.forward_arrow_icon,
|
||||
iconColor: AppColors.blackColor,
|
||||
width: 18,
|
||||
height: 13,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
).paddingAll(16.h),
|
||||
);
|
||||
}
|
||||
|
||||
Widget placesCountItem(String svgPath, String count, String title) {
|
||||
return AppCustomChipWidget(
|
||||
iconSize: 14,
|
||||
icon: svgPath,
|
||||
iconHasColor: false,
|
||||
richText: RichText(
|
||||
text: TextSpan(
|
||||
text: count,
|
||||
style: TextStyle(
|
||||
fontSize: 12.h,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.blackColor),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: title,
|
||||
style: TextStyle(
|
||||
fontSize: 12.h,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.blackColor))
|
||||
])),
|
||||
);
|
||||
}
|
||||
|
||||
Widget get header => Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.h,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.blackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
subTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 12.h,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.greyTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
import 'dart:async';
|
||||
|
||||
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' show Utils;
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
|
||||
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'
|
||||
show MyAppointmentsViewModel;
|
||||
import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_item.dart'
|
||||
show RegionListItem;
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class RegionBottomSheetBody extends StatefulWidget {
|
||||
|
||||
const RegionBottomSheetBody({super.key});
|
||||
|
||||
@override
|
||||
State<RegionBottomSheetBody> createState() => _RegionBottomSheetBodyState();
|
||||
}
|
||||
|
||||
class _RegionBottomSheetBodyState extends State<RegionBottomSheetBody> {
|
||||
late MyAppointmentsViewModel myAppointmentsViewModel;
|
||||
late AppointmentViaRegionViewmodel regionalViewModel;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
scheduleMicrotask(() {
|
||||
myAppointmentsViewModel.getRegionMappedProjectList();
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context);
|
||||
regionalViewModel = Provider.of<AppointmentViaRegionViewmodel>(context);
|
||||
return Consumer<MyAppointmentsViewModel>(
|
||||
builder: (context, myAppointmentsVM, child) {
|
||||
if (myAppointmentsVM.isRegionListLoading) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height * 0.3,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
child: Center(
|
||||
child: Utils.getLoadingWidget(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.5,
|
||||
child: ListView.separated(
|
||||
itemCount:
|
||||
myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ??
|
||||
0,
|
||||
separatorBuilder: (_, __) {
|
||||
return SizedBox(
|
||||
height: 16.h,
|
||||
);
|
||||
},
|
||||
itemBuilder: (_, index) {
|
||||
String key = myAppointmentsVM
|
||||
.hospitalList?.registeredDoctorMap?.keys
|
||||
.toList()[index] ??
|
||||
'';
|
||||
return RegionListItem(
|
||||
title: key,
|
||||
subTitle: "",
|
||||
hmcCount:
|
||||
"${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmcSize ?? 0}",
|
||||
hmgCount:
|
||||
"${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmgSize ?? 0}",
|
||||
).onPress(() {
|
||||
regionalViewModel.setSelectedRegionId(key);
|
||||
regionalViewModel.setBottomSheetState(AppointmentViaRegionState.TYPE_SELECTION);
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue