Merge branch 'master' of http://34.17.52.180/Haroon6138/HMG_Patient_App_New into dev_sultan
# Conflicts: # lib/presentation/lab/lab_orders_page.dartpull/10/head
commit
3cafc16d50
@ -0,0 +1,3 @@
|
||||
<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="M6.99984 12.7702C3.53655 12.7702 0.729004 9.96263 0.729004 6.49935C0.729004 3.03606 3.53655 0.228516 6.99984 0.228516C10.4631 0.228516 13.2707 3.03606 13.2707 6.49935C13.2707 9.96263 10.4631 12.7702 6.99984 12.7702ZM9.1623 5.16184C9.39012 4.93404 9.39013 4.5647 9.16233 4.33688C8.93453 4.10907 8.56519 4.10906 8.33737 4.33686L6.99972 5.67442L5.6623 4.33709C5.43449 4.10929 5.06514 4.1093 4.83734 4.33711C4.60955 4.56493 4.60956 4.93427 4.83737 5.16207L6.17474 6.49935L4.83737 7.83663C4.60956 8.06442 4.60955 8.43377 4.83734 8.66158C5.06514 8.8894 5.43449 8.88941 5.6623 8.66161L6.99972 7.32428L8.33737 8.66184C8.56519 8.88964 8.93453 8.88963 9.16233 8.66181C9.39013 8.434 9.39012 8.06465 9.1623 7.83686L7.82471 6.49935L9.1623 5.16184Z" fill="#ED1C2B"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 909 B |
@ -0,0 +1,4 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.03033 6.96967C7.73744 6.67678 7.26256 6.67678 6.96967 6.96967C6.67678 7.26256 6.67678 7.73744 6.96967 8.03033L9.93934 11L6.96967 13.9697C6.67678 14.2626 6.67678 14.7374 6.96967 15.0303C7.26256 15.3232 7.73744 15.3232 8.03033 15.0303L11 12.0607L13.9697 15.0303C14.2626 15.3232 14.7374 15.3232 15.0303 15.0303C15.3232 14.7374 15.3232 14.2626 15.0303 13.9697L12.0607 11L15.0303 8.03033C15.3232 7.73744 15.3232 7.26256 15.0303 6.96967C14.7374 6.67678 14.2626 6.67678 13.9697 6.96967L11 9.93934L8.03033 6.96967Z" fill="#2B353E"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 0.25C5.06294 0.25 0.25 5.06294 0.25 11C0.25 16.9371 5.06294 21.75 11 21.75C16.9371 21.75 21.75 16.9371 21.75 11C21.75 5.06294 16.9371 0.25 11 0.25ZM1.75 11C1.75 5.89137 5.89137 1.75 11 1.75C16.1086 1.75 20.25 5.89137 20.25 11C20.25 16.1086 16.1086 20.25 11 20.25C5.89137 20.25 1.75 16.1086 1.75 11Z" fill="#2B353E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1018 B |
@ -0,0 +1,4 @@
|
||||
<svg width="22" height="23" viewBox="0 0 22 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.4932 13.7808C20.7528 9.09639 17.955 4.27023 13.2297 3.00853C9.70851 2.06832 6.11906 3.37593 3.99728 6.04158C3.84468 6.2333 3.86798 6.50772 4.04125 6.68099L5.04846 7.6882C5.18151 7.82125 5.1938 8.04137 5.18151 8.24316C5.14872 8.78189 4.6854 9.19203 4.14668 9.15923L1.69362 9.00989C1.38358 8.99102 1.10097 8.82587 0.932324 8.56502C0.76368 8.30416 0.72909 7.97867 0.839142 7.6882C2.77489 2.57901 8.3266 -0.323654 13.7339 1.12017C19.4935 2.65805 22.9235 8.55039 21.3807 14.2883C19.8381 20.025 13.9137 23.4174 8.1554 21.8799C3.87709 20.7375 0.886935 17.1944 0.261338 13.0982C0.179854 12.5647 0.546317 12.0661 1.07986 11.9846C1.61339 11.9031 2.11197 12.2696 2.19345 12.8031C2.70523 16.1541 5.15307 19.0552 8.65962 19.9915C13.3861 21.2536 18.2332 18.4666 19.4932 13.7808Z" fill="#ED1C2B"/>
|
||||
<path d="M12 7.5C12 6.94772 11.5523 6.5 11 6.5C10.4477 6.5 10 6.94772 10 7.5V11.5C10 11.7652 10.1054 12.0196 10.2929 12.2071L12.2929 14.2071C12.6834 14.5976 13.3166 14.5976 13.7071 14.2071C14.0976 13.8166 14.0976 13.1834 13.7071 12.7929L12 11.0858V7.5Z" fill="#ED1C2B"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,5 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="40" height="40" rx="10" fill="#EFEFF0"/>
|
||||
<path d="M20 9.25C15.5442 9.25 11.9279 12.8415 11.9279 17.277C11.9278 18.3087 11.8584 19.0873 11.3827 19.7872C11.3166 19.8831 11.2288 20.0032 11.1329 20.1345C10.9663 20.3625 10.7753 20.624 10.6303 20.8505C10.3745 21.2503 10.1246 21.7324 10.0387 22.2942C9.75836 24.127 11.0506 25.3136 12.3375 25.8454C16.8702 27.7182 23.1298 27.7182 27.6625 25.8454C28.9494 25.3136 30.2416 24.127 29.9613 22.2942C29.8754 21.7324 29.6255 21.2503 29.3697 20.8505C29.2247 20.624 29.0337 20.3625 28.8671 20.1345C28.7712 20.0033 28.6835 19.8832 28.6173 19.7873C28.1416 19.0874 28.0722 18.3088 28.0721 17.277C28.0721 12.8415 24.4558 9.25 20 9.25Z" fill="#8F9AA3"/>
|
||||
<path d="M19.9985 30.7477C21.0187 30.7477 21.9742 30.4563 22.7776 29.9511C23.4906 29.5027 23.8472 29.2785 23.7224 28.9057C23.5976 28.533 23.1057 28.5747 22.1217 28.6582C20.7146 28.7776 19.2824 28.7776 17.8752 28.6582C16.8913 28.5747 16.3993 28.533 16.2745 28.9057C16.1498 29.2784 16.5063 29.5027 17.2193 29.9511C18.0227 30.4563 18.9782 30.7477 19.9985 30.7477Z" fill="#8F9AA3"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,4 @@
|
||||
<svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.16613 2.14867C6.59446 2.05148 7.04084 2 7.50016 2C10.8139 2 13.5002 4.68629 13.5002 8C13.5002 9.53082 12.9272 10.928 11.9827 11.9886L11.9827 11C11.9827 10.5858 11.6469 10.25 11.2327 10.25C10.8185 10.25 10.4827 10.5858 10.4827 11L10.4827 13.625C10.4827 14.0392 10.8185 14.375 11.2327 14.375H13.8752C14.2894 14.375 14.6252 14.0392 14.6252 13.625C14.6252 13.2108 14.2894 12.875 13.8752 12.875H13.1997C14.3217 11.5644 15.0002 9.86153 15.0002 8C15.0002 3.85786 11.6423 0.5 7.50016 0.5C6.9284 0.5 6.3707 0.564117 5.8342 0.685856C5.43025 0.777516 5.1771 1.17928 5.26876 1.58323C5.36042 1.98717 5.76218 2.24033 6.16613 2.14867Z" fill="#18C273"/>
|
||||
<path d="M1.125 1.63672C0.710786 1.63672 0.375 1.97251 0.375 2.38672C0.375 2.80093 0.710786 3.13672 1.125 3.13672H1.79048C0.674497 4.44574 0 6.14405 0 8.00006C0 12.1422 3.35786 15.5001 7.5 15.5001C8.07176 15.5001 8.62946 15.4359 9.16597 15.3142C9.56991 15.2225 9.82307 14.8208 9.73141 14.4168C9.63975 14.0129 9.23798 13.7597 8.83404 13.8514C8.4057 13.9486 7.95932 14.0001 7.5 14.0001C4.18629 14.0001 1.5 11.3138 1.5 8.00006C1.5 6.4787 2.06588 5.08936 3 4.03118V5.00006C3 5.41427 3.33579 5.75006 3.75 5.75006C4.16421 5.75006 4.5 5.41427 4.5 5.00006V2.38672C4.5 1.97251 4.16421 1.63672 3.75 1.63672L1.125 1.63672Z" fill="#18C273"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class NationalityCountries {
|
||||
String? id;
|
||||
String? name;
|
||||
String? nameN;
|
||||
|
||||
NationalityCountries({
|
||||
this.id,
|
||||
this.name,
|
||||
this.nameN,
|
||||
});
|
||||
|
||||
factory NationalityCountries.fromRawJson(String str) => NationalityCountries.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory NationalityCountries.fromJson(Map<String, dynamic> json) => NationalityCountries(
|
||||
id: json["ID"],
|
||||
name: json["Name"],
|
||||
nameN: json["NameN"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"ID": id,
|
||||
"Name": name,
|
||||
"NameN": nameN,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:hmg_patient_app_new/core/api/api_client.dart';
|
||||
import 'package:hmg_patient_app_new/core/api_consts.dart';
|
||||
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
|
||||
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
|
||||
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
||||
|
||||
abstract class InsuranceRepo {
|
||||
Future<Either<Failure, GenericApiModel<List<PatientInsuranceDetailsResponseModel>>>> getPatientInsuranceDetails({required String patientId});
|
||||
}
|
||||
|
||||
class InsuranceRepoImp implements InsuranceRepo {
|
||||
final ApiClient apiClient;
|
||||
final LoggerService loggerService;
|
||||
|
||||
InsuranceRepoImp({required this.loggerService, required this.apiClient});
|
||||
|
||||
@override
|
||||
Future<Either<Failure, GenericApiModel<List<PatientInsuranceDetailsResponseModel>>>> getPatientInsuranceDetails({required String patientId}) async {
|
||||
final mapDevice = {
|
||||
"isDentalAllowedBackend": false,
|
||||
"VersionID": 50.0,
|
||||
"Channel": 3,
|
||||
"LanguageID": 2,
|
||||
"IPAdress": "10.20.10.20",
|
||||
"generalid": "Cs2020@2016\$2958",
|
||||
"Latitude": 0.0,
|
||||
"Longitude": 0.0,
|
||||
"DeviceTypeID": 1,
|
||||
"PatientType": 1,
|
||||
"PatientTypeID": 1,
|
||||
"TokenID": "@dm!n",
|
||||
"PatientID": "3628599",
|
||||
"PatientOutSA": "0",
|
||||
"SessionID": "03478TYC02N80874CTYN04883475!?"
|
||||
};
|
||||
|
||||
try {
|
||||
GenericApiModel<List<PatientInsuranceDetailsResponseModel>>? apiResponse;
|
||||
Failure? failure;
|
||||
await apiClient.post(
|
||||
GET_PAtIENTS_INSURANCE,
|
||||
body: mapDevice,
|
||||
onFailure: (error, statusCode, {messageStatus, failureType}) {
|
||||
failure = failureType;
|
||||
},
|
||||
onSuccess: (response, statusCode, {messageStatus}) {
|
||||
try {
|
||||
final list = response['List_PatientInsuranceCard'];
|
||||
if (list == null || list.isEmpty) {
|
||||
throw Exception("insurance list is empty");
|
||||
}
|
||||
|
||||
final labOrders = list.map((item) => PatientInsuranceDetailsResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<PatientInsuranceDetailsResponseModel>();
|
||||
|
||||
apiResponse = GenericApiModel<List<PatientInsuranceDetailsResponseModel>>(
|
||||
messageStatus: messageStatus,
|
||||
statusCode: statusCode,
|
||||
errorMessage: null,
|
||||
data: labOrders,
|
||||
);
|
||||
} catch (e) {
|
||||
failure = DataParsingFailure(e.toString());
|
||||
}
|
||||
},
|
||||
);
|
||||
if (failure != null) return Left(failure!);
|
||||
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
|
||||
return Right(apiResponse!);
|
||||
} catch (e) {
|
||||
return Left(UnknownFailure(e.toString()));
|
||||
}
|
||||
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/features/insurance/insurance_repo.dart';
|
||||
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
|
||||
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
|
||||
|
||||
class InsuranceViewModel extends ChangeNotifier {
|
||||
bool isInsuranceLoading = false;
|
||||
bool isInsuranceHistoryLoading = false;
|
||||
|
||||
InsuranceRepo insuranceRepo;
|
||||
ErrorHandlerService errorHandlerService;
|
||||
|
||||
List<PatientInsuranceDetailsResponseModel> patientInsuranceList = [];
|
||||
|
||||
InsuranceViewModel({required this.insuranceRepo, required this.errorHandlerService});
|
||||
|
||||
initInsuranceProvider() {
|
||||
patientInsuranceList.clear();
|
||||
isInsuranceLoading = true;
|
||||
isInsuranceHistoryLoading = true;
|
||||
getPatientInsuranceDetails();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
setIsInsuranceHistoryLoading(bool val) {
|
||||
isInsuranceHistoryLoading = val;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getPatientInsuranceDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
||||
final result = await insuranceRepo.getPatientInsuranceDetails(patientId: "1231755");
|
||||
|
||||
result.fold(
|
||||
(failure) async => await errorHandlerService.handleError(failure: failure),
|
||||
(apiResponse) {
|
||||
if (apiResponse.messageStatus == 2) {
|
||||
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
||||
} else if (apiResponse.messageStatus == 1) {
|
||||
patientInsuranceList = apiResponse.data!;
|
||||
isInsuranceLoading = false;
|
||||
notifyListeners();
|
||||
if (onSuccess != null) {
|
||||
onSuccess(apiResponse);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
class PatientInsuranceDetailsResponseModel {
|
||||
String? setupID;
|
||||
int? projectID;
|
||||
bool? isActive;
|
||||
int? patientID;
|
||||
int? companyID;
|
||||
int? subCategoryID;
|
||||
dynamic companyType;
|
||||
String? patientCardID;
|
||||
String? cardValidTo;
|
||||
int? patientCreditLimit;
|
||||
String? subPolicyNo;
|
||||
String? companyName;
|
||||
String? companyNameN;
|
||||
String? subCategoryDesc;
|
||||
dynamic subCategoryDescN;
|
||||
bool? isElectronicClaim;
|
||||
String? subCategoryValidTo;
|
||||
dynamic groupID;
|
||||
String? groupName;
|
||||
dynamic groupNameN;
|
||||
String? insurancePolicyNo;
|
||||
|
||||
PatientInsuranceDetailsResponseModel(
|
||||
{this.setupID,
|
||||
this.projectID,
|
||||
this.isActive,
|
||||
this.patientID,
|
||||
this.companyID,
|
||||
this.subCategoryID,
|
||||
this.companyType,
|
||||
this.patientCardID,
|
||||
this.cardValidTo,
|
||||
this.patientCreditLimit,
|
||||
this.subPolicyNo,
|
||||
this.companyName,
|
||||
this.companyNameN,
|
||||
this.subCategoryDesc,
|
||||
this.subCategoryDescN,
|
||||
this.isElectronicClaim,
|
||||
this.subCategoryValidTo,
|
||||
this.groupID,
|
||||
this.groupName,
|
||||
this.groupNameN,
|
||||
this.insurancePolicyNo});
|
||||
|
||||
PatientInsuranceDetailsResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
setupID = json['SetupID'];
|
||||
projectID = json['ProjectID'];
|
||||
isActive = json['IsActive'];
|
||||
patientID = json['PatientID'];
|
||||
companyID = json['CompanyID'];
|
||||
subCategoryID = json['SubCategoryID'];
|
||||
companyType = json['CompanyType'];
|
||||
patientCardID = json['PatientCardID'];
|
||||
cardValidTo = json['CardValidTo'];
|
||||
patientCreditLimit = json['PatientCreditLimit'];
|
||||
subPolicyNo = json['SubPolicyNo'];
|
||||
companyName = json['CompanyName'];
|
||||
companyNameN = json['CompanyNameN'];
|
||||
subCategoryDesc = json['SubCategoryDesc'];
|
||||
subCategoryDescN = json['SubCategoryDescN'];
|
||||
isElectronicClaim = json['IsElectronicClaim'];
|
||||
subCategoryValidTo = json['SubCategoryValidTo'];
|
||||
groupID = json['GroupID'];
|
||||
groupName = json['GroupName'];
|
||||
groupNameN = json['GroupNameN'];
|
||||
insurancePolicyNo = json['InsurancePolicyNo'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['SetupID'] = this.setupID;
|
||||
data['ProjectID'] = this.projectID;
|
||||
data['IsActive'] = this.isActive;
|
||||
data['PatientID'] = this.patientID;
|
||||
data['CompanyID'] = this.companyID;
|
||||
data['SubCategoryID'] = this.subCategoryID;
|
||||
data['CompanyType'] = this.companyType;
|
||||
data['PatientCardID'] = this.patientCardID;
|
||||
data['CardValidTo'] = this.cardValidTo;
|
||||
data['PatientCreditLimit'] = this.patientCreditLimit;
|
||||
data['SubPolicyNo'] = this.subPolicyNo;
|
||||
data['CompanyName'] = this.companyName;
|
||||
data['CompanyNameN'] = this.companyNameN;
|
||||
data['SubCategoryDesc'] = this.subCategoryDesc;
|
||||
data['SubCategoryDescN'] = this.subCategoryDescN;
|
||||
data['IsElectronicClaim'] = this.isElectronicClaim;
|
||||
data['SubCategoryValidTo'] = this.subCategoryValidTo;
|
||||
data['GroupID'] = this.groupID;
|
||||
data['GroupName'] = this.groupName;
|
||||
data['GroupNameN'] = this.groupNameN;
|
||||
data['InsurancePolicyNo'] = this.insurancePolicyNo;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,316 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_state.dart';
|
||||
import 'package:hmg_patient_app_new/core/dependencies.dart';
|
||||
import 'package:hmg_patient_app_new/core/enums.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart' show CustomButton;
|
||||
import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart';
|
||||
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/otp/otp.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class RegisterNew extends StatefulWidget {
|
||||
@override
|
||||
_RegisterNew createState() => _RegisterNew();
|
||||
}
|
||||
|
||||
class _RegisterNew extends State<RegisterNew> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppState appState = getIt.get<AppState>();
|
||||
AuthenticationViewModel authVm = context.read<AuthenticationViewModel>();
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bgScaffoldColor,
|
||||
appBar: CustomAppBar(
|
||||
onBackPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
onLanguageChanged: (String value) {
|
||||
// context.setLocale(value == 'en' ? Locale('ar', 'SA') : Locale('en', 'US'));
|
||||
},
|
||||
),
|
||||
body: GestureDetector(
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
child: ScrollConfiguration(
|
||||
behavior: ScrollConfiguration.of(context).copyWith(overscroll: false, physics: const ClampingScrollPhysics()),
|
||||
child: NotificationListener<OverscrollIndicatorNotification>(
|
||||
onNotification: (notification) {
|
||||
notification.disallowIndicator();
|
||||
return true;
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
physics: ClampingScrollPhysics(),
|
||||
padding: EdgeInsets.symmetric(horizontal: 24.h),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Utils.showLottie(context: context, assetPath: 'assets/animations/lottie/register.json', width: 200.h, height: 200.h, fit: BoxFit.cover, repeat: true),
|
||||
SizedBox(height: 16.h),
|
||||
LocaleKeys.prepareToElevate.tr().toText32(isBold: true),
|
||||
SizedBox(height: 24.h),
|
||||
Directionality(
|
||||
textDirection: Directionality.of(context),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.h),
|
||||
child: Column(
|
||||
children: [
|
||||
CustomCountryDropdown(
|
||||
countryList: CountryEnum.values,
|
||||
onCountryChange: authVm.onCountryChange,
|
||||
isRtl: Directionality.of(context) == TextDirection.LTR,
|
||||
).withVerticalPadding(8.h),
|
||||
Divider(height: 1.h),
|
||||
TextInputWidget(
|
||||
labelText: LocaleKeys.nationalIdNumber.tr(),
|
||||
hintText: "xxxxxxxxx",
|
||||
controller: authVm.nationalIdController,
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: true,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
autoFocus: true,
|
||||
padding: EdgeInsets.symmetric(vertical: 8.h),
|
||||
leadingIcon: AppAssets.student_card,
|
||||
// onChange: (value) {
|
||||
// print(value);
|
||||
// }
|
||||
).withVerticalPadding(8),
|
||||
Divider(height: 1),
|
||||
TextInputWidget(
|
||||
labelText: LocaleKeys.dob.tr(),
|
||||
hintText: "11 July, 1994",
|
||||
controller: authVm.dobController,
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: true,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
padding: EdgeInsets.symmetric(vertical: 8.h),
|
||||
leadingIcon: AppAssets.birthday_cake,
|
||||
selectionType: SelectionTypeEnum.calendar,
|
||||
).withVerticalPadding(8),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 25.h),
|
||||
GestureDetector(
|
||||
onTap: authVm.onTermAccepted,
|
||||
child: Row(
|
||||
children: [
|
||||
Selector<AuthenticationViewModel, bool>(
|
||||
selector: (_, viewModel) => viewModel.isTermsAccepted,
|
||||
shouldRebuild: (previous, next) => previous != next,
|
||||
builder: (context, isTermsAccepted, child) {
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: 24.h,
|
||||
width: 24.h,
|
||||
decoration: BoxDecoration(
|
||||
color: isTermsAccepted ? AppColors.primaryRedColor : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(color: isTermsAccepted ? AppColors.primaryRedBorderColor : AppColors.greyColor, width: 2.h),
|
||||
),
|
||||
child: isTermsAccepted ? Icon(Icons.check, size: 16.fSize, color: Colors.white) : null,
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(width: 12.h),
|
||||
Expanded(
|
||||
child: Text(
|
||||
LocaleKeys.iAcceptTermsConditions.tr(),
|
||||
style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 25.h),
|
||||
CustomButton(
|
||||
text: "Register",
|
||||
icon: AppAssets.note_edit,
|
||||
onPressed: () {
|
||||
showRegisterModel(context: context, authVM: authVm);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 14),
|
||||
Center(
|
||||
child: RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: context.dynamicTextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16.fSize,
|
||||
height: 26 / 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(text: LocaleKeys.alreadyHaveAccount.tr(), style: context.dynamicTextStyle()),
|
||||
TextSpan(text: " "),
|
||||
TextSpan(
|
||||
text: LocaleKeys.loginNow.tr(),
|
||||
style: context.dynamicTextStyle(
|
||||
color: AppColors.primaryRedColor,
|
||||
fontSize: 16.fSize,
|
||||
height: 26 / 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
void showRegisterModel({required BuildContext context, required AuthenticationViewModel authVM}) {
|
||||
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(
|
||||
countryCode: authVM.selectedCountrySignup.countryCode,
|
||||
initialPhoneNumber: "",
|
||||
textController: authVM.phoneNumberController,
|
||||
isEnableCountryDropdown: true,
|
||||
onCountryChange: authVM.onCountryChange,
|
||||
onChange: authVM.onPhoneNumberChange,
|
||||
buttons: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.sendOTPSMS.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (BuildContext context) => OTPVerificationPage(
|
||||
phoneNumber: '12234567',
|
||||
)));
|
||||
|
||||
// if (mobileNo.isEmpty) {
|
||||
// context.showBottomSheet(
|
||||
// child: ExceptionBottomSheet(
|
||||
// message: TranslationBase.of(context).pleaseEnterMobile,
|
||||
// showCancel: false,
|
||||
// onOkPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// } else if (!Utils.validateMobileNumber(mobileNo)) {
|
||||
// context.showBottomSheet(
|
||||
// child: ExceptionBottomSheet(
|
||||
// message: TranslationBase.of(context).pleaseEnterValidMobile,
|
||||
// showCancel: false,
|
||||
// onOkPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// } else {
|
||||
// registerUser(1);
|
||||
// }
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => OTPVerificationPage(phoneNumber: '12234567')));
|
||||
},
|
||||
backgroundColor: AppColors.primaryRedColor,
|
||||
borderColor: AppColors.primaryRedBorderColor,
|
||||
textColor: AppColors.whiteColor,
|
||||
icon: AppAssets.message,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.h),
|
||||
child: LocaleKeys.oR.tr().toText16(color: AppColors.textColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 10.h, top: 10.h),
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.sendOTPWHATSAPP.tr(),
|
||||
onPressed: () {
|
||||
// if (mobileNo.isEmpty) {
|
||||
// context.showBottomSheet(
|
||||
// child: ExceptionBottomSheet(
|
||||
// message: TranslationBase.of(context).pleaseEnterMobile,
|
||||
// showCancel: false,
|
||||
// onOkPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// } else if (!Utils.validateMobileNumber(mobileNo)) {
|
||||
// context.showBottomSheet(
|
||||
// child: ExceptionBottomSheet(
|
||||
// message: TranslationBase.of(context).pleaseEnterValidMobile,
|
||||
// showCancel: false,
|
||||
// onOkPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// } else {
|
||||
// registerUser(4);
|
||||
// }
|
||||
// int? val = Utils.onOtpBtnPressed(OTPType.whatsapp, mobileNo, context);
|
||||
// registerUser(val);
|
||||
},
|
||||
backgroundColor: AppColors.whiteColor,
|
||||
borderColor: AppColors.borderOnlyColor,
|
||||
textColor: AppColors.textColor,
|
||||
icon: AppAssets.whatsapp,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,353 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_state.dart';
|
||||
import 'package:hmg_patient_app_new/core/common_models/nationality_country_model.dart';
|
||||
import 'package:hmg_patient_app_new/core/dependencies.dart';
|
||||
import 'package:hmg_patient_app_new/core/enums.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/context_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.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/dropdown/dropdown_widget.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class RegisterNewStep2 extends StatefulWidget {
|
||||
var nHICData;
|
||||
var payload;
|
||||
|
||||
RegisterNewStep2(this.nHICData, this.payload, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_RegisterNew createState() => _RegisterNew();
|
||||
}
|
||||
|
||||
class _RegisterNew extends State<RegisterNewStep2> {
|
||||
bool isFromDubai = true;
|
||||
AuthenticationViewModel? authVM;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
authVM = context.read<AuthenticationViewModel>();
|
||||
authVM!.loadCountriesData(context: context);
|
||||
// isFromDubai = widget.payload.zipCode!.contains("971") || widget.payload.zipCode!.contains("+971");
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
authVM!.clearDefaults();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppState appState = getIt.get<AppState>();
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
onBackPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
authVM!.clearDefaults();
|
||||
},
|
||||
onLanguageChanged: (lang) {},
|
||||
hideLogoAndLang: true,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
reverse: false,
|
||||
padding: EdgeInsets.only(left: 24.h, right: 24.h, top: 24.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Directionality(
|
||||
textDirection: Directionality.of(context),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)),
|
||||
padding: EdgeInsets.only(left: 16.h, right: 16.h),
|
||||
child: Column(
|
||||
children: [
|
||||
TextInputWidget(
|
||||
labelText: isFromDubai ? LocaleKeys.fullName.tr() : LocaleKeys.name.tr(),
|
||||
hintText: isFromDubai ? "name" ?? "" : (widget.nHICData!.firstNameEn!.toUpperCase() + " " + widget.nHICData!.lastNameEn!.toUpperCase()),
|
||||
controller: null,
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: false,
|
||||
isBorderAllowed: false,
|
||||
keyboardType: TextInputType.text,
|
||||
isAllowLeadingIcon: true,
|
||||
isReadOnly: isFromDubai ? false : true,
|
||||
leadingIcon: AppAssets.user_circle)
|
||||
.paddingSymmetrical(0.h, 16.h),
|
||||
Divider(height: 1, color: AppColors.greyColor),
|
||||
TextInputWidget(
|
||||
labelText: LocaleKeys.nationalIdNumber.tr(),
|
||||
hintText: isFromDubai ? "widget.payload.nationalID!" : (widget.nHICData!.idNumber ?? ""),
|
||||
controller: null,
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: false,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
isReadOnly: true,
|
||||
leadingIcon: AppAssets.student_card)
|
||||
.paddingSymmetrical(0.h, 16.h),
|
||||
Divider(height: 1, color: AppColors.greyColor),
|
||||
isFromDubai
|
||||
? Selector<AuthenticationViewModel, GenderTypeEnum?>(
|
||||
selector: (_, authViewModel) => authViewModel.genderType,
|
||||
shouldRebuild: (previous, next) => previous != next,
|
||||
builder: (context, genderType, child) {
|
||||
final authVM = context.read<AuthenticationViewModel>();
|
||||
return DropdownWidget(
|
||||
labelText: LocaleKeys.gender.tr(),
|
||||
hintText: LocaleKeys.malE.tr(),
|
||||
isEnable: true,
|
||||
dropdownItems: GenderTypeEnum.values.map((e) => appState!.isArabic() ? e.typeAr : e.type).toList(),
|
||||
selectedValue: genderType != null ? (appState!.isArabic() ? genderType!.typeAr : genderType!.type) : "",
|
||||
onChange: authVM.onGenderChange,
|
||||
isBorderAllowed: false,
|
||||
hasSelectionCustomIcon: true,
|
||||
isAllowRadius: false,
|
||||
padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0),
|
||||
selectionCustomIcon: AppAssets.arrow_down,
|
||||
leadingIcon: AppAssets.user_full,
|
||||
).withVerticalPadding(8);
|
||||
})
|
||||
: TextInputWidget(
|
||||
labelText: LocaleKeys.gender.tr(),
|
||||
hintText: (widget.nHICData!.gender ?? ""),
|
||||
controller: null,
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: false,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
isReadOnly: isFromDubai ? false : true,
|
||||
leadingIcon: AppAssets.user_full,
|
||||
onChange: (value) {})
|
||||
.paddingSymmetrical(0.h, 16.h),
|
||||
Divider(height: 1, color: AppColors.greyColor),
|
||||
isFromDubai
|
||||
? Selector<AuthenticationViewModel, MaritalStatusTypeEnum?>(
|
||||
selector: (_, authViewModel) => authViewModel.maritalStatus,
|
||||
shouldRebuild: (previous, next) => previous != next,
|
||||
builder: (context, maritalStatus, child) {
|
||||
final authVM = context.read<AuthenticationViewModel>(); // For onChange
|
||||
return DropdownWidget(
|
||||
labelText: LocaleKeys.maritalStatus.tr(),
|
||||
hintText: LocaleKeys.married.tr(),
|
||||
isEnable: true,
|
||||
dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState!.isArabic() ? e.typeAr : e.type).toList(),
|
||||
selectedValue: maritalStatus != null ? (appState!.isArabic() ? maritalStatus.typeAr : maritalStatus.type) : "",
|
||||
onChange: authVM.onMaritalStatusChange,
|
||||
isBorderAllowed: false,
|
||||
hasSelectionCustomIcon: true,
|
||||
isAllowRadius: false,
|
||||
padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0),
|
||||
selectionCustomIcon: AppAssets.arrow_down,
|
||||
leadingIcon: AppAssets.smart_phone,
|
||||
).withVerticalPadding(8);
|
||||
},
|
||||
)
|
||||
: TextInputWidget(
|
||||
labelText: LocaleKeys.maritalStatus.tr(),
|
||||
hintText: appState!.isArabic()
|
||||
? (MaritalStatusTypeExtension.fromValue(widget.nHICData!.maritalStatusCode)!.typeAr)
|
||||
: (MaritalStatusTypeExtension.fromValue(widget.nHICData!.maritalStatusCode)!.type),
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: false,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
isReadOnly: true,
|
||||
leadingIcon: AppAssets.smart_phone,
|
||||
onChange: (value) {})
|
||||
.paddingSymmetrical(0.h, 16.h),
|
||||
Divider(height: 1, color: AppColors.greyColor),
|
||||
isFromDubai
|
||||
? Selector<AuthenticationViewModel, ({List<NationalityCountries>? countriesList, NationalityCountries? selectedCountry, bool isArabic})>(
|
||||
selector: (context, authViewModel) {
|
||||
final appState = getIt.get<AppState>();
|
||||
return (countriesList: authViewModel.countriesList, selectedCountry: authViewModel.pickedCountryByUAEUser, isArabic: appState.isArabic());
|
||||
},
|
||||
shouldRebuild: (previous, next) => previous.countriesList != next.countriesList || previous.selectedCountry != next.selectedCountry || previous.isArabic != next.isArabic,
|
||||
builder: (context, data, child) {
|
||||
final authVM = context.read<AuthenticationViewModel>();
|
||||
return DropdownWidget(
|
||||
labelText: LocaleKeys.country.tr(),
|
||||
hintText: LocaleKeys.uae.tr(),
|
||||
isEnable: true,
|
||||
dropdownItems: (data.countriesList ?? []).map((e) => data.isArabic ? e.nameN ?? "" : e.name ?? "").toList(),
|
||||
selectedValue: data.selectedCountry != null
|
||||
? data.isArabic
|
||||
? data.selectedCountry!.nameN ?? ""
|
||||
: data.selectedCountry!.name ?? ""
|
||||
: "",
|
||||
onChange: authVM.onUAEUserCountrySelection,
|
||||
isBorderAllowed: false,
|
||||
hasSelectionCustomIcon: true,
|
||||
isAllowRadius: false,
|
||||
padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0),
|
||||
selectionCustomIcon: AppAssets.arrow_down,
|
||||
leadingIcon: AppAssets.globe,
|
||||
).withVerticalPadding(8);
|
||||
},
|
||||
)
|
||||
: TextInputWidget(
|
||||
labelText: LocaleKeys.nationality.tr(),
|
||||
hintText: appState.isArabic()
|
||||
? (authVM!.countriesList!.firstWhere((e) => e.id == (widget.nHICData!.nationalityCode ?? ""), orElse: () => NationalityCountries()).nameN ?? "")
|
||||
: (authVM!.countriesList!.firstWhere((e) => e.id == (widget.nHICData!.nationalityCode ?? ""), orElse: () => NationalityCountries()).name ?? ""),
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: false,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
isReadOnly: true,
|
||||
leadingIcon: AppAssets.globe,
|
||||
onChange: (value) {})
|
||||
.paddingSymmetrical(0.h, 16.h),
|
||||
Divider(
|
||||
height: 1,
|
||||
color: AppColors.greyColor,
|
||||
),
|
||||
TextInputWidget(
|
||||
labelText: LocaleKeys.mobileNumber.tr(),
|
||||
hintText: ("widget.payload.mobileNo" ?? ""),
|
||||
controller: authVM!.phoneNumberController,
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isAllowRadius: false,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
isReadOnly: true,
|
||||
leadingIcon: AppAssets.call,
|
||||
onChange: (value) {})
|
||||
.paddingSymmetrical(0.h, 16.h),
|
||||
Divider(
|
||||
height: 1,
|
||||
color: AppColors.greyColor,
|
||||
),
|
||||
TextInputWidget(
|
||||
labelText: LocaleKeys.dob.tr(),
|
||||
hintText: isFromDubai ? "widget.payload.dob!" : (widget.nHICData!.dateOfBirth ?? ""),
|
||||
controller: authVM!.dobController,
|
||||
isEnable: true,
|
||||
prefix: null,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
isReadOnly: true,
|
||||
leadingIcon: AppAssets.birthday_cake,
|
||||
selectionType: SelectionTypeEnum.calendar,
|
||||
).paddingSymmetrical(0.h, 16.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 50.h),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.cancel.tr(),
|
||||
icon: AppAssets.cancel,
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
authVM!.clearDefaults();
|
||||
},
|
||||
backgroundColor: AppColors.secondaryLightRedColor,
|
||||
borderColor: AppColors.secondaryLightRedColor,
|
||||
textColor: AppColors.primaryRedColor,
|
||||
iconColor: AppColors.primaryRedColor,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
backgroundColor: AppColors.lightGreenColor,
|
||||
borderColor: AppColors.lightGreenColor,
|
||||
textColor: AppColors.textGreenColor,
|
||||
text: LocaleKeys.confirm.tr(),
|
||||
icon: AppAssets.confirm,
|
||||
iconColor: AppColors.textGreenColor,
|
||||
onPressed: () {
|
||||
// if (isFromDubai) {
|
||||
// if (name == null) {
|
||||
// AppToast.showErrorToast(message: LocaleKeys.enterFullName);
|
||||
// return;
|
||||
// }
|
||||
// if (!name!.contains(" ")) if (selectedGenderType == null) {
|
||||
// AppToast.showErrorToast(message: TranslationBase.of(context).enterFullName);
|
||||
// return;
|
||||
// }
|
||||
// if (selectedMaritalStatusType == null) {
|
||||
// AppToast.showErrorToast(message: TranslationBase.of(context).chooseMaritalStatus);
|
||||
// return;
|
||||
// }
|
||||
// if (selectedCountry == null) {
|
||||
// AppToast.showErrorToast(message: TranslationBase.of(context).chooseCountry);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
showModel(context: context);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void showModel({required BuildContext context}) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
isDismissible: false,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (bottomSheetContext) => Padding(
|
||||
padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom),
|
||||
child: SingleChildScrollView(
|
||||
child: GenericBottomSheet(
|
||||
textController: TextEditingController(),
|
||||
isForEmail: true,
|
||||
buttons: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.submit,
|
||||
onPressed: () {
|
||||
// if (emailAddress.text.isEmpty) {
|
||||
// Utils.showErrorToast(TranslationBase.of(context).enterEmailAddress);
|
||||
// return;
|
||||
// } else {
|
||||
// Navigator.of(context).pop();
|
||||
// registerNow();
|
||||
// }
|
||||
},
|
||||
backgroundColor: AppColors.bgGreenColor,
|
||||
borderColor: AppColors.bgGreenColor,
|
||||
textColor: AppColors.whiteColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,289 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.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/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/authentication/login.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
|
||||
|
||||
class SavedLogin extends StatefulWidget {
|
||||
// final SelectDeviceIMEIRES savedLoginData;
|
||||
|
||||
// const SavedLogin(this.savedLoginData, {Key? key}) : super(key: key);
|
||||
const SavedLogin();
|
||||
|
||||
@override
|
||||
_SavedLogin createState() => _SavedLogin();
|
||||
}
|
||||
|
||||
class _SavedLogin extends State<SavedLogin> {
|
||||
LoginTypeEnum loginType = LoginTypeEnum.sms;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
onBackPressed: () {},
|
||||
onLanguageChanged: (lang) {},
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Spacer(flex: 2),
|
||||
// Welcome back text
|
||||
LocaleKeys.welcomeBack.tr().toText16(color: AppColors.inputLabelTextColor),
|
||||
SizedBox(height: 16.h),
|
||||
("widget.savedLoginData.name!.toLowerCase().capitalizeFirstofEach").toText26(isBold: true, height: 26 / 36, color: AppColors.textColor),
|
||||
SizedBox(height: 24.h),
|
||||
Container(
|
||||
padding: EdgeInsets.all(16.h),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
border: Border.all(color: AppColors.whiteColor),
|
||||
borderRadius: BorderRadius.circular(24.h),
|
||||
boxShadow: [
|
||||
BoxShadow(color: Color(0x0D000000), blurRadius: 16, offset: Offset(0, 0), spreadRadius: 5),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Last login info
|
||||
('LocaleKeys.lastloginBy.tr()' + ' {getType(widget.savedLoginData.logInType!, context)}').toText14(isBold: true, color: AppColors.greyTextColor),
|
||||
('widget.savedLoginData.createdOn != null ? DateUtil.getFormattedDate(DateUtil.convertStringToDate(widget.savedLoginData.createdOn!), "d MMMM, y at HH:mm") : --')
|
||||
.toText16(isBold: true, color: AppColors.textColor),
|
||||
|
||||
Container(margin: EdgeInsets.all(16.h), child: Utils.buildSvgWithAssets(icon: getTypeIcons(loginType.toInt), iconColor: loginType.toInt == 4 ? null : AppColors.primaryRedColor)),
|
||||
// Face ID login button
|
||||
Container(
|
||||
height: 45,
|
||||
child: CustomButton(
|
||||
text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}",
|
||||
onPressed: () {
|
||||
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
|
||||
// loginWithFingerPrintFace(loginType.toInt, widget.savedLoginData.iMEI!);
|
||||
} else {
|
||||
int? val = loginType.toInt;
|
||||
//checkUserAuthentication(val);
|
||||
}
|
||||
},
|
||||
backgroundColor: Color(0xffED1C2B),
|
||||
borderColor: Color(0xffFEE9EA),
|
||||
textColor: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
borderRadius: 12,
|
||||
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
|
||||
icon: AppAssets.apple_finder,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Text(
|
||||
LocaleKeys.oR.tr(),
|
||||
style: context.dynamicTextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
// OTP login button
|
||||
loginType != null && loginType.toInt != 1
|
||||
? Column(
|
||||
children: [
|
||||
loginType.toInt != 1
|
||||
? CustomButton(
|
||||
text: LocaleKeys.loginByOTP.tr(),
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
isDismissible: false,
|
||||
useSafeArea: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
enableDrag: false,
|
||||
// Prevent dragging to avoid focus conflicts
|
||||
builder: (bottomSheetContext) => StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom),
|
||||
child: SingleChildScrollView(
|
||||
child: GenericBottomSheet(
|
||||
countryCode: "966",
|
||||
initialPhoneNumber: "",
|
||||
textController: TextEditingController(),
|
||||
isFromSavedLogin: true,
|
||||
isEnableCountryDropdown: true,
|
||||
onCountryChange: (value) {},
|
||||
onChange: (String? value) {},
|
||||
buttons: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 10.h),
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.sendOTPSMS.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
loginType = LoginTypeEnum.sms;
|
||||
int? val = loginType.toInt;
|
||||
// checkUserAuthentication(val);
|
||||
},
|
||||
backgroundColor: AppColors.primaryRedColor,
|
||||
borderColor: AppColors.primaryRedBorderColor,
|
||||
textColor: AppColors.whiteColor,
|
||||
icon: AppAssets.message,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 8.h), child: (LocaleKeys.oR.tr()).toText16(color: AppColors.textColor)),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10, top: 10),
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.sendOTPWHATSAPP.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
loginType = LoginTypeEnum.whatsapp;
|
||||
int? val = loginType.toInt;
|
||||
// checkUserAuthentication(val);
|
||||
},
|
||||
backgroundColor: AppColors.transparent,
|
||||
borderColor: AppColors.textColor,
|
||||
textColor: AppColors.textColor,
|
||||
icon: AppAssets.whatsapp,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
},
|
||||
backgroundColor: AppColors.whiteColor,
|
||||
borderColor: AppColors.borderOnlyColor,
|
||||
textColor: AppColors.textColor,
|
||||
borderWidth: 2,
|
||||
padding: EdgeInsets.fromLTRB(0, 14, 0, 14),
|
||||
icon: AppAssets.password_validation,
|
||||
)
|
||||
: Container(),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
)
|
||||
: CustomButton(
|
||||
text: "${LocaleKeys.loginBy.tr()} ${LoginTypeEnum.whatsapp.displayName}",
|
||||
onPressed: () {
|
||||
if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) {
|
||||
// loginWithFingerPrintFace(loginType.toInt, "iMEI");
|
||||
} else {
|
||||
loginType = LoginTypeEnum.whatsapp;
|
||||
int? val = loginType.toInt;
|
||||
// checkUserAuthentication(val);
|
||||
}
|
||||
},
|
||||
backgroundColor: AppColors.whiteColor,
|
||||
borderColor: Color(0xFF2E3039),
|
||||
textColor: Color(0xFF2E3039),
|
||||
borderWidth: 2,
|
||||
padding: EdgeInsets.fromLTRB(0, 14, 0, 14),
|
||||
icon: AppAssets.whatsapp,
|
||||
),
|
||||
const Spacer(flex: 2),
|
||||
// OR divider
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Guest and Switch account
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 56,
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.guest.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(builder: (BuildContext context) => LoginScreen()),
|
||||
);
|
||||
},
|
||||
backgroundColor: Color(0xffFEE9EA),
|
||||
borderColor: Color(0xffFEE9EA),
|
||||
textColor: Color(0xffED1C2B),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
borderRadius: 12,
|
||||
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
|
||||
// icon: "assets/images/svg/apple-finder.svg",
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.05,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 56,
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.switchAccount.tr(),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(builder: (BuildContext context) => LoginScreen()),
|
||||
);
|
||||
},
|
||||
backgroundColor: Color(0xffFEE9EA),
|
||||
borderColor: Color(0xffFEE9EA),
|
||||
textColor: Color(0xffED1C2B),
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
borderRadius: 12,
|
||||
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
|
||||
// icon: "assets/images/svg/apple-finder.svg",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String getTypeIcons(int type) {
|
||||
final types = {
|
||||
1: AppAssets.sms,
|
||||
2: AppAssets.fingerprint,
|
||||
3: AppAssets.fingerprint,
|
||||
4: AppAssets.whatsapp,
|
||||
};
|
||||
|
||||
if (types.containsKey(type)) {
|
||||
return types[type]!;
|
||||
} else {
|
||||
throw Exception('Invalid login type: $type');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
import 'dart:async';
|
||||
|
||||
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/date_util.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/insurance/insurance_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.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/shimmer/movies_shimmer_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'widgets/insurance_history.dart';
|
||||
|
||||
class InsuranceHomePage extends StatefulWidget {
|
||||
const InsuranceHomePage({super.key});
|
||||
|
||||
@override
|
||||
State<InsuranceHomePage> createState() => _InsuranceHomePageState();
|
||||
}
|
||||
|
||||
class _InsuranceHomePageState extends State<InsuranceHomePage> {
|
||||
late InsuranceViewModel insuranceViewModel;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
scheduleMicrotask(() {
|
||||
insuranceViewModel.initInsuranceProvider();
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
insuranceViewModel = Provider.of<InsuranceViewModel>(context);
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bgScaffoldColor,
|
||||
appBar: AppBar(
|
||||
title: LocaleKeys.insurance.tr(context: context).toText18(),
|
||||
backgroundColor: AppColors.bgScaffoldColor,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
"${LocaleKeys.insurance.tr(context: context)} ${LocaleKeys.updateInsurance.tr(context: context)}".toText24(isBold: true),
|
||||
CustomButton(
|
||||
icon: AppAssets.insurance_history_icon,
|
||||
iconColor: AppColors.primaryRedColor,
|
||||
iconSize: 21.h,
|
||||
text: LocaleKeys.history.tr(context: context),
|
||||
onPressed: () {
|
||||
insuranceVM.setIsInsuranceHistoryLoading(true);
|
||||
showCommonBottomSheet(context,
|
||||
child: InsuranceHistory(), callBackFunc: () {}, title: "", height: ResponsiveExtension.screenHeight * 0.5, isCloseButtonVisible: false, isFullScreen: false);
|
||||
},
|
||||
backgroundColor: AppColors.primaryRedColor.withOpacity(0.1),
|
||||
borderColor: AppColors.primaryRedColor.withOpacity(0.0),
|
||||
textColor: AppColors.primaryRedColor,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
borderRadius: 12,
|
||||
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||
height: 40.h,
|
||||
),
|
||||
],
|
||||
).paddingSymmetrical(24.h, 24.h),
|
||||
insuranceVM.isInsuranceLoading
|
||||
? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0)
|
||||
: PatientInsuranceCard(
|
||||
insuranceCardDetailsModel: insuranceVM.patientInsuranceList.first,
|
||||
isInsuranceExpired: DateTime.now().isAfter(DateUtil.convertStringToDate(insuranceVM.patientInsuranceList.first.cardValidTo))),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
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/features/insurance/insurance_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class InsuranceHistory extends StatelessWidget {
|
||||
InsuranceHistory({super.key});
|
||||
|
||||
late InsuranceViewModel insuranceViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
insuranceViewModel = Provider.of<InsuranceViewModel>(context);
|
||||
return Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
LocaleKeys.history.tr(context: context).toText24(isBold: true),
|
||||
Utils.buildSvgWithAssets(icon: AppAssets.close_bottom_sheet_icon).onPress(() {
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
],
|
||||
).paddingSymmetrical(24.h, 24.h),
|
||||
insuranceVM.isInsuranceHistoryLoading ? const MoviesShimmerWidget().paddingSymmetrical(24.h, 24.h) : Container()
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
|
||||
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
|
||||
import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patient_insurance_details_response_model.dart';
|
||||
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class PatientInsuranceCard extends StatelessWidget {
|
||||
PatientInsuranceCard({super.key, required this.insuranceCardDetailsModel, required this.isInsuranceExpired});
|
||||
|
||||
PatientInsuranceDetailsResponseModel insuranceCardDetailsModel;
|
||||
bool isInsuranceExpired = false;
|
||||
|
||||
late InsuranceViewModel insuranceViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
insuranceViewModel = Provider.of<InsuranceViewModel>(context);
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: AppColors.whiteColor,
|
||||
borderRadius: 24,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
"Haroon Amjad".toText18(isBold: true),
|
||||
"Policy: ${insuranceCardDetailsModel.insurancePolicyNo}".toText12(isBold: true, color: AppColors.lightGrayColor),
|
||||
],
|
||||
),
|
||||
CustomButton(
|
||||
icon: isInsuranceExpired ? AppAssets.cancel_circle_icon : AppAssets.insurance_active_icon,
|
||||
iconColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor,
|
||||
iconSize: 13.h,
|
||||
text: isInsuranceExpired ? "Insurance Expired" : "Insurance Active",
|
||||
onPressed: () {},
|
||||
backgroundColor: isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.15) : AppColors.successColor.withOpacity(0.15),
|
||||
borderColor: isInsuranceExpired ? AppColors.primaryRedColor.withOpacity(0.01) : AppColors.successColor.withOpacity(0.01),
|
||||
textColor: isInsuranceExpired ? AppColors.primaryRedColor : AppColors.successColor,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
borderRadius: 12,
|
||||
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||
height: 30.h,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 12.h),
|
||||
insuranceCardDetailsModel.groupName!.toText12(isBold: true),
|
||||
insuranceCardDetailsModel.companyName!.toText12(isBold: true),
|
||||
SizedBox(height: 8.h),
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
spacing: 6.h,
|
||||
runSpacing: 6.h,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CustomButton(
|
||||
icon: AppAssets.doctor_calendar_icon,
|
||||
iconColor: AppColors.blackColor,
|
||||
iconSize: 13.h,
|
||||
text: "${LocaleKeys.expiryDate.tr(context: context)} ${DateUtil.formatDateToDate(DateUtil.convertStringToDate(insuranceCardDetailsModel.cardValidTo), false)}",
|
||||
onPressed: () {},
|
||||
backgroundColor: AppColors.greyColor,
|
||||
borderColor: AppColors.greyColor,
|
||||
textColor: AppColors.blackColor,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
borderRadius: 12,
|
||||
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||
height: 30.h,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
CustomButton(
|
||||
text: "Patient Card ID: ${insuranceCardDetailsModel.patientCardID}",
|
||||
onPressed: () {},
|
||||
backgroundColor: AppColors.greyColor,
|
||||
borderColor: AppColors.greyColor,
|
||||
textColor: AppColors.blackColor,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
borderRadius: 12,
|
||||
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||
height: 30.h,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.h),
|
||||
isInsuranceExpired
|
||||
? CustomButton(
|
||||
icon: AppAssets.update_insurance_card_icon,
|
||||
iconColor: AppColors.successColor,
|
||||
iconSize: 15.h,
|
||||
text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}",
|
||||
onPressed: () {},
|
||||
backgroundColor: AppColors.bgGreenColor.withOpacity(0.20),
|
||||
borderColor: AppColors.bgGreenColor.withOpacity(0.0),
|
||||
textColor: AppColors.bgGreenColor,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
borderRadius: 12,
|
||||
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
|
||||
height: 40.h,
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
),
|
||||
).paddingSymmetrical(24.h, 0.h);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||
import 'package:hmg_patient_app_new/core/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/generated/locale_keys.g.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
|
||||
|
||||
class ExceptionBottomSheet extends StatelessWidget {
|
||||
String message;
|
||||
bool showOKButton;
|
||||
bool showCancel;
|
||||
Function() onOkPressed;
|
||||
Function()? onCancelPressed;
|
||||
|
||||
ExceptionBottomSheet({Key? key, required this.message, this.showOKButton = true, this.showCancel = false, required this.onOkPressed, this.onCancelPressed}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
bottom: Platform.isIOS ? false : true, // Adjust for iOS to avoid bottom padding
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside
|
||||
},
|
||||
child: Builder(builder: (context) {
|
||||
return Directionality(
|
||||
textDirection: Directionality.of(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(24.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFF8F8FA),
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
LocaleKeys.notice.tr().toText28(),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Utils.buildSvgWithAssets(icon: AppAssets.cross_circle),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.h),
|
||||
(message ?? "").toText16(isBold: false, color: AppColors.textColor),
|
||||
SizedBox(height: 10.h),
|
||||
SizedBox(height: 24.h),
|
||||
if (showOKButton && showCancel)
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.cancel.tr(),
|
||||
onPressed: onCancelPressed != null
|
||||
? onCancelPressed!
|
||||
: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
backgroundColor: AppColors.secondaryLightRedColor,
|
||||
borderColor: AppColors.secondaryLightRedColor,
|
||||
textColor: AppColors.primaryRedColor,
|
||||
icon: AppAssets.cancel,
|
||||
iconColor: AppColors.primaryRedColor,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5.h),
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
text: showCancel ? LocaleKeys.confirm.tr() : LocaleKeys.ok.tr(),
|
||||
onPressed: onOkPressed,
|
||||
backgroundColor: AppColors.bgGreenColor,
|
||||
borderColor: AppColors.bgGreenColor,
|
||||
textColor: Colors.white,
|
||||
icon: AppAssets.confirm,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (showOKButton && !showCancel)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 10.h),
|
||||
child: CustomButton(
|
||||
text: LocaleKeys.ok.tr(),
|
||||
onPressed: onOkPressed,
|
||||
backgroundColor: AppColors.primaryRedColor,
|
||||
borderColor: AppColors.primaryRedBorderColor,
|
||||
textColor: Colors.white,
|
||||
icon: AppAssets.confirm,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
import 'dart:io';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||
import 'package:hmg_patient_app_new/core/enums.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';
|
||||
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
|
||||
|
||||
class GenericBottomSheet extends StatefulWidget {
|
||||
String? countryCode;
|
||||
String? initialPhoneNumber;
|
||||
final List<Widget> buttons;
|
||||
TextEditingController? textController;
|
||||
final bool isForEmail;
|
||||
Function(CountryEnum)? onCountryChange;
|
||||
final bool isEnableCountryDropdown;
|
||||
final bool isFromSavedLogin;
|
||||
Function(String?)? onChange;
|
||||
|
||||
// FocusNode myFocusNode;
|
||||
|
||||
GenericBottomSheet({
|
||||
this.countryCode = "",
|
||||
this.initialPhoneNumber = "",
|
||||
required this.buttons,
|
||||
this.textController,
|
||||
this.isForEmail = false,
|
||||
this.onCountryChange,
|
||||
this.isEnableCountryDropdown = false,
|
||||
this.isFromSavedLogin = false,
|
||||
this.onChange,
|
||||
// required this.myFocusNode
|
||||
});
|
||||
|
||||
@override
|
||||
_GenericBottomSheetState createState() => _GenericBottomSheetState();
|
||||
}
|
||||
|
||||
class _GenericBottomSheetState extends State<GenericBottomSheet> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
if (!widget.isForEmail && widget.textController != null) {
|
||||
widget.textController!.text = widget.initialPhoneNumber!;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
top: false,
|
||||
bottom: Platform.isIOS ? false : true,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
child: Directionality(
|
||||
textDirection: Directionality.of(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(24.h),
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.bgScaffoldColor, borderRadius: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Title
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: widget.isFromSavedLogin
|
||||
? LocaleKeys.receiveOtpToast.tr().toText24()
|
||||
: widget.isForEmail
|
||||
? LocaleKeys.enterEmail.tr().toText24()
|
||||
: LocaleKeys.enterPhoneNumber.tr().toText24()),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 10.h),
|
||||
child: Utils.buildSvgWithAssets(icon: AppAssets.cross_circle),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
// Subtitle
|
||||
widget.isFromSavedLogin
|
||||
? LocaleKeys.pleaseChooseOption.tr().toText16()
|
||||
: widget.isForEmail
|
||||
? LocaleKeys.enterEmailDesc.tr().toText16()
|
||||
: LocaleKeys.enterPhoneDesc.tr().toText16(),
|
||||
|
||||
if (widget.isFromSavedLogin)
|
||||
...[]
|
||||
else ...[
|
||||
widget.textController != null
|
||||
? TextInputWidget(
|
||||
labelText: widget.isForEmail ? LocaleKeys.email : LocaleKeys.phoneNumber,
|
||||
hintText: widget.isForEmail ? "demo@gmail.com" : "5xxxxxxxx",
|
||||
controller: widget.textController!,
|
||||
padding: EdgeInsets.all(8.h),
|
||||
keyboardType: widget.isForEmail ? TextInputType.emailAddress : TextInputType.number,
|
||||
onChange: (value) {
|
||||
if (widget.onChange != null) {
|
||||
widget.onChange!(value);
|
||||
}
|
||||
},
|
||||
onCountryChange: (value) {
|
||||
if (widget.onCountryChange != null) {
|
||||
widget.onCountryChange!(value);
|
||||
}
|
||||
},
|
||||
isEnable: true,
|
||||
isReadOnly: widget.isFromSavedLogin,
|
||||
prefix: widget.isForEmail ? null : widget.countryCode,
|
||||
isBorderAllowed: false,
|
||||
isAllowLeadingIcon: true,
|
||||
isCountryDropDown: widget.isEnableCountryDropdown,
|
||||
leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone,
|
||||
)
|
||||
: SizedBox(),
|
||||
],
|
||||
|
||||
SizedBox(height: 24.h),
|
||||
...widget.buttons,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,210 @@
|
||||
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/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';
|
||||
|
||||
class CustomCountryDropdown extends StatefulWidget {
|
||||
final List<CountryEnum> countryList;
|
||||
final Function(CountryEnum)? onCountryChange;
|
||||
final Function(String)? onPhoneNumberChanged;
|
||||
final bool isRtl;
|
||||
final bool isFromBottomSheet;
|
||||
final bool isEnableTextField;
|
||||
Widget? textField;
|
||||
|
||||
CustomCountryDropdown({
|
||||
Key? key,
|
||||
required this.countryList,
|
||||
this.onCountryChange,
|
||||
this.onPhoneNumberChanged,
|
||||
required this.isRtl,
|
||||
this.isFromBottomSheet = false,
|
||||
this.isEnableTextField = false,
|
||||
this.textField,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_CustomCountryDropdownState createState() => _CustomCountryDropdownState();
|
||||
}
|
||||
|
||||
class _CustomCountryDropdownState extends State<CustomCountryDropdown> {
|
||||
CountryEnum? selectedCountry;
|
||||
late OverlayEntry _overlayEntry;
|
||||
bool _isDropdownOpen = false;
|
||||
FocusNode textFocusNode = new FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
selectedCountry = CountryEnum.saudiArabia;
|
||||
|
||||
if (widget.isEnableTextField && widget.isFromBottomSheet) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted && textFocusNode.canRequestFocus) {
|
||||
FocusScope.of(context).requestFocus(textFocusNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
textFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 40.h,
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 10.h),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (_isDropdownOpen) {
|
||||
_closeDropdown();
|
||||
} else {
|
||||
_openDropdown();
|
||||
}
|
||||
},
|
||||
child: Utils.buildSvgWithAssets(icon: selectedCountry != null ? selectedCountry!.iconPath : AppAssets.ksa, width: 40.h, height: 40.h)),
|
||||
SizedBox(width: 8.h),
|
||||
Utils.buildSvgWithAssets(icon: _isDropdownOpen ? AppAssets.dropdow_icon : AppAssets.dropdow_icon),
|
||||
SizedBox(width: 4.h),
|
||||
if (widget.isFromBottomSheet)
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (widget.isEnableTextField && textFocusNode.canRequestFocus) {
|
||||
FocusScope.of(context).requestFocus(textFocusNode);
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
LocaleKeys.phoneNumber.tr(),
|
||||
style: TextStyle(fontSize: 12.fSize, height: 21 / 12, fontWeight: FontWeight.w500, letterSpacing: -1),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
selectedCountry!.countryCode,
|
||||
style: TextStyle(fontSize: 12.fSize, height: 21 / 18, fontWeight: FontWeight.w600, letterSpacing: -0.2),
|
||||
),
|
||||
SizedBox(width: 4.h),
|
||||
if (widget.isEnableTextField)
|
||||
SizedBox(
|
||||
height: 20,
|
||||
width: 200,
|
||||
child: TextField(
|
||||
focusNode: textFocusNode,
|
||||
decoration: InputDecoration(hintText: "", isDense: true, border: InputBorder.none),
|
||||
keyboardType: TextInputType.phone,
|
||||
onChanged: widget.onPhoneNumberChanged),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
if (!widget.isFromBottomSheet)
|
||||
Text(
|
||||
selectedCountry != null ? selectedCountry!.displayName : "Select Country",
|
||||
style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, letterSpacing: -0.2),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openDropdown() {
|
||||
if (textFocusNode.hasFocus) {
|
||||
textFocusNode.unfocus();
|
||||
}
|
||||
|
||||
RenderBox renderBox = context.findRenderObject() as RenderBox;
|
||||
Offset offset = renderBox.localToGlobal(Offset.zero);
|
||||
|
||||
_overlayEntry = OverlayEntry(
|
||||
builder: (context) => Stack(
|
||||
children: [
|
||||
// Dismiss dropdown when tapping outside
|
||||
Positioned.fill(
|
||||
child: GestureDetector(
|
||||
onTap: _closeDropdown,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: Container(),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: offset.dy + renderBox.size.height,
|
||||
left: widget.isRtl ? offset.dx + 6.h : offset.dx - 6.h,
|
||||
width: renderBox.size.width,
|
||||
child: Material(
|
||||
child: Container(
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: Colors.white, borderRadius: 12),
|
||||
child: Column(
|
||||
children: widget.countryList
|
||||
.map(
|
||||
(country) => GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedCountry = country;
|
||||
});
|
||||
widget.onCountryChange?.call(country);
|
||||
_closeDropdown();
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h),
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 16.h),
|
||||
child: Row(
|
||||
children: [
|
||||
Utils.buildSvgWithAssets(icon: country.iconPath, width: 38.h, height: 38.h),
|
||||
if (!widget.isFromBottomSheet) SizedBox(width: 12.h),
|
||||
if (!widget.isFromBottomSheet) Text(country.displayName, style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, letterSpacing: -0.2)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Overlay.of(context)?.insert(_overlayEntry);
|
||||
setState(() {
|
||||
_isDropdownOpen = true;
|
||||
});
|
||||
}
|
||||
|
||||
void _closeDropdown() {
|
||||
_overlayEntry.remove();
|
||||
setState(() {
|
||||
_isDropdownOpen = false;
|
||||
});
|
||||
|
||||
if (widget.isEnableTextField && widget.isFromBottomSheet) {
|
||||
Future.delayed(Duration(milliseconds: 100), () {
|
||||
if (mounted && textFocusNode.canRequestFocus) {
|
||||
FocusScope.of(context).requestFocus(textFocusNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart' show Icons, PopupMenuItem, showMenu, Colors;
|
||||
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/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
|
||||
class DropdownWidget extends StatelessWidget {
|
||||
final String labelText;
|
||||
final String hintText;
|
||||
final List<String> dropdownItems;
|
||||
final String? selectedValue;
|
||||
final Function(String?)? onChange;
|
||||
final bool isEnable;
|
||||
final bool isBorderAllowed;
|
||||
final bool isAllowRadius;
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final bool hasSelectionCustomIcon;
|
||||
final String? selectionCustomIcon;
|
||||
final String? leadingIcon;
|
||||
|
||||
const DropdownWidget({
|
||||
Key? key,
|
||||
required this.labelText,
|
||||
required this.hintText,
|
||||
required this.dropdownItems,
|
||||
this.selectedValue,
|
||||
this.onChange,
|
||||
this.isEnable = true,
|
||||
this.isBorderAllowed = true,
|
||||
this.isAllowRadius = true,
|
||||
this.padding,
|
||||
this.hasSelectionCustomIcon = false,
|
||||
this.selectionCustomIcon,
|
||||
this.leadingIcon,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget content = Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [_buildLabelText(), _buildDropdown(context)],
|
||||
);
|
||||
|
||||
return Container(
|
||||
padding: padding,
|
||||
alignment: Alignment.center, // This might need adjustment based on layout
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: isAllowRadius ? 15.h : null,
|
||||
side: isBorderAllowed ? BorderSide(color: const Color(0xffefefef), width: 1) : null,
|
||||
),
|
||||
child: Row(
|
||||
// Wrap with a Row
|
||||
crossAxisAlignment: CrossAxisAlignment.center, // Align items vertically in the center
|
||||
children: [
|
||||
if (leadingIcon != null) ...[
|
||||
_buildLeadingIcon(),
|
||||
SizedBox(width: 3.h),
|
||||
],
|
||||
Expanded(child: content),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLeadingIcon() {
|
||||
return Container(
|
||||
height: 40.h,
|
||||
width: 40.h,
|
||||
margin: EdgeInsets.only(right: 10.h),
|
||||
padding: EdgeInsets.all(8.h),
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(borderRadius: 10.h, color: AppColors.greyColor),
|
||||
child: Utils.buildSvgWithAssets(icon: leadingIcon!));
|
||||
}
|
||||
|
||||
Widget _buildLabelText() {
|
||||
return Text(
|
||||
labelText,
|
||||
style: TextStyle(
|
||||
fontSize: 12.fSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xff898A8D),
|
||||
letterSpacing: -0.2,
|
||||
height: 18 / 12,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDropdown(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: isEnable
|
||||
? () async {
|
||||
final renderBox = context.findRenderObject() as RenderBox;
|
||||
final offset = renderBox.localToGlobal(Offset.zero);
|
||||
final selected = await showMenu<String>(
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(
|
||||
offset.dx,
|
||||
offset.dy + renderBox.size.height,
|
||||
offset.dx + renderBox.size.width,
|
||||
0,
|
||||
),
|
||||
items: dropdownItems
|
||||
.map(
|
||||
(e) => PopupMenuItem<String>(
|
||||
value: e,
|
||||
child: Text(
|
||||
e,
|
||||
style: TextStyle(
|
||||
fontSize: 14.fSize,
|
||||
height: 21 / 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: -0.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
);
|
||||
|
||||
if (selected != null && onChange != null) {
|
||||
onChange!(selected);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
(selectedValue == null || selectedValue!.isEmpty) ? hintText : selectedValue!,
|
||||
textAlign: TextAlign.left,
|
||||
textDirection: TextDirection.ltr,
|
||||
style: TextStyle(
|
||||
fontSize: 14.fSize,
|
||||
height: 21 / 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: (selectedValue != null && selectedValue!.isNotEmpty) ? const Color(0xff2E3039) : const Color(0xffB0B0B0),
|
||||
letterSpacing: -0.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hasSelectionCustomIcon && selectionCustomIcon != null) Utils.buildSvgWithAssets(icon: selectionCustomIcon!) else const Icon(Icons.keyboard_arrow_down_outlined),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,132 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart' show Icons, PopupMenuItem, showMenu, Colors;
|
||||
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
||||
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
|
||||
|
||||
class DropdownWidget extends StatelessWidget {
|
||||
final String labelText;
|
||||
final String hintText;
|
||||
final List<String> dropdownItems;
|
||||
final String? selectedValue;
|
||||
final Function(String?)? onChange;
|
||||
final bool isEnable;
|
||||
final bool isBorderAllowed;
|
||||
final bool isAllowRadius;
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final bool hasSelectionCustomIcon;
|
||||
final String? selectionCustomIcon;
|
||||
|
||||
const DropdownWidget({
|
||||
Key? key,
|
||||
required this.labelText,
|
||||
required this.hintText,
|
||||
required this.dropdownItems,
|
||||
this.selectedValue,
|
||||
this.onChange,
|
||||
this.isEnable = true,
|
||||
this.isBorderAllowed = true,
|
||||
this.isAllowRadius = true,
|
||||
this.padding,
|
||||
this.hasSelectionCustomIcon = false,
|
||||
this.selectionCustomIcon,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: padding,
|
||||
alignment: Alignment.center,
|
||||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: isAllowRadius ? 15 : null,
|
||||
side: isBorderAllowed
|
||||
? BorderSide(color: const Color(0xffefefef), width: 1)
|
||||
: null,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildLabelText(),
|
||||
_buildDropdown(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLabelText() {
|
||||
return Text(
|
||||
labelText,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xff898A8D),
|
||||
letterSpacing: -0.2,
|
||||
height: 18 / 12,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDropdown(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: isEnable
|
||||
? () async {
|
||||
final renderBox = context.findRenderObject() as RenderBox;
|
||||
final offset = renderBox.localToGlobal(Offset.zero);
|
||||
final selected = await showMenu<String>(
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(
|
||||
offset.dx,
|
||||
offset.dy + renderBox.size.height,
|
||||
offset.dx + renderBox.size.width,
|
||||
0,
|
||||
),
|
||||
items: dropdownItems
|
||||
.map(
|
||||
(e) => PopupMenuItem<String>(
|
||||
value: e,
|
||||
child: Text(e),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
);
|
||||
|
||||
if (selected != null && onChange != null) {
|
||||
onChange!(selected);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
(selectedValue == null || selectedValue!.isEmpty)
|
||||
? hintText
|
||||
: selectedValue!,
|
||||
textAlign: TextAlign.left,
|
||||
textDirection: TextDirection.ltr,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
height: 21 / 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: (selectedValue != null && selectedValue!.isNotEmpty)
|
||||
? const Color(0xff2E3039)
|
||||
: const Color(0xffB0B0B0),
|
||||
letterSpacing: -0.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hasSelectionCustomIcon && selectionCustomIcon != null)
|
||||
Utils.buildSvgWithAssets(icon: selectionCustomIcon!)
|
||||
else
|
||||
const Icon(Icons.keyboard_arrow_down_outlined),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,230 @@
|
||||
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/extensions/widget_extensions.dart';
|
||||
import 'package:hmg_patient_app_new/presentation/authentication/register_step2.dart';
|
||||
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||
import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart';
|
||||
|
||||
class OTPVerificationPage extends StatefulWidget {
|
||||
final String phoneNumber;
|
||||
|
||||
const OTPVerificationPage({Key? key, required this.phoneNumber}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<OTPVerificationPage> createState() => _OTPVerificationPageState();
|
||||
}
|
||||
|
||||
class _OTPVerificationPageState extends State<OTPVerificationPage> {
|
||||
final int _otpLength = 4;
|
||||
late final List<TextEditingController> _controllers;
|
||||
late final List<FocusNode> _focusNodes;
|
||||
|
||||
Timer? _resendTimer;
|
||||
int _resendTime = 60;
|
||||
bool _isOtpComplete = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controllers = List.generate(_otpLength, (_) => TextEditingController());
|
||||
_focusNodes = List.generate(_otpLength, (_) => FocusNode());
|
||||
_startResendTimer();
|
||||
|
||||
// Focus the first field once the screen is built
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (_focusNodes.isNotEmpty) {
|
||||
FocusScope.of(context).requestFocus(_focusNodes[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
for (final c in _controllers) c.dispose();
|
||||
for (final f in _focusNodes) f.dispose();
|
||||
_resendTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _startResendTimer() {
|
||||
_resendTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (_resendTime > 0) {
|
||||
setState(() => _resendTime--);
|
||||
} else {
|
||||
timer.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _onOtpChanged(int index, String value) {
|
||||
if (value.length == 1 && index < _otpLength - 1) {
|
||||
_focusNodes[index + 1].requestFocus();
|
||||
} else if (value.isEmpty && index > 0) {
|
||||
_focusNodes[index - 1].requestFocus();
|
||||
}
|
||||
_checkOtpCompletion();
|
||||
}
|
||||
|
||||
void _checkOtpCompletion() {
|
||||
final isComplete = _controllers.every((c) => c.text.isNotEmpty);
|
||||
|
||||
if (isComplete != _isOtpComplete) {
|
||||
setState(() => _isOtpComplete = isComplete);
|
||||
|
||||
if (isComplete) {
|
||||
_verifyOtp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _resendOtp() {
|
||||
if (_resendTime == 0) {
|
||||
setState(() => _resendTime = 60);
|
||||
_startResendTimer();
|
||||
autoFillOtp("1234");
|
||||
|
||||
// call resend API here
|
||||
}
|
||||
}
|
||||
|
||||
String _getMaskedPhoneNumber() {
|
||||
final phone = widget.phoneNumber;
|
||||
return phone.length > 4 ? '05xxxxxx${phone.substring(phone.length - 2)}' : phone;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
hideLogoAndLang: true,
|
||||
onBackPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
onLanguageChanged: (lang) {},
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24.h),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 40.h),
|
||||
Text(
|
||||
'OTP Verification',
|
||||
style: TextStyle(fontSize: 24.fSize, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
Text(
|
||||
'We have sent you the OTP code on ${_getMaskedPhoneNumber()} via SMS for registration verification',
|
||||
style: TextStyle(fontSize: 16.fSize, color: Colors.grey),
|
||||
),
|
||||
SizedBox(height: 40.h),
|
||||
|
||||
// OTP Input Fields
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: List.generate(_otpLength, (index) {
|
||||
return ValueListenableBuilder<TextEditingValue>(
|
||||
valueListenable: _controllers[index],
|
||||
builder: (context, value, _) {
|
||||
final hasText = value.text.isNotEmpty;
|
||||
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.easeInOut,
|
||||
width: 70.h,
|
||||
margin: EdgeInsets.symmetric(horizontal: 4.h),
|
||||
decoration: RoundedRectangleBorder()
|
||||
.toSmoothCornerDecoration(color: _isOtpComplete ? AppColors.successColor : (hasText ? AppColors.blackBgColor : AppColors.whiteColor), borderRadius: 16),
|
||||
child: Center(
|
||||
child: TextField(
|
||||
controller: _controllers[index],
|
||||
focusNode: _focusNodes[index],
|
||||
textAlign: TextAlign.center,
|
||||
keyboardType: TextInputType.number,
|
||||
maxLength: 1,
|
||||
style: TextStyle(
|
||||
fontSize: 40.fSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.whiteColor,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
counterText: '',
|
||||
filled: true,
|
||||
fillColor: Colors.transparent,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
),
|
||||
onChanged: (v) => _onOtpChanged(index, v),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// Resend OTP
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text("Didn't receive it? "),
|
||||
if (_resendTime > 0)
|
||||
Text(
|
||||
'resend in (${_resendTime.toString().padLeft(2, '0')}:00). ',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
)
|
||||
else
|
||||
GestureDetector(
|
||||
onTap: _resendOtp,
|
||||
child: const Text(
|
||||
'Resend',
|
||||
style: TextStyle(
|
||||
color: AppColors.primaryRedColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _verifyOtp() {
|
||||
final otp = _controllers.map((c) => c.text).join();
|
||||
debugPrint('Verifying OTP: $otp');
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Verifying OTP: $otp')),
|
||||
);
|
||||
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => RegisterNewStep2(null, {"nationalID": "12345678654321"})));
|
||||
}
|
||||
|
||||
/// Auto fill OTP into text fields
|
||||
void autoFillOtp(String otp) {
|
||||
if (otp.length != _otpLength) return;
|
||||
|
||||
for (int i = 0; i < _otpLength; i++) {
|
||||
_controllers[i].text = otp[i];
|
||||
}
|
||||
|
||||
// Move focus to the last field
|
||||
_focusNodes[_otpLength - 1].requestFocus();
|
||||
|
||||
// Trigger completion check and color update
|
||||
_checkOtpCompletion();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue