e-referral done.

pull/104/head
Sultan khan 2 months ago
parent 5f047e1b6f
commit fb69723a65

@ -221,7 +221,7 @@ class AppDependencies {
);
getIt.registerLazySingleton<HmgServicesViewModel>(
() => HmgServicesViewModel(bookAppointmentsRepo: getIt(), hmgServicesRepo: getIt(), errorHandlerService: getIt()),
() => HmgServicesViewModel(bookAppointmentsRepo: getIt(), hmgServicesRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt()),
);
// Screen-specific VMs Factory

@ -8,6 +8,7 @@ import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/check_activation_e_referral_req_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/req_models/order_update_req_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/search_e_referral_req_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_all_cities_resp_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';
@ -18,6 +19,7 @@ import 'package:provider/provider.dart';
import 'models/req_models/create_e_referral_model.dart';
import 'models/req_models/send_activation_code_ereferral_req_model.dart';
import 'models/resq_models/relationship_type_resp_mode.dart';
import 'models/resq_models/search_e_referral_resp_model.dart';
abstract class HmgServicesRepo {
Future<Either<Failure, GenericApiModel<List<GetCMCAllOrdersResponseModel>>>> getAllComprehensiveCheckupOrders();
@ -56,6 +58,10 @@ abstract class HmgServicesRepo {
Future<Either<Failure, GenericApiModel<String>>> createEReferral(CreateEReferralRequestModel requestModel);
Future<Either<Failure, GenericApiModel<List<SearchEReferralResponseModel>>>> searchEReferral(SearchEReferralRequestModel requestModel);
}
class HmgServicesRepoImp implements HmgServicesRepo {
@ -757,4 +763,58 @@ class HmgServicesRepoImp implements HmgServicesRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<SearchEReferralResponseModel>>>> searchEReferral(SearchEReferralRequestModel requestBody) async {
try {
GenericApiModel<List<SearchEReferralResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getEReferrals,
body: requestBody.toJson(),
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
loggerService.logError("EReferral Services API Failed: $error, Status: $statusCode");
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
List<SearchEReferralResponseModel> searchReferral = [];
if (response['List_EReferrals'] != null && response['List_EReferrals'] is List) {
final servicesList = response['List_EReferrals'] as List;
for (var serviceJson in servicesList) {
if (serviceJson is Map<String, dynamic>) {
searchReferral.add(SearchEReferralResponseModel.fromJson(serviceJson));
}
}
}
apiResponse = GenericApiModel<List<SearchEReferralResponseModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: errorMessage,
data: searchReferral,
);
} catch (e) {
loggerService.logError("Error parsing E-Referral services: ${e.toString()}");
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
log("Unknown error in Search Referral: ${e.toString()}");
return Left(UnknownFailure(e.toString()));
}
}
}

@ -1,16 +1,20 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/create_e_referral_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/req_models/order_update_req_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/search_e_referral_req_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/send_activation_code_ereferral_req_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get_all_cities_resp_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/features/hmg_services/models/resq_models/search_e_referral_resp_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'models/req_models/check_activation_e_referral_req_model.dart';
import 'models/resq_models/relationship_type_resp_mode.dart';
@ -19,8 +23,9 @@ class HmgServicesViewModel extends ChangeNotifier {
final HmgServicesRepo hmgServicesRepo;
final BookAppointmentsRepo bookAppointmentsRepo;
final ErrorHandlerService errorHandlerService;
final NavigationService navigationService;
HmgServicesViewModel({required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService});
HmgServicesViewModel({required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService});
bool isCmcOrdersLoading = false;
bool isCmcServicesLoading = false;
@ -51,8 +56,9 @@ class HmgServicesViewModel extends ChangeNotifier {
List<GetAllRelationshipTypeResponseModel> relationTypes =[];
List<GetAllCitiesResponseModel> getAllCitiesList =[];
List<SearchEReferralResponseModel> searchReferralList =[];
Future<void> getOrdersList() async {
Future<void> getOrdersList() async {}
// HHC multiple services selection
List<GetCMCServicesResponseModel> selectedHhcServices = [];
@ -702,4 +708,84 @@ class HmgServicesViewModel extends ChangeNotifier {
);
}
Future<void> searchEReferral({
required SearchEReferralRequestModel requestModel,
Function(dynamic)? onSuccess,
Function(String)? onError,
}) async {
notifyListeners();
final result = await hmgServicesRepo.searchEReferral(requestModel);
result.fold(
(failure) async {
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
if (apiResponse.messageStatus == 1) {
searchReferralList = apiResponse.data ?? [];
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
} else {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? 'Unknown error');
}
}
},
);
}
Future<void> navigateToOTPScreen(
{required OTPTypeEnum otpTypeEnum,
required String phoneNumber,
required String loginToken,
required Function onSuccess,
}) async {
navigationService.pushToOtpScreen(
phoneNumber: phoneNumber,
isFormFamilyFile: false,
checkActivationCode: (int activationCode) async {
checkEReferralActivationCode(
requestModel: CheckActivationCodeForEReferralRequestModel(
logInTokenID: loginToken,
activationCode: activationCode.toString(),
),
onSuccess: (GenericApiModel response) {
onSuccess();
},
onError: (String errorMessage) {
print(errorMessage);
},
);
},
onResendOTPPressed: (String phoneNumber) async {
// await sendActivationCode(
// otpTypeEnum: otpTypeEnum,
// phoneNumber: phoneNumberController.text,
// nationalIdOrFileNumber: nationalIdController.text,
// isForRegister: isComingFromRegister,
// isComingFromResendOTP: true,
// payload: payload,
// isFormFamilyFile: isFormFamilyFile,
// isExcludedUser: isExcludedUser,
// responseID: responseID,
// );
},
);
}
}

@ -0,0 +1,60 @@
class SearchEReferralRequestModel {
String? patientMobileNumber;
double? versionID;
int? channel;
int? languageID;
String? iPAdress;
String? generalid;
int? patientOutSA;
dynamic sessionID;
bool? isDentalAllowedBackend;
int? deviceTypeID;
int? referralNumber;
String? identificationNo;
SearchEReferralRequestModel(
{this.patientMobileNumber,
this.versionID,
this.channel,
this.languageID,
this.iPAdress,
this.generalid,
this.patientOutSA,
this.sessionID,
this.isDentalAllowedBackend,
this.deviceTypeID,
this.referralNumber,
this.identificationNo});
SearchEReferralRequestModel.fromJson(Map<String, dynamic> json) {
patientMobileNumber = json['PatientMobileNumber'];
versionID = json['VersionID'];
channel = json['Channel'];
languageID = json['LanguageID'];
iPAdress = json['IPAdress'];
generalid = json['generalid'];
patientOutSA = json['PatientOutSA'];
sessionID = json['SessionID'];
isDentalAllowedBackend = json['isDentalAllowedBackend'];
deviceTypeID = json['DeviceTypeID'];
referralNumber = json['ReferralNumber'];
identificationNo = json['IdentificationNo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['PatientMobileNumber'] = this.patientMobileNumber;
data['VersionID'] = this.versionID;
data['Channel'] = this.channel;
data['LanguageID'] = this.languageID;
data['IPAdress'] = this.iPAdress;
data['generalid'] = this.generalid;
data['PatientOutSA'] = this.patientOutSA;
data['SessionID'] = this.sessionID;
data['isDentalAllowedBackend'] = this.isDentalAllowedBackend;
data['DeviceTypeID'] = this.deviceTypeID;
data['ReferralNumber'] = this.referralNumber;
data['IdentificationNo'] = this.identificationNo;
return data;
}
}

@ -0,0 +1,161 @@
import 'dart:convert';
class SearchEReferralResponseModel {
dynamic acceptedBrachCode;
dynamic acceptedBranchName;
dynamic acceptedBranchNameAr;
dynamic channel;
dynamic identityCardAttachment;
String? identityNumber;
dynamic insuranceCardAttachment;
bool? isInsuredPatient;
List<MedicalReportAttachment>? medicalReportAttachment;
String? otherRelationship;
String? patientContactNo;
int? patientId;
String? patientName;
dynamic preferredBranchCode;
dynamic preferredBranchName;
String? referralDate;
int? referralNumber;
RelationshipType? relationshipType;
String? requesterContactNo;
String? requesterName;
String? status;
String? statusAr;
SearchEReferralResponseModel({
this.acceptedBrachCode,
this.acceptedBranchName,
this.acceptedBranchNameAr,
this.channel,
this.identityCardAttachment,
this.identityNumber,
this.insuranceCardAttachment,
this.isInsuredPatient,
this.medicalReportAttachment,
this.otherRelationship,
this.patientContactNo,
this.patientId,
this.patientName,
this.preferredBranchCode,
this.preferredBranchName,
this.referralDate,
this.referralNumber,
this.relationshipType,
this.requesterContactNo,
this.requesterName,
this.status,
this.statusAr,
});
factory SearchEReferralResponseModel.fromRawJson(String str) => SearchEReferralResponseModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory SearchEReferralResponseModel.fromJson(Map<String, dynamic> json) => SearchEReferralResponseModel(
acceptedBrachCode: json["AcceptedBrachCode"],
acceptedBranchName: json["AcceptedBranchName"],
acceptedBranchNameAr: json["AcceptedBranchNameAr"],
channel: json["Channel"],
identityCardAttachment: json["IdentityCardAttachment"],
identityNumber: json["IdentityNumber"],
insuranceCardAttachment: json["InsuranceCardAttachment"],
isInsuredPatient: json["IsInsuredPatient"],
medicalReportAttachment: json["MedicalReportAttachment"] == null ? [] : List<MedicalReportAttachment>.from(json["MedicalReportAttachment"]!.map((x) => MedicalReportAttachment.fromJson(x))),
otherRelationship: json["OtherRelationship"],
patientContactNo: json["PatientContactNo"],
patientId: json["PatientId"],
patientName: json["PatientName"],
preferredBranchCode: json["PreferredBranchCode"],
preferredBranchName: json["PreferredBranchName"],
referralDate: json["ReferralDate"],
referralNumber: json["ReferralNumber"],
relationshipType: json["RelationshipType"] == null ? null : RelationshipType.fromJson(json["RelationshipType"]),
requesterContactNo: json["RequesterContactNo"],
requesterName: json["RequesterName"],
status: json["Status"],
statusAr: json["StatusAr"],
);
Map<String, dynamic> toJson() => {
"AcceptedBrachCode": acceptedBrachCode,
"AcceptedBranchName": acceptedBranchName,
"AcceptedBranchNameAr": acceptedBranchNameAr,
"Channel": channel,
"IdentityCardAttachment": identityCardAttachment,
"IdentityNumber": identityNumber,
"InsuranceCardAttachment": insuranceCardAttachment,
"IsInsuredPatient": isInsuredPatient,
"MedicalReportAttachment": medicalReportAttachment == null ? [] : List<dynamic>.from(medicalReportAttachment!.map((x) => x.toJson())),
"OtherRelationship": otherRelationship,
"PatientContactNo": patientContactNo,
"PatientId": patientId,
"PatientName": patientName,
"PreferredBranchCode": preferredBranchCode,
"PreferredBranchName": preferredBranchName,
"ReferralDate": referralDate,
"ReferralNumber": referralNumber,
"RelationshipType": relationshipType?.toJson(),
"RequesterContactNo": requesterContactNo,
"RequesterName": requesterName,
"Status": status,
"StatusAr": statusAr,
};
}
class MedicalReportAttachment {
String? base64String;
String? fileName;
MedicalReportAttachment({
this.base64String,
this.fileName,
});
factory MedicalReportAttachment.fromRawJson(String str) => MedicalReportAttachment.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory MedicalReportAttachment.fromJson(Map<String, dynamic> json) => MedicalReportAttachment(
base64String: json["Base64String"],
fileName: json["FileName"],
);
Map<String, dynamic> toJson() => {
"Base64String": base64String,
"FileName": fileName,
};
}
class RelationshipType {
int? id;
String? text;
String? textAr;
String? textEn;
RelationshipType({
this.id,
this.text,
this.textAr,
this.textEn,
});
factory RelationshipType.fromRawJson(String str) => RelationshipType.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory RelationshipType.fromJson(Map<String, dynamic> json) => RelationshipType(
id: json["ID"],
text: json["Text"],
textAr: json["Text_Ar"],
textEn: json["Text_En"],
);
Map<String, dynamic> toJson() => {
"ID": id,
"Text": text,
"Text_Ar": textAr,
"Text_En": textEn,
};
}

@ -9,7 +9,10 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/
class ReferralFormData {
String requesterName = '';
String requesterPhone = '';
String searchPhone ='';
CountryEnum countryEnum = CountryEnum.saudiArabia;
CountryEnum patientCountryEnum = CountryEnum.saudiArabia;
GetAllRelationshipTypeResponseModel? relationship;
String otherRelationshipName = '';
@ -39,4 +42,7 @@ class FormValidationErrors {
String? medicalReport;
String? branch;
String? insuredDocument;
String? searchValue;
String? searchPhone;
}

@ -10,12 +10,12 @@ class ReferralValidator {
errors.requesterName = 'Referral requester name is required';
}
if (formData.requesterPhone.trim().isEmpty) {
errors.requesterPhone = 'Phone number is required';
} else if (formData.countryEnum.countryCode == '966' &&
!_isValidSaudiPhone(formData.requesterPhone)) {
errors.requesterPhone = 'Please enter a valid Saudi phone number (5xxxxxxxx)';
}
// if (formData.requesterPhone.trim().isEmpty) {
// errors.requesterPhone = 'Phone number is required';
// } else if (formData.countryEnum.countryCode == '966' &&
// !_isValidSaudiPhone(formData.requesterPhone)) {
// errors.requesterPhone = 'Please enter a valid Saudi phone number (5xxxxxxxx)';
// }
if (formData.relationship == null) {
errors.relationship = 'Please select a relationship';

@ -16,7 +16,16 @@ class ReferralFormManager extends ChangeNotifier {
ReferralFormData get formData => _formData;
FormValidationErrors get errors => _errors;
// Field-specific update methods that don't notify listeners immediately
int _searchCriteria = 0; // 0 = Identification Number, 1 = Referral Number
String? _searchValue;
String? _searchPhone;
// Getters
int get searchCriteria => _searchCriteria;
String? get searchValue => _searchValue;
String? get searchPhone => _searchPhone;
void updateRequesterName(String value) {
_formData.requesterName = value;
_clearError('requesterName');
@ -30,9 +39,13 @@ class ReferralFormManager extends ChangeNotifier {
void updateCountryEnum(CountryEnum value) {
_formData.countryEnum = value;
}
void updatePatientCountryEnum(CountryEnum value) {
_formData.patientCountryEnum = value;
}
void updateRelationship(GetAllRelationshipTypeResponseModel? value) {
_formData.relationship = value;
notifyListeners();
_clearError('relationship');
}
@ -59,6 +72,7 @@ class ReferralFormManager extends ChangeNotifier {
void updatePatientCity(GetAllCitiesResponseModel? value) {
_formData.patientCity = value;
_clearError('patientCity');
notifyListeners();
}
void updateBranch(HospitalsModel? value) {
@ -83,6 +97,7 @@ class ReferralFormManager extends ChangeNotifier {
if (index >= 0 && index < _formData.medicalReportImages.length) {
_formData.medicalReportImages.removeAt(index);
}
notifyListeners();
}
void addInsuranceDocument(EReferralAttachment attachment) {
@ -94,8 +109,11 @@ class ReferralFormManager extends ChangeNotifier {
if (index >= 0 && index < _formData.insuredPatientImages.length) {
_formData.insuredPatientImages.removeAt(index);
}
notifyListeners();
}
// Error management
void setErrors(FormValidationErrors newErrors) {
_errors.requesterName = newErrors.requesterName;
@ -203,4 +221,70 @@ class ReferralFormManager extends ChangeNotifier {
notifyListeners();
}
}
void updateSearchCriteria(int criteria) {
_searchCriteria = criteria;
_errors.searchValue = _validateSearchValue();
notifyListeners();
}
void updateSearchValue(String value) {
_searchValue = value;
_errors.searchValue = _validateSearchValue();
}
void updateSearchPhone(String value) {
_searchPhone = value;
_errors.searchPhone = _validateSearchPhone();
}
String? _validateSearchValue() {
if (_searchValue == null || _searchValue!.isEmpty) {
return _searchCriteria == 0
? 'Identification Number is required'
: 'Referral Number is required';
}
if (_searchCriteria == 0) {
// Validate identification number format
if (!_isValidIdentificationNumber(_searchValue!)) {
return 'Please enter a valid identification number';
}
} else {
// Validate referral number format
if (!_isValidReferralNumber(_searchValue!)) {
return 'Please enter a valid referral number';
}
}
return null;
}
bool _isValidIdentificationNumber(String value) {
// Add your identification number validation logic
return value.isNotEmpty; // Basic validation
}
bool _isValidReferralNumber(String value) {
// Add your referral number validation logic
return value.isNotEmpty; // Basic validation
}
void validateSearchForm() {
_errors.searchValue = _validateSearchValue();
_errors.searchPhone = _validateSearchPhone();
notifyListeners();
}
String? _validateSearchPhone() {
if (_searchPhone == null || _searchPhone!.isEmpty) {
return 'Phone number is required';
}
return null;
}
bool get isSearchFormInValid {
return (
_errors.searchValue != null &&
_errors.searchValue!.isNotEmpty ||
_errors.searchPhone != null &&
_errors.searchPhone!.isNotEmpty);
}
}

@ -1,103 +0,0 @@
import 'dart:ui';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.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/presentation/e_referral/new_e_referral.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/search_e_referral.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/custom_tab_bar.dart';
import 'package:provider/provider.dart';
class EReferralPage extends StatefulWidget {
const EReferralPage({super.key});
@override
_EReferralPageState createState() => _EReferralPageState();
}
class _EReferralPageState extends State<EReferralPage> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
bool isNewReferral = true;
VoidCallback? onNextStep;
int _currentPageIndex = 0;
int activeTabIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: "E Referral".needTranslation,
child: Consumer<ContactUsViewModel>(builder: (context, contactUsVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
CustomTabBar(
activeTextColor: AppColors.primaryRedColor,
activeBackgroundColor: AppColors.primaryRedColor.withValues(alpha: .1),
tabs: [
CustomTabBarModel(null, "New Referral".needTranslation),
CustomTabBarModel(null, "Search Referral".needTranslation),
],
onTabChange: (index) {
activeTabIndex =index;
setState(() {
});
},
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 24.h),
activeTabIndex ==0 ? NewReferralPage(
onNextStep: (nextStep) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
onNextStep = nextStep;
});
});
},
onStepChanged: (int value) {
setState(() {
_currentPageIndex = value;
});
},
) :
SearchEReferralPage(
onNextStep: (onNextStep) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
onNextStep = onNextStep;
});
});
},
)
],
);
}),
),
bottomNavigationBar: Padding(
padding: EdgeInsets.all(20.h),
child: CustomButton(
text:activeTabIndex == 0 ? _currentPageIndex >= 2 ? LocaleKeys.submit.tr() : LocaleKeys.next.tr() : LocaleKeys.search.tr(),
onPressed: onNextStep ?? () {},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
)),
);
}
}

@ -0,0 +1,310 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.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/core/utils/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/hmg_services/models/resq_models/search_e_referral_resp_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';
import 'package:smooth_corner/smooth_corner.dart';
class SearchResultPage extends StatefulWidget {
const SearchResultPage({super.key});
@override
_SearchResultPageState createState() => _SearchResultPageState();
}
class _SearchResultPageState extends State<SearchResultPage> {
HmgServicesViewModel? hmgServicesVM;
String _selectedFilter = 'All';
@override
void initState() {
hmgServicesVM = context.read<HmgServicesViewModel>();
super.initState();
}
@override
Widget build(BuildContext context) {
return CollapsingListView(
title: "Search Result".needTranslation,
child: Column(
children: [
// List of referrals
ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: hmgServicesVM?.searchReferralList.length,
itemBuilder: (context, index) {
return _buildReferralCard(hmgServicesVM!.searchReferralList[index]);
},
),
],
),
);
}
Widget _buildReferralCard(SearchEReferralResponseModel referral) {
return SmoothCard(
borderRadius: BorderRadius.circular(16.h),
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
color: AppColors.whiteColor,
child: Padding(
padding: EdgeInsets.all(16.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
'Referral No ${referral.referralNumber}'.needTranslation.toText18(isBold: true, color: AppColors.textColor),
Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: _getStatusColor(referral.status!),
borderRadius: BorderRadius.circular(20),
),
child:
referral.status!.toText12(color: AppColors.whiteColor,
// style: TextStyle(
// color: Colors.white,
// fontSize: 12,
// fontWeight: FontWeight.w500,
// ),
),
),
],
),
SizedBox(height: 16),
// Patient information
Row(
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: AppColors.lightGrayBGColor,
shape: BoxShape.circle,
),
child: Icon(
Icons.person,
color: AppColors.lightGrayBGColor,
size: 30,
),
),
SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//Text(
referral.patientName!.toText16(isBold: true, color: AppColors.textColor),
// style: TextStyle(
// fontSize: 16,
// fontWeight: FontWeight.bold,
// ),
// ),
SizedBox(height: 4),
// Text(
'ID: ${referral.identityNumber}'.toText14(color: AppColors.greyTextColor),
// style: TextStyle(
// color: Colors.grey[600],
// ),
// ),
],
),
),
],
),
SizedBox(height: 16),
// Details row
Row(
children: [
_buildDetailItem(
Icons.phone,
referral.patientContactNo!,
),
SizedBox(width: 16),
_buildDetailItem(Icons.calendar_today, Utils.getDayMonthYearDateFormatted(DateUtil.convertStringToDateNoTimeZone(referral.referralDate!))),
],
),
SizedBox(height: 16),
// Requester information
Container(
padding: EdgeInsets.all(5.h),
decoration: BoxDecoration(
color: AppColors.lightGrayBGColor,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(
Icons.person_outline,
color: Colors.grey[600],
size: 20,
),
SizedBox(width: 8),
//Text(
'Requester: ${referral.requesterName}'.toText14(),
// style: TextStyle(
// color: Colors.grey[700],
// ),
// ),
SizedBox(width: 16),
Icon(
Icons.phone,
color: Colors.grey[600],
size: 16,
),
SizedBox(width: 4),
// Text(
referral.requesterContactNo!.toText14(),
// style: TextStyle(
// color: Colors.grey[700],
// ),
// ),
],
),
),
SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
Icons.group,
color: Colors.grey[600],
size: 16,
),
SizedBox(width: 4),
//Text(
'Relationship: ${referral.relationshipType?.text}'.toText14(color:AppColors.greyTextColor),
// style: TextStyle(
// color: Colors.grey[700],
// fontSize: 14,
// ),
// ),
],
),
Row(
children: [
Icon(
Icons.attach_file,
color: Colors.grey[600],
size: 16,
),
SizedBox(width: 4),
// Text(
'${referral.medicalReportAttachment?.length} file(s)'.toText14(color:AppColors.greyTextColor),
// style: TextStyle(
// color: Colors.grey[700],
// fontSize: 14,
// ),
// ),
],
),
],
),
SizedBox(height: 16),
// Action buttons
],
),
),
);
}
Widget _buildDetailItem(IconData icon, String text) {
return Row(
children: [
Icon(
icon,
color: Colors.grey[600],
size: 16,
),
SizedBox(width: 4),
// Text(
text.toText14(color: AppColors.greyTextColor),
// style: TextStyle(
// color: Colors.grey[700],
// ),
// ),
],
);
}
Color _getStatusColor(String status) {
switch (status) {
case 'Pending':
return AppColors.alertColor;
case 'Completed':
return AppColors.bgGreenColor;
case 'Rejected':
return AppColors.primaryRedColor;
default:
return AppColors.lightGrayColor;
}
}
void _showFilterOptions() {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Filter Results',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
_buildFilterOption('All'),
_buildFilterOption('Pending'),
_buildFilterOption('Completed'),
_buildFilterOption('Rejected'),
],
),
);
},
);
}
Widget _buildFilterOption(String filter) {
return ListTile(
leading: Icon(
_selectedFilter == filter ? Icons.radio_button_checked : Icons.radio_button_off,
color: _selectedFilter == filter ? Colors.blue[700] : Colors.grey,
),
title: Text(filter),
onTap: () {
setState(() {
_selectedFilter = filter;
});
Navigator.pop(context);
},
);
}
}

@ -1,27 +1,35 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.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/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.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/create_e_referral_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/e_referral_form_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/search_e_referral.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/widget/e-referral_otp.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/widget/e_referral_other_details.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/widget/e_referral_patient_info.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/widget/e_referral_requester_form.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/widget/e_referral_stepper.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:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/stepper/stepper_widget.dart';
import 'package:provider/provider.dart';
import 'e-referral_validator.dart';
import 'e_referral_form_manager.dart';
class NewReferralPage extends StatefulWidget {
final Function(VoidCallback) onNextStep;
final Function(int) onStepChanged;
const NewReferralPage({
super.key,
required this.onNextStep,
required this.onStepChanged,
});
@override
@ -33,17 +41,14 @@ class _NewReferralPageState extends State<NewReferralPage> {
final ReferralFormManager _formManager = ReferralFormManager(); // Use manager
int _currentStep = 0;
final List<String> _steps = [
'Requester Info',
'Patient Information',
'Other details'
];
double widthOfOneState = ((ResponsiveExtension.screenWidth) / 3) - (20.h);
final List<String> _steps = ['Requester Info', 'Patient Information', 'Other details'];
@override
void initState() {
super.initState();
_loadData();
widget.onNextStep(_handleNextStep);
}
void _handleNextStep() {
@ -52,8 +57,7 @@ class _NewReferralPageState extends State<NewReferralPage> {
if (_validateCurrentStep()) {
OTPService.openOTPScreen(
context: context,
phoneNumber: _formManager.formData.requesterPhone ?? '',
countryEnum: _formManager.formData.countryEnum,
formManager: _formManager,
onSuccess: _proceedToNextStep,
);
}
@ -99,44 +103,45 @@ class _NewReferralPageState extends State<NewReferralPage> {
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
setState(() {
_currentStep++;
});
widget.onStepChanged(_currentStep);
// setState(() {
_currentStep++;
// });
// widget.onStepChanged(_currentStep);
}
void _submitReferral() {
CreateEReferralRequestModel createReferrralRequestModel =
CreateEReferralRequestModel(
CreateEReferralRequestModel createReferralRequestModel = CreateEReferralRequestModel(
isInsuredPatient: _formManager.formData.isPatientInsured,
cityCode: _formManager.formData.patientCity!.iD!.toString(),
cityName: _formManager.formData.patientCity!.description,
cityCode: _formManager.formData.patientCity!.iD!.toString(),
cityName: _formManager.formData.patientCity!.description,
requesterName: _formManager.formData.requesterName,
requesterContactNo: _formManager.formData.requesterPhone,
requesterContactNo: _formManager.formData.countryEnum.countryCode + _formManager.formData.requesterPhone,
requesterRelationship: _formManager.formData.relationship?.iD,
otherRelationship: _formManager.formData.relationship!.iD.toString(),
fullName: _formManager.formData.patientName,
identificationNo: int.tryParse(_formManager.formData!.patientIdentification ?? '0'),
patientMobileNumber: _formManager.formData.patientPhone,
patientMobileNumber: _formManager.formData.patientCountryEnum.countryCode + _formManager.formData.patientPhone,
preferredBranchCode: _formManager.formData.branch!.iD,
medicalReportAttachment: _formManager.formData.medicalReportImages,
insuranceCardAttachment: _formManager.formData.insuredPatientImages,
preferredBranchName: _formManager.formData.branch!.desciption
);
preferredBranchName: _formManager.formData.branch!.desciption);
final hmgServicesVM = context.read<HmgServicesViewModel>();
LoaderBottomSheet.showLoader();
hmgServicesVM.createEReferral(
requestModel: createReferrralRequestModel,
onSuccess: (response) {
print("E-Referral submitted successfully");
requestModel: createReferralRequestModel,
onSuccess: (GenericApiModel response) {
showSuccessBottomSheet(int.parse(response.data), hmgServicesVM);
LoaderBottomSheet.hideLoader();
},
onError: (errorMessage) {
// Handle error (e.g., show error message)
print(errorMessage);
},
);
}
void _loadData() {
@ -152,32 +157,107 @@ class _NewReferralPageState extends State<NewReferralPage> {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: _formManager,
child: SizedBox(
height: MediaQuery.of(context).size.height,
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: "E Referral".needTranslation,
isClose: false,
search: () async {
await Navigator.of(context).push(
CustomPageRoute(
page: SearchEReferralPage(),
fullScreenDialog: true,
direction: AxisDirection.down,
),
);
},
bottomChild: Container(
color: Colors.white,
padding: EdgeInsets.all(ResponsiveExtension(20).h),
child: CustomButton(
text: _currentStep <=1 ? LocaleKeys.next.tr() : LocaleKeys.submit.tr(),
// icon: AppAssets.search_icon,
iconColor: Colors.white,
onPressed: () => {_handleNextStep()},
),
),
child: ChangeNotifierProvider.value(
value: _formManager,
child: SizedBox(
height: ResponsiveExtension.screenHeight * 0.65,
child: Column(
children: [
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(3, (index) {
if (_currentStep == index) {
return StepperWidget(widthOfOneState, AppColors.primaryRedColor, true, 4.h);
} else {
return StepperWidget(widthOfOneState, AppColors.greyLightColor, false, 4.h);
}
})),
Expanded(
child: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
onPageChanged: (index) => {
// setState(() => _currentStep = index)
},
children: [
RequesterFormStep(),
PatientInformationStep(),
OtherDetailsStep(),
],
)),
],
)),
)));
// );
}
showSuccessBottomSheet(int requestId, HmgServicesViewModel hmgServicesViewModel) {
return showCommonBottomSheetWithoutHeight(
context,
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
children: [
const SizedBox(height: 8),
ProgressStepperWidget(
currentStep: _currentStep,
steps: _steps,
Utils.getSuccessWidget(loadingText: "Your Referral has been created Successfully.".needTranslation),
Row(
children: [
"Here is your Referral #: ".needTranslation.toText14(
color: AppColors.textColorLight,
weight: FontWeight.w500,
),
SizedBox(width: 4.w),
("$requestId").toText16(isBold: true),
],
),
Expanded(
child: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
onPageChanged: (index) => setState(() => _currentStep = index),
children: [
RequesterFormStep(),
PatientInformationStep(),
OtherDetailsStep(),
],
),
SizedBox(height: 24.h),
Row(
children: [
Expanded(
child: CustomButton(
height: 56.h,
text: LocaleKeys.ok.tr(),
onPressed: () {
context.pop();
context.pop();
_currentStep =0;
},
textColor: AppColors.whiteColor,
),
),
],
),
],
),
),
isCloseButtonVisible: false,
isDismissible: false,
isFullScreen: false,
);
}
}
}

@ -1,19 +1,24 @@
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/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/create_e_referral_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/req_models/search_e_referral_req_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/widget/search_e_referral_form.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/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'e-referral_validator.dart';
import 'e_referral_form_manager.dart';
import 'e_referral_search_result.dart';
class SearchEReferralPage extends StatefulWidget {
final Function(VoidCallback) onNextStep;
const SearchEReferralPage({
super.key,
required this.onNextStep,
});
@override
@ -21,78 +26,95 @@ class SearchEReferralPage extends StatefulWidget {
}
class _SearchEReferralPageState extends State<SearchEReferralPage> {
final PageController _pageController = PageController();
final ReferralFormManager _formManager = ReferralFormManager(); // Use manager
int _currentStep = 0;
// final PageController _pageController = PageController();
final ReferralFormManager _formManager = ReferralFormManager();
late HmgServicesViewModel hmgServicesVM;
@override
void initState() {
super.initState();
_loadData();
widget.onNextStep(_handleNextStep);
}
void _handleNextStep() {
_searchReferral();
void _handleSearch() {
_formManager.validateSearchForm();
if (!_formManager.isSearchFormInValid) {
_searchReferral();
}
}
void _searchReferral() {
SearchEReferralRequestModel searchEReferralReq;
CreateEReferralRequestModel createReferrralRequestModel =
CreateEReferralRequestModel(
isInsuredPatient: _formManager.formData.isPatientInsured,
cityCode: _formManager.formData.patientCity!.iD!.toString(),
cityName: _formManager.formData.patientCity!.description,
requesterName: _formManager.formData.requesterName,
requesterContactNo: _formManager.formData.requesterPhone,
requesterRelationship: _formManager.formData.relationship?.iD,
otherRelationship: _formManager.formData.relationship!.iD.toString(),
fullName: _formManager.formData.patientName,
identificationNo: int.tryParse(_formManager.formData!.patientIdentification ?? '0'),
patientMobileNumber: _formManager.formData.patientPhone,
preferredBranchCode: _formManager.formData.branch!.iD,
medicalReportAttachment: _formManager.formData.medicalReportImages,
insuranceCardAttachment: _formManager.formData.insuredPatientImages,
preferredBranchName: _formManager.formData.branch!.desciption
);
if (_formManager.searchCriteria == 0) {
searchEReferralReq = SearchEReferralRequestModel(
identificationNo: _formManager.searchValue,
patientMobileNumber: _formManager.formData.countryEnum.countryCode + _formManager.searchPhone!,
referralNumber: 0,
);
} else {
final hmgServicesVM = context.read<HmgServicesViewModel>();
hmgServicesVM.createEReferral(
requestModel: createReferrralRequestModel,
onSuccess: (response) {
print("E-Referral submitted successfully");
},
onError: (errorMessage) {
// Handle error (e.g., show error message)
print(errorMessage);
searchEReferralReq = SearchEReferralRequestModel(referralNumber: int.parse(_formManager.searchValue!), patientMobileNumber: _formManager.formData.patientPhone, identificationNo: '');
}
hmgServicesVM = context.read<HmgServicesViewModel>();
LoaderBottomSheet.showLoader();
hmgServicesVM.searchEReferral(
requestModel: searchEReferralReq,
onSuccess: (response) async {
LoaderBottomSheet.hideLoader();
await Navigator.of(context).push(
CustomPageRoute(
page: SearchResultPage(),
fullScreenDialog: true,
direction: AxisDirection.down,
),
);
},
);
);
}
void _loadData() {
WidgetsBinding.instance.addPostFrameCallback((_) {});
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: _formManager,
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
Expanded(
child:
return CollapsingListView(
title: "Search E-Referral".needTranslation,
isClose: true,
bottomChild: Container(
color: Colors.white,
padding: EdgeInsets.all(ResponsiveExtension(20).h),
child: CustomButton(
text: LocaleKeys.search.tr(),
icon: AppAssets.search_icon,
iconColor: Colors.white,
onPressed: () => {
_handleSearch()
},
),
),
child: ChangeNotifierProvider.value(
value: _formManager,
child: Column(
children: [
_buildHeader(),
SearchEReferralFormForm(),
),
],
),
],
)),
);
}
Widget _buildHeader() {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [SizedBox(height: 8), 'Please enter the required information to search for an e-referral'.needTranslation.toText12()],
),
);
}
}
}

@ -1,8 +1,17 @@
// services/otp_service.dart
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/enums.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_form_manager.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
@ -14,92 +23,101 @@ import 'package:hmg_patient_app_new/features/authentication/widgets/otp_verifica
class OTPService {
static void openOTPScreen({
required BuildContext context,
required String phoneNumber,
required CountryEnum countryEnum,
required ReferralFormManager formManager,
required Function onSuccess,
}) {
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
hmgServicesViewModel.eReferralSendActivationCode(
requestModel: SendActivationCodeForEReferralRequestModel(
patientMobileNumber: int.parse(phoneNumber),
zipCode: countryEnum.countryCode,
patientOutSA: countryEnum.countryCode == '966' ? 0 : 1,
),
onSuccess: (GenericApiModel response) {
_showOTPVerificationSheet(
context: context,
phoneNumber: phoneNumber,
loginTokenID: response.data,
onSuccess: onSuccess,
);
},
onError: (String errorMessage) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(errorMessage))
);
},
);
_showOTPVerificationSheet(context: context, formManager: formManager , onSuccess: onSuccess);
//
// LoaderBottomSheet.showLoader();
}
static void _showOTPVerificationSheet({
required BuildContext context,
required String phoneNumber,
required String loginTokenID,
required ReferralFormManager formManager,
required Function onSuccess,
}) {
showCommonBottomSheet(
context,
isFullScreen: true,
title: "OTP Verification",
isCloseButtonVisible: false,
height:ResponsiveExtension.screenHeight * 0.75,
child: OTPVerificationScreen(
phoneNumber: phoneNumber,
checkActivationCode: (int code) {
_verifyOTP(
context: context,
loginTokenID: loginTokenID,
code: code,
onSuccess: onSuccess,
);
},
onResendOTPPressed: (String phoneNumber) {
Navigator.pop(context);
openOTPScreen(
context: context,
phoneNumber: phoneNumber,
countryEnum: CountryEnum.saudiArabia,
onSuccess: onSuccess,
);
},
isFormFamilyFile: false,
),
);
}
static void _verifyOTP({
required BuildContext context,
required String loginTokenID,
required int code,
required Function onSuccess,
}) {
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
hmgServicesViewModel.checkEReferralActivationCode(
requestModel: CheckActivationCodeForEReferralRequestModel(
logInTokenID: loginTokenID,
activationCode: code.toString(),
),
onSuccess: (GenericApiModel response) {
Navigator.pop(context);
onSuccess();
},
onError: (String errorMessage) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(errorMessage))
);
},
showModalBottomSheet(
context: context,
isScrollControlled: true,
isDismissible: false,
useSafeArea: true,
backgroundColor: Colors.transparent,
builder: (bottomSheetContext) => Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom),
child: SingleChildScrollView(
child: GenericBottomSheet(
isEnableCountryDropdown:true,
textController: TextEditingController(),
onChange: (value) {
formManager.updateRequesterPhone(value ?? '');
},
onCountryChange: (value) {
formManager.updateCountryEnum(value);
},
autoFocus: true,
buttons: [
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: CustomButton(
text: LocaleKeys.sendOTPSMS.tr(),
onPressed: () async {
if (ValidationUtils.isValidatePhone(
phoneNumber: formManager.formData.requesterPhone,
onOkPress: () {
Navigator.pop(context);
},
)) {
Navigator.pop(context);
final hmgServicesViewModel = context.read<HmgServicesViewModel>();
LoaderBottomSheet.showLoader();
hmgServicesViewModel.eReferralSendActivationCode(
requestModel: SendActivationCodeForEReferralRequestModel(
patientMobileNumber: int.parse(formManager.formData.requesterPhone),
zipCode: formManager.formData.countryEnum.countryCode,
patientOutSA: formManager.formData.countryEnum.countryCode == '966' ? 0 : 1,
),
onSuccess: (GenericApiModel response) {
LoaderBottomSheet.hideLoader();
hmgServicesViewModel.navigateToOTPScreen(otpTypeEnum: OTPTypeEnum.sms, phoneNumber: formManager.formData.requesterPhone, loginToken:response.data , onSuccess: (){
Navigator.pop(context);
onSuccess();
});
},
onError: (String errorMessage) {
LoaderBottomSheet.hideLoader();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(errorMessage))
);
},
);
}
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedBorderColor,
textColor: AppColors.whiteColor,
icon: AppAssets.message,
),
),
],
),
)),
);
}
}
}

@ -1,8 +1,10 @@
// widgets/other_details_step.dart
import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/validation_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/models/req_models/create_e_referral_model.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_form_manager.dart';
@ -55,6 +57,7 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
_insuranceController.text = hasInsuranceDocs
? '${_formManager.formData.insuredPatientImages.length} file(s) selected'
: '';
}
@override
@ -105,7 +108,7 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
onTap: () {
ImageOptions.showImageOptionsNew(
context,
true,
false,
(String image, File file) {
_addMedicalReport(image, file, formManager);
},
@ -199,7 +202,7 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
onTap: () {
ImageOptions.showImageOptionsNew(
context,
true,
false,
(String image, File file) {
_addInsuranceDocument(image, file, formManager);
},
@ -245,22 +248,28 @@ class _OtherDetailsStepState extends State<OtherDetailsStep> {
);
}
return ListView.separated(
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white,
customBorder: BorderRadius.all(Radius.circular(24.h)) ,
), child: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.all(16.h),
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
final branch = hospitals[index];
return ListTile(
title: Text(branch.desciption ?? 'Unknown'),
title: (branch.desciption ?? 'Unknown').toText14(),
onTap: () {
formManager.updateBranch(branch);
Navigator.pop(context);
},
);
},
separatorBuilder: (context, index) => const Divider(),
// separatorBuilder: (context, index) => const Divider(),
itemCount: hospitals.length,
);
));
},
),
useSafeArea: true,

@ -1,6 +1,8 @@
// widgets/patient_information_step.dart
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/validation_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/presentation/e_referral/e_referral_form_manager.dart';
import 'package:provider/provider.dart';
@ -160,7 +162,7 @@ class PatientInformationStepState extends State<PatientInformationStep> {
formManager.updatePatientPhone(value ?? '');
},
onCountryChange: (value) {
formManager.updateCountryEnum(value);
formManager.updatePatientCountryEnum(value);
},
prefix: '966',
isBorderAllowed: false,
@ -192,50 +194,8 @@ class PatientInformationStepState extends State<PatientInformationStep> {
});
}
// void _showCountryBottomSheet(BuildContext context, ReferralFormManager formManager) {
// final authVM = context.read<AuthenticationViewModel>();
//
// showCommonBottomSheetWithoutHeight(
// context,
// title: "Select Country",
// child: Consumer<AuthenticationViewModel>(
// builder: (context, authVM, child) {
// final countries = authVM.countriesList;
// if (countries == null || countries.isEmpty) {
// return const Center(
// child: Padding(
// padding: EdgeInsets.all(16.0),
// child: Text('No countries available'),
// ),
// );
// }
//
// return ListView.separated(
// shrinkWrap: true,
// physics: const BouncingScrollPhysics(),
// itemBuilder: (context, index) {
// final country = countries[index];
// return ListTile(
// title: Text(country.name ?? 'Unknown'),
// onTap: () {
// formManager.updatePatientCountry(country);
// Navigator.pop(context);
// },
// );
// },
// separatorBuilder: (context, index) => const Divider(),
// itemCount: countries.length,
// );
// },
// ),
// useSafeArea: true,
// isFullScreen: false,
// isCloseButtonVisible: true,
// );
// }
void _showCityBottomSheet(BuildContext context, ReferralFormManager formManager) {
final hmgServicesVM = context.read<HmgServicesViewModel>();
showCommonBottomSheetWithoutHeight(
context,
@ -252,22 +212,28 @@ class PatientInformationStepState extends State<PatientInformationStep> {
);
}
return ListView.separated(
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white,
customBorder: BorderRadius.all(Radius.circular(24.h)) ,
), child: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.all(16.h),
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
final city = cities[index];
return ListTile(
title: Text(city.description ?? 'Unknown'),
title: (city.description ?? 'Unknown').toText14(),
onTap: () {
formManager.updatePatientCity(city);
Navigator.pop(context);
},
);
},
separatorBuilder: (context, index) => const Divider(),
// separatorBuilder: (context, index) => const Divider(),
itemCount: cities.length,
);
));
},
),
useSafeArea: true,

@ -1,6 +1,8 @@
// widgets/requester_form_step.dart
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/utils/validation_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/models/ui_models/e_referral_form_model.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/e-referral_validator.dart';
@ -63,15 +65,17 @@ class RequesterFormStepState extends State<RequesterFormStep> {
return Consumer<ReferralFormManager>(
builder: (context, formManager, child) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 0.0),
child: ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
children: [
const SizedBox(height: 12),
// const SizedBox(height: 12),
_buildSectionTitle('Referral requester information'),
const SizedBox(height: 12),
const SizedBox(height: 12),
_buildNameField(formManager),
_buildPhoneField(formManager),
// _buildPhoneField(formManager),
_buildRelationshipField(context, formManager),
if (_showOtherNameField(formManager)) _buildOtherNameField(formManager),
],
@ -98,43 +102,43 @@ class RequesterFormStepState extends State<RequesterFormStep> {
labelText: 'Requester Name',
keyboardType: TextInputType.text,
errorMessage: formManager.errors.requesterName,
isAllowLeadingIcon: true,
leadingIcon: AppAssets.user_circle,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.requesterName),
onChange: (value) {
formManager.updateRequesterName(value ?? '');
},
onSubmitted: (value) {
_phoneFocusNode.requestFocus();
},
).paddingSymmetrical(0, 8),
);
}
Widget _buildPhoneField(ReferralFormManager formManager) {
return Focus(
focusNode: _phoneFocusNode,
child: TextInputWidget(
labelText: 'Phone Number',
hintText: "5xxxxxxxx",
controller: _phoneController,
padding: const EdgeInsets.all(8),
keyboardType: TextInputType.number,
onChange: (value) {
formManager.updateRequesterPhone(value ?? '');
},
onCountryChange: (value) {
formManager.updateCountryEnum(value);
},
prefix: '966',
isBorderAllowed: false,
isAllowLeadingIcon: true,
fontSize: 13,
isCountryDropDown: true,
leadingIcon: AppAssets.smart_phone,
errorMessage: formManager.errors.requesterPhone,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.requesterPhone)
).paddingSymmetrical(0, 8),
);
}
//
// Widget _buildPhoneField(ReferralFormManager formManager) {
// return Focus(
// focusNode: _phoneFocusNode,
// child: TextInputWidget(
// labelText: 'Phone Number',
// hintText: "5xxxxxxxx",
// controller: _phoneController,
// padding: const EdgeInsets.all(8),
// keyboardType: TextInputType.number,
// onChange: (value) {
// formManager.updateRequesterPhone(value ?? '');
// },
// onCountryChange: (value) {
// formManager.updateCountryEnum(value);
// },
// prefix: '966',
// isBorderAllowed: false,
// isAllowLeadingIcon: true,
// fontSize: 13,
// isCountryDropDown: true,
// leadingIcon: AppAssets.smart_phone,
// errorMessage: formManager.errors.requesterPhone,
// hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.requesterPhone)
// ).paddingSymmetrical(0, 8),
// );
// }
Widget _buildRelationshipField(BuildContext context, ReferralFormManager formManager) {
return DropdownWidget(
@ -159,6 +163,7 @@ class RequesterFormStepState extends State<RequesterFormStep> {
focusNode: _otherNameFocusNode,
child: TextInputWidget(
controller: _otherNameController,
keyboardType: TextInputType.text,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
hintText: 'Other Name*',
labelText: 'Other Name',
@ -192,22 +197,28 @@ class RequesterFormStepState extends State<RequesterFormStep> {
);
}
return ListView.separated(
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white,
customBorder: BorderRadius.all(Radius.circular(24.h)) ,
), child: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.all(16.h),
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
final relationship = hmgServicesVM.relationTypes[index];
return ListTile(
title: Text(relationship.textEn ?? 'Unknown'),
title:relationship.textEn?.toText14(),
onTap: () {
formManager.updateRelationship(relationship);
Navigator.pop(context);
},
);
},
separatorBuilder: (context, index) => const Divider(),
//separatorBuilder: (context, index) => const Divider(),
itemCount: hmgServicesVM.relationTypes.length,
);
));
},
),
isFullScreen: false,

@ -1,72 +0,0 @@
// widgets/progress_stepper_widget.dart
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class ProgressStepperWidget extends StatelessWidget {
final int currentStep;
final List<String> steps;
const ProgressStepperWidget({
super.key,
required this.currentStep,
required this.steps,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (int i = 0; i < steps.length; i++)
_buildStep(
title: steps[i],
active: i == currentStep,
showDivider: i < steps.length - 1,
),
],
),
);
}
Widget _buildStep({required String title, required bool active, bool showDivider = true}) {
final Color activeColor = active ? AppColors.primaryRedColor : Colors.grey.shade400;
return Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
radius: 13,
backgroundColor: active ? activeColor : Colors.grey.shade300,
child: Icon(Icons.check, size: 14, color: Colors.white),
),
if (showDivider)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Divider(thickness: 1),
),
],
),
const SizedBox(height: 6),
Text(title, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600)),
const SizedBox(height: 6),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
decoration: BoxDecoration(
color: active ? activeColor.withOpacity(0.15) : Colors.grey.shade100,
borderRadius: BorderRadius.circular(6),
),
child: Text(
active ? 'Active' : 'Inactive',
style: TextStyle(fontSize: 9, color: active ? activeColor : Colors.grey)
),
),
],
),
);
}
}

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/validation_utils.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
@ -12,8 +11,10 @@ import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_mode
import 'package:hmg_patient_app_new/widgets/dropdown/dropdown_widget.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
class SearchEReferralFormForm extends StatefulWidget {
const SearchEReferralFormForm({super.key});
final VoidCallback? onFormValidated;
const SearchEReferralFormForm({super.key, this.onFormValidated});
@override
State<SearchEReferralFormForm> createState() => SearchEReferralFormFormState();
@ -22,35 +23,25 @@ class SearchEReferralFormForm extends StatefulWidget {
class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
late TextEditingController _searchController;
late TextEditingController _phoneController;
late FocusNode _searchFocusNode;
late FocusNode _searchFocusNode;
late FocusNode _phoneFocusNode;
int criteria =0;
List<Map<int,String>> criteriaList = [
{0: 'Identification Number'},
{1: 'Referral Number'},
];
late ReferralFormManager _formManager;
@override
void initState() {
super.initState();
_formManager = context.read<ReferralFormManager>();
_searchController = TextEditingController();
_phoneController = TextEditingController();
_searchFocusNode = FocusNode();
_phoneFocusNode = FocusNode();
// Initialize controllers with current values
_searchController.text = '';
_phoneController.text = '';
// Auto-focus the name field when the step loads
// Initialize controllers with current values from form manager
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
_searchFocusNode.requestFocus();
final formManager = context.read<ReferralFormManager>();
_searchController.text = formManager.searchValue ?? '';
_phoneController.text = formManager.searchPhone ?? '';
// _searchFocusNode.requestFocus();
}
});
}
@ -62,14 +53,13 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: ListView(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: [
const SizedBox(height: 12),
// const SizedBox(height: 12),
_buildSelectionField(context, formManager),
_buildNameField(formManager),
_buildPhoneField(formManager),
],
),
);
@ -77,24 +67,21 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
);
}
Widget _buildNameField(ReferralFormManager formManager) {
return Focus(
focusNode: _searchFocusNode,
autofocus: true,
child: TextInputWidget(
controller: _searchController,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
hintText:criteria ==0 ? "Enter Identification Number" : "Enter Referral Number",
labelText: criteria ==0 ? "Identification Number" : "Referral Number",
keyboardType: TextInputType.text,
// errorMessage: formManager.errors.requesterName,
hasError: !ValidationUtils.isNullOrEmpty(_searchController.text),
hintText: formManager.searchCriteria == 0 ? "Enter Identification Number" : "Enter Referral Number",
labelText: formManager.searchCriteria == 0 ? "Identification Number" : "Referral Number",
keyboardType: TextInputType.number,
errorMessage: formManager.errors.searchValue,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.searchValue),
onChange: (value) {
},
onSubmitted: (value) {
formManager.updateSearchValue(value ?? '');
//_validateForm(formManager);
},
).paddingSymmetrical(0, 8),
);
@ -103,17 +90,25 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
Widget _buildPhoneField(ReferralFormManager formManager) {
return Focus(
focusNode: _phoneFocusNode,
autofocus: false,
child: TextInputWidget(
autoFocus: false,
labelText: 'Phone Number',
hintText: "5xxxxxxxx",
controller: _phoneController,
padding: const EdgeInsets.all(8),
keyboardType: TextInputType.number,
onChange: (value) {
formManager.updateRequesterPhone(value ?? '');
formManager.updateSearchPhone(value ?? '');
// _validateForm(formManager);
},
// onSubmitted: (value) {
// formManager.updateRequesterPhone(value ?? '');
// _validateForm(formManager);
// },
onCountryChange: (value) {
formManager.updateCountryEnum(value);
// _validateForm(formManager);
},
prefix: '966',
isBorderAllowed: false,
@ -121,8 +116,8 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
fontSize: 13,
isCountryDropDown: true,
leadingIcon: AppAssets.smart_phone,
errorMessage: formManager.errors.requesterPhone,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.requesterPhone)
errorMessage: formManager.errors.searchPhone,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.searchPhone),
).paddingSymmetrical(0, 8),
);
}
@ -130,7 +125,7 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
Widget _buildSelectionField(BuildContext context, ReferralFormManager formManager) {
return DropdownWidget(
labelText: "Select the Search Criteria",
hintText: criteria ==0 ? "Identification Number" : "Referral Number",
hintText: formManager.searchCriteria == 0 ? "Identification Number" : "Referral Number",
isEnable: false,
hasSelectionCustomIcon: false,
labelColor: Colors.black,
@ -138,38 +133,63 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
leadingIcon: AppAssets.search_icon,
dropdownItems: [],
).paddingSymmetrical(0, 8).onPress(() {
_showCriteriaBottomSheet(context);
_showCriteriaBottomSheet(context, formManager);
});
}
void _showCriteriaBottomSheet(BuildContext context,) {
void _showCriteriaBottomSheet(BuildContext context, ReferralFormManager formManager) {
final criteriaList = [
{0: 'Identification Number'},
{1: 'Referral Number'},
];
showCommonBottomSheetWithoutHeight(
context,
title: "Select Criteria",
child: ListView.separated(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
return ListTile(
title: Text(criteriaList[index].values.first),
onTap: () {
setState(() {
criteria = index;
});
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
final criteria = criteriaList[index];
final criteriaKey = criteria.keys.first;
final criteriaValue = criteria.values.first;
return ListTile(
leading: Radio<int>(
value: criteriaKey,
groupValue: formManager.searchCriteria,
onChanged: (value) {
if (value != null) {
formManager.updateSearchCriteria(value);
_searchController.clear();
_validateForm(formManager);
Navigator.pop(context);
},
);
}
},
),
title: Text(criteriaValue),
onTap: () {
formManager.updateSearchCriteria(criteriaKey);
_searchController.clear();
_validateForm(formManager);
Navigator.pop(context);
},
separatorBuilder: (context, index) => const Divider(),
itemCount: criteriaList.length,
),
);
},
separatorBuilder: (context, index) => const Divider(),
itemCount: criteriaList.length,
),
isFullScreen: false,
isCloseButtonVisible: true,
);
);
}
void _validateForm(ReferralFormManager formManager) {
// Trigger validation
formManager.validateSearchForm();
// Notify parent if form validation state changes
widget.onFormValidated?.call();
}
@override
@ -178,7 +198,6 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
_phoneController.dispose();
_searchFocusNode.dispose();
_phoneFocusNode.dispose();
super.dispose();
}
}
}

@ -23,7 +23,7 @@ class PickupLocation extends StatelessWidget {
children: [
"Select Pickup Direction"
.needTranslation
.toText24(color: AppColors.textColor,isBold: true),
.toText24(color: AppColors.textColor, isBold: true),
SizedBox(
height: 16.h,
),
@ -34,128 +34,147 @@ class PickupLocation extends StatelessWidget {
height: 12.h,
),
Selector<EmergencyServicesViewModel, AmbulanceCallingPlace>(
selector: (context, viewModel) => viewModel.callingPlace,
builder: (context, value, _) {
return Column(
spacing: 12.h,
children: [
RadioGroup<AmbulanceCallingPlace>(
groupValue: value,
onChanged: (value) {
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(value);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 24.h,
children: [
Row(
children: [
Radio(
value: AmbulanceCallingPlace.TO_HOSPITAL,
groupValue: value,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"To Hospital"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w500)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(AmbulanceCallingPlace.TO_HOSPITAL);
}),
Row(
children: [
Radio(
value: AmbulanceCallingPlace.FROM_HOSPITAL,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"From Hospital"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w500)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(AmbulanceCallingPlace.FROM_HOSPITAL);
}),
],
selector: (context, viewModel) => viewModel.callingPlace,
builder: (context, value, _) {
return Column(
children: [
SizedBox(height: 12.h),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Row(
children: [
Radio<AmbulanceCallingPlace>(
value: AmbulanceCallingPlace.TO_HOSPITAL,
groupValue: value,
onChanged: (AmbulanceCallingPlace? newValue) {
if (newValue != null) {
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(newValue);
}
},
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"To Hospital"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w500)
],
).onPress(() {
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(AmbulanceCallingPlace.TO_HOSPITAL);
}),
),
),
Visibility(
visible: value == AmbulanceCallingPlace.TO_HOSPITAL,
child: Selector<EmergencyServicesViewModel, AmbulanceDirection>(
selector: (context, viewModel) =>
viewModel.ambulanceDirection,
builder: (context, directionValue, _) {
return Column(
spacing: 12.h,
crossAxisAlignment: CrossAxisAlignment.start,
Expanded(
child: Row(
children: [
Radio<AmbulanceCallingPlace>(
value: AmbulanceCallingPlace.FROM_HOSPITAL,
groupValue: value,
onChanged: (AmbulanceCallingPlace? newValue) {
if (newValue != null) {
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(newValue);
}
},
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"From Hospital"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w500)
],
).onPress(() {
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(AmbulanceCallingPlace.FROM_HOSPITAL);
}),
),
],
),
Visibility(
visible: value == AmbulanceCallingPlace.TO_HOSPITAL,
child: Selector<EmergencyServicesViewModel, AmbulanceDirection>(
selector: (context, viewModel) => viewModel.ambulanceDirection,
builder: (context, directionValue, _) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 16.h),
"Select Way"
.needTranslation
.toText16(color: AppColors.textColor, weight: FontWeight.w600),
SizedBox(height: 12.h),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
"Select Way"
.needTranslation
.toText16(color: AppColors.textColor, weight: FontWeight.w600),
RadioGroup<AmbulanceDirection>(
groupValue: directionValue,
onChanged: (value) {
Expanded(
child: Row(
children: [
Radio<AmbulanceDirection>(
value: AmbulanceDirection.ONE_WAY,
groupValue: directionValue,
onChanged: (AmbulanceDirection? newValue) {
if (newValue != null) {
context
.read<EmergencyServicesViewModel>()
.updateDirection(newValue);
}
},
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"One Way"
.needTranslation
.toText12(color: AppColors.textColor, fontWeight: FontWeight.w500)
],
).onPress(() {
context
.read<EmergencyServicesViewModel>()
.updateDirection(value);
},
.updateDirection(AmbulanceDirection.ONE_WAY);
}),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 24.h,
children: [
Row(
children: [
Radio(
value: AmbulanceDirection.ONE_WAY,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"One Way"
.needTranslation
.toText12(color: AppColors.textColor, fontWeight: FontWeight.w500)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateDirection(AmbulanceDirection.ONE_WAY);
}),
Row(
children: [
Radio(
value: AmbulanceDirection.TWO_WAY,
// activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"Two Way"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w500)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateDirection(AmbulanceDirection.TWO_WAY);
}),
Radio<AmbulanceDirection>(
value: AmbulanceDirection.TWO_WAY,
groupValue: directionValue,
onChanged: (AmbulanceDirection? newValue) {
if (newValue != null) {
context
.read<EmergencyServicesViewModel>()
.updateDirection(newValue);
}
},
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"Two Way"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w500)
],
),
).onPress(() {
context
.read<EmergencyServicesViewModel>()
.updateDirection(AmbulanceDirection.TWO_WAY);
}),
),
],
);
}),
)
],
);
}),
),
],
);
},
),
)
],
);
},
),
SizedBox(
height: 16.h,
),
@ -170,4 +189,4 @@ class PickupLocation extends StatelessWidget {
],
);
}
}
}

@ -3,7 +3,7 @@ import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/presentation/authentication/register.dart';
import 'package:hmg_patient_app_new/presentation/authentication/register_step2.dart';
import 'package:hmg_patient_app_new/presentation/comprehensive_checkup/comprehensive_checkup_page.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/e_referral_page_home.dart';
import 'package:hmg_patient_app_new/presentation/e_referral/new_e_referral.dart';
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
import 'package:hmg_patient_app_new/presentation/home_health_care/hhc_procedures_page.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart';
@ -27,7 +27,7 @@ class AppRoutes {
register: (context) => RegisterNew(),
registerStepTwo: (context) => RegisterNewStep2(),
medicalFilePage: (context) => MedicalFilePage(),
eReferralPage: (context) => EReferralPage(),
eReferralPage: (context) => NewReferralPage(),
comprehensiveCheckupPage: (context) => ComprehensiveCheckupPage(),
homeHealthCarePage: (context) => HhcProceduresPage()
};

@ -147,6 +147,7 @@ void cameraImageAndroid(Function(String, File) image) async {
if (base64Encode != null) {
image(base64Encode, _image);
}
}
class _BottomSheet extends StatelessWidget {

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/order_tracking/order_tracking_state.dart';
import 'package:hmg_patient_app_new/widgets/stepper/stepper_widget.dart';
class OrderTrackingWidget extends StatelessWidget {
final double? height;
@ -35,9 +36,9 @@ class OrderTrackingWidget extends StatelessWidget {
return Row(
children: List.generate(4, (index) {
if (index == 0) {
return oneProgressBar(widthOfOneState, AppColors.primaryRedColor, true);
return StepperWidget(widthOfOneState, AppColors.primaryRedColor, true, height);
} else {
return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
return StepperWidget(widthOfOneState, AppColors.greyLightColor, false, height);
}
}));
}
@ -46,9 +47,9 @@ class OrderTrackingWidget extends StatelessWidget {
return Row(
children: List.generate(4, (index){
if(index == 0) {
return oneProgressBar(widthOfOneState, AppColors.primaryRedColor, true);
return StepperWidget(widthOfOneState, AppColors.primaryRedColor, true, height);
} else {
return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
return StepperWidget(widthOfOneState, AppColors.greyLightColor, false, height);
}
})
);
@ -57,9 +58,9 @@ class OrderTrackingWidget extends StatelessWidget {
return Row(
children: List.generate(4, (index){
if(index == 1 || index == 0) {
return oneProgressBar(widthOfOneState, AppColors.primaryRedColor, index == 1 );
return StepperWidget(widthOfOneState, AppColors.primaryRedColor, index == 1, height );
} else {
return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
return StepperWidget(widthOfOneState, AppColors.greyLightColor, false, height);
}
})
);
@ -67,9 +68,9 @@ class OrderTrackingWidget extends StatelessWidget {
return Row(
children: List.generate(4, (index){
if(index == 2 || index == 1 || index == 0) {
return oneProgressBar(widthOfOneState, AppColors.primaryRedColor, index == 2);
return StepperWidget(widthOfOneState, AppColors.primaryRedColor, index == 2, height);
} else {
return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
return StepperWidget(widthOfOneState, AppColors.greyLightColor, false, height);
}
})
);
@ -77,7 +78,7 @@ class OrderTrackingWidget extends StatelessWidget {
return Row(
children: List.generate(4, (index){
// if(index == 3) {
return oneProgressBar(widthOfOneState, AppColors.successLightColor, index == 3);
return StepperWidget(widthOfOneState, AppColors.successLightColor, index == 3, height);
// } else {
// return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
// }
@ -87,7 +88,7 @@ class OrderTrackingWidget extends StatelessWidget {
return Row(
children: List.generate(4, (index){
// if(index == 3) {
return oneProgressBar(widthOfOneState, AppColors.errorColor, index == 3);
return StepperWidget(widthOfOneState, AppColors.errorColor, index == 3, height);
// } else {
// return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
// }
@ -97,7 +98,7 @@ class OrderTrackingWidget extends StatelessWidget {
return Row(
children: List.generate(4, (index){
// if(index == 3) {
return oneProgressBar(widthOfOneState, AppColors.errorColor, index == 3);
return StepperWidget(widthOfOneState, AppColors.errorColor, index == 3, height);
// } else {
// return oneProgressBar(widthOfOneState, AppColors.greyLightColor, false);
// }
@ -106,58 +107,6 @@ class OrderTrackingWidget extends StatelessWidget {
}
}
Widget oneProgressBar(double width, Color color, bool hasThumb) {
return Row(
children: [
AnimatedSize(
duration: const Duration(seconds:1),
child: SizedBox(
height: 28.h,
width: width,
child: Stack(
clipBehavior: Clip.none,
children: [
SizedBox(
height: 28.h,
child: Container(
width: width,
height: height,
decoration: BoxDecoration(
color: color,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(30.h)
),
),
),
Visibility(
visible: hasThumb,
child: Positioned(
top: -6.h, // move thumb above bar center
left: width - 22.h, // move to right end
child: thumb(color),
),
)
],
),
),
),
SizedBox(width: 8.h)
],
);
}
Widget thumb(Color color) {
return Container(
width: 18.h,
height: 18.h,
padding: EdgeInsets.zero,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2.h)
),
);
}
}

@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class StepperWidget extends StatelessWidget {
double width = 80.w;
Color activeColor = AppColors.primaryRedColor;
bool hasThumb = true;
double? height = 4.h;
StepperWidget( this.width, this.activeColor, this.hasThumb, this.height, {super.key});
@override
Widget build(BuildContext context) {
return oneProgressBar(width, activeColor, hasThumb);
}
Widget oneProgressBar(double width, Color color, bool hasThumb) {
return Row(
children: [
AnimatedSize(
duration: const Duration(seconds: 1),
child: SizedBox(
height: 28.h,
width: width,
child: Stack(
clipBehavior: Clip.none,
children: [
SizedBox(
height: height,
child: Container(
width: width,
height: height,
decoration: BoxDecoration(
color: color,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(30.h)
),
),
),
Visibility(
visible: hasThumb,
child: Positioned(
top: -6.h, // move thumb above bar center
left: width - 22.h, // move to right end
child: thumb(color),
),
)
],
),
),
),
SizedBox(width: 8.h)
],
);
}
Widget thumb(Color color) {
return Container(
width: 18.h,
height: 18.h,
padding: EdgeInsets.zero,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2.h)
),
);
}
}
Loading…
Cancel
Save