diff --git a/assets/images/svg/cross-circle.svg b/assets/images/svg/cross-circle.svg new file mode 100644 index 00000000..7fc10c24 --- /dev/null +++ b/assets/images/svg/cross-circle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/svg/message.svg b/assets/images/svg/message.svg new file mode 100644 index 00000000..1e09cedc --- /dev/null +++ b/assets/images/svg/message.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/svg/student-card.svg b/assets/images/svg/student-card.svg new file mode 100644 index 00000000..441a83f6 --- /dev/null +++ b/assets/images/svg/student-card.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/images/svg/whatsapp.svg b/assets/images/svg/whatsapp.svg new file mode 100644 index 00000000..4b2a40aa --- /dev/null +++ b/assets/images/svg/whatsapp.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/lib/config/config.dart b/lib/config/config.dart index e425c27d..fb64f682 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -21,8 +21,8 @@ var PACKAGES_ORDERS = '/api/orders'; var PACKAGES_ORDER_HISTORY = '/api/orders/items'; var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara'; // var BASE_URL = 'http://10.50.100.198:2018/'; - var BASE_URL = 'https://uat.hmgwebservices.com/'; -// var BASE_URL = 'https://hmgwebservices.com/'; + // var BASE_URL = 'https://uat.hmgwebservices.com/'; +var BASE_URL = 'https://hmgwebservices.com/'; // var BASE_URL = 'http://10.201.204.103/'; // var BASE_URL = 'https://orash.cloudsolutions.com.sa/'; // var BASE_URL = 'https://vidauat.cloudsolutions.com.sa/'; diff --git a/lib/new_ui/otp/otp_validation_bootmsheet_widget.dart b/lib/new_ui/otp/otp_validation_bootmsheet_widget.dart index 41f30bbf..3262dd20 100644 --- a/lib/new_ui/otp/otp_validation_bootmsheet_widget.dart +++ b/lib/new_ui/otp/otp_validation_bootmsheet_widget.dart @@ -1,39 +1,32 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:hmg_patient_app/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart'; import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; -import 'package:hmg_patient_app/widgets/mobile-no/mobile_no.dart'; import 'package:hmg_patient_app/widgets/text/app_texts_widget.dart'; -class OtpVerificationBottomSheet extends StatefulWidget { +class GenericBottomSheet extends StatefulWidget { final String countryCode; final String initialPhoneNumber; - final Function(String phoneNumber, bool viaWhatsApp) onOtpRequested; + final List buttons; + TextEditingController? textController; - const OtpVerificationBottomSheet({ + GenericBottomSheet({ Key? key, this.countryCode = "+966", this.initialPhoneNumber = "", - required this.onOtpRequested, + required this.buttons, + this.textController, }) : super(key: key); @override - _OtpVerificationBottomSheetState createState() => _OtpVerificationBottomSheetState(); + _GenericBottomSheetState createState() => _GenericBottomSheetState(); } -class _OtpVerificationBottomSheetState extends State { - late TextEditingController _phoneController; - bool _viaWhatsApp = true; - +class _GenericBottomSheetState extends State { @override void initState() { super.initState(); - _phoneController = TextEditingController(text: widget.initialPhoneNumber); - } - - @override - void dispose() { - _phoneController.dispose(); - super.dispose(); + widget.textController = TextEditingController(text: widget.initialPhoneNumber); } @override @@ -52,113 +45,43 @@ class _OtpVerificationBottomSheetState extends State // Title Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [AppText("Enter Phone Number", fontSize: 28, letterSpacing: -2, fontFamily: 'poppins', color: Color(0xFF2E3039), fontWeight: FontWeight.w600), Icon(Icons.close_outlined)], + children: [ + AppText("Enter Phone Number", fontSize: 28, letterSpacing: -2, fontFamily: 'poppins', color: Color(0xFF2E3039), fontWeight: FontWeight.w600), + InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: SvgPicture.asset("assets/images/svg/cross-circle.svg", width: 24, height: 24)), + ], ), const SizedBox(height: 10), // Subtitle AppText("Enter your phone number to receive OTP verification code", fontSize: 16, fontFamily: 'poppins', color: Color(0xFF2E3039), fontWeight: FontWeight.w500), const SizedBox(height: 10), - _buildPhoneNumberSection(), - const SizedBox(height: 24), - _buildDeliveryMethodSection(), + widget.textController != null + ? Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Directionality( + textDirection: TextDirection.ltr, + child: inputWidget(TranslationBase.of(context).phoneNumber, "5xxxxxxxx", widget.textController!, onChange: (value) { + widget.textController!.text = value!; + }, isEnable: true, prefix: "966", hasSelection: false, isBorderAllowed: false, isAllowLeadingIcon: true, leadingIcon: "assets/images/svg/smart-phone.svg"), + ), + ], + ) + : SizedBox(), + SizedBox(height: 24), + ...widget.buttons, ], ), ); } - - Widget _buildPhoneNumberSection() { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Directionality( - textDirection: TextDirection.ltr, - child: inputWidget(TranslationBase.of(context).phoneNumber, "5xxxxxxxx", _phoneController, isEnable: true, prefix: "966", hasSelection: false, isBorderAllowed: false, isAllowLeadingIcon: true), - ), - ], - ); - } - - Widget _buildDeliveryMethodSection() { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // SMS Option - InkWell( - onTap: () { - setState(() { - _viaWhatsApp = false; - }); - }, - child: Row( - children: [ - CustomButton( - text: "Send me OTP on SMS", - onPressed: () { - setState(() { - _viaWhatsApp = false; - }); - }, - backgroundColor: Colors.red, - borderColor: Colors.red, - textColor: Colors.white, - borderRadius: 12, - padding: const EdgeInsets.fromLTRB(8, 16, 8, 16), - fontSize: 16, - fontFamily: 'poppins', - fontWeight: FontWeight.w500, - ), - ], - ), - ), - const SizedBox(height: 10), - // OR Divider - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child:AppText("OR", fontSize: 16, fontFamily: 'poppins', color: Color(0xFF2E3039), fontWeight: FontWeight.w500), - - ), - ], - ), - const SizedBox(height: 10), - InkWell( - onTap: () { - setState(() { - _viaWhatsApp = true; - }); - }, - child: Row( - children: [ - CustomButton( - text: "Send me OTP on WhatsApp", - onPressed: () { - setState(() { - _viaWhatsApp = true; - }); - }, - backgroundColor: Colors.white, - borderColor: Color(0xFF2E3039), - textColor: Color(0xFF2E3039), - borderRadius: 12, - padding: const EdgeInsets.fromLTRB(8, 16, 8, 16), - fontSize: 16, - borderWidth: 2, - fontFamily: 'poppins', - fontWeight: FontWeight.w500, - ), - ], - ), - ), - ], - ); - } } class CustomButton extends StatelessWidget { final String text; + String? icon; final VoidCallback onPressed; final Color backgroundColor; final Color borderColor; @@ -171,7 +94,7 @@ class CustomButton extends StatelessWidget { final FontWeight fontWeight; final bool isDisabled; - const CustomButton({ + CustomButton({ Key? key, required this.text, required this.onPressed, @@ -185,25 +108,37 @@ class CustomButton extends StatelessWidget { this.fontFamily = 'poppins', this.fontWeight = FontWeight.w500, this.isDisabled = false, + this.icon, }) : super(key: key); @override Widget build(BuildContext context) { - return Expanded( - child: GestureDetector( - onTap: isDisabled ? null : onPressed, - child: Container( - padding: padding, - decoration: BoxDecoration( - color: isDisabled ? backgroundColor.withOpacity(0.5) : backgroundColor, - borderRadius: BorderRadius.circular(borderRadius), - border: Border.all( - color: isDisabled ? borderColor.withOpacity(0.5) : borderColor, - width: borderWidth, - ), + return GestureDetector( + onTap: isDisabled ? null : onPressed, + child: Container( + padding: padding, + decoration: BoxDecoration( + color: isDisabled ? backgroundColor.withOpacity(0.5) : backgroundColor, + borderRadius: BorderRadius.circular(borderRadius), + border: Border.all( + color: isDisabled ? borderColor.withOpacity(0.5) : borderColor, + width: borderWidth, ), - child: Center( - child: Text( + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (icon != null) + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: SvgPicture.asset( + icon!, + width: 24, + height: 24, + ), + ), + Text( text, style: TextStyle( fontSize: fontSize, @@ -212,7 +147,7 @@ class CustomButton extends StatelessWidget { fontWeight: fontWeight, ), ), - ), + ], ), ), ); diff --git a/lib/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart b/lib/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart index 3699ed30..2c3a07b5 100644 --- a/lib/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart +++ b/lib/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart @@ -305,8 +305,8 @@ class _CarbsState extends State { // } } -Widget inputWidget(String _labelText, String _hintText, TextEditingController _controller, - {String? prefix, bool isEnable = true, bool hasSelection = false, bool isBorderAllowed = true, bool isAllowLeadingIcon = false}) { +Widget inputWidget(String _labelText, String _hintText, TextEditingController? _controller, + {Function? onChange(String? value)?, String? prefix, bool isEnable = true, bool hasSelection = false, bool isBorderAllowed = true, bool isAllowLeadingIcon = false, String? leadingIcon,}) { return Container( padding: EdgeInsets.only(left: 16, right: 16, bottom: 15, top: 15), alignment: Alignment.center, @@ -324,7 +324,7 @@ Widget inputWidget(String _labelText, String _hintText, TextEditingController _c onTap: hasSelection ? () {} : null, child: Row( children: [ - if (isAllowLeadingIcon) + if (isAllowLeadingIcon && leadingIcon != null) Container( height: 40, width: 40, @@ -336,30 +336,43 @@ Widget inputWidget(String _labelText, String _hintText, TextEditingController _c Radius.circular(10), ), ), - child: SvgPicture.asset("assets/images/svg/smart-phone.svg", width: 24,height: 24,), + child: SvgPicture.asset( + leadingIcon, + width: 24, + height: 24, + ), ), Expanded( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, children: [ Text( _labelText, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xff898A8D), - fontFamily: 'poppins', - letterSpacing: -0.2, - height: 18/12 - ), + style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xff898A8D), fontFamily: 'poppins', letterSpacing: -0.2, height: 18 / 12), ), + // if(prefix !=null) Row( + // children: [ + // Text( + // "+" + prefix, + // style: TextStyle( + // fontSize: 14, + // height: 21 / 14, + // fontWeight: FontWeight.w500, + // color: Color(0xff2E303A), + // letterSpacing: -0.56, + // ), + // ), + // ], + // ), TextField( enabled: isEnable, scrollPadding: EdgeInsets.zero, keyboardType: TextInputType.number, controller: _controller, - onChanged: (value) => {}, + textAlignVertical: TextAlignVertical.top, + onChanged: onChange, style: TextStyle( fontSize: 14, height: 21 / 14, @@ -372,12 +385,12 @@ Widget inputWidget(String _labelText, String _hintText, TextEditingController _c hintText: _hintText, hintStyle: TextStyle( fontSize: 14, - height: 21 / 14, + height: 21 / 16, fontWeight: FontWeight.w500, color: Color(0xff2E3039), letterSpacing: -0.2, ), - prefixIconConstraints: BoxConstraints(minWidth: 50), + prefixIconConstraints: BoxConstraints(minWidth: 45), prefixIcon: prefix == null ? null : Text( @@ -387,7 +400,7 @@ Widget inputWidget(String _labelText, String _hintText, TextEditingController _c height: 21 / 14, fontWeight: FontWeight.w500, color: Color(0xff2E303A), - letterSpacing: -0.56, + letterSpacing: -0.2, ), ), contentPadding: EdgeInsets.zero, diff --git a/lib/pages/login/confirm-login.dart b/lib/pages/login/confirm-login.dart index 3eb88925..595a6a8b 100644 --- a/lib/pages/login/confirm-login.dart +++ b/lib/pages/login/confirm-login.dart @@ -70,13 +70,9 @@ class _ConfirmLogin extends State { var registerd_data; bool isMoreOption = false; var zipCode; - var patientOutSA; - var loginTokenID; - var loginType; - var deviceToken; var lastLogin; diff --git a/lib/pages/login/register_new.dart b/lib/pages/login/register_new.dart index 3f9a0ecd..6751b7ce 100644 --- a/lib/pages/login/register_new.dart +++ b/lib/pages/login/register_new.dart @@ -54,6 +54,7 @@ class _RegisterNew extends State { isShowAppBar: true, isShowDecPage: false, showNewAppBar: true, + showNewAppBarTitle: true, body: SingleChildScrollView( child: Container( diff --git a/lib/pages/login/welcome.dart b/lib/pages/login/welcome.dart index 356fded6..3ab54304 100644 --- a/lib/pages/login/welcome.dart +++ b/lib/pages/login/welcome.dart @@ -1,17 +1,46 @@ +import 'package:flutter/gestures.dart'; import 'package:hmg_patient_app/analytics/google-analytics.dart'; +import 'package:hmg_patient_app/config/config.dart'; +import 'package:hmg_patient_app/config/shared_pref_kay.dart'; +import 'package:hmg_patient_app/core/service/AuthenticatedUserObject.dart'; +import 'package:hmg_patient_app/core/viewModels/appointment_rate_view_model.dart'; +import 'package:hmg_patient_app/core/viewModels/project_view_model.dart'; import 'package:hmg_patient_app/locator.dart'; +import 'package:hmg_patient_app/models/Appointments/toDoCountProviderModel.dart'; +import 'package:hmg_patient_app/models/Authentication/check_activation_code_response.dart'; +import 'package:hmg_patient_app/models/Authentication/check_paitent_authentication_req.dart'; +import 'package:hmg_patient_app/models/Authentication/select_device_imei_res.dart'; +import 'package:hmg_patient_app/models/Authentication/send_activation_request.dart'; +import 'package:hmg_patient_app/models/InPatientServices/get_admission_info_response_model.dart'; +import 'package:hmg_patient_app/models/InPatientServices/get_admission_request_info_response_model.dart'; import 'package:hmg_patient_app/new_ui/otp/otp_validation_bootmsheet_widget.dart'; +import 'package:hmg_patient_app/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart'; +import 'package:hmg_patient_app/pages/landing/landing_page.dart'; import 'package:hmg_patient_app/pages/login/login-type.dart'; import 'package:hmg_patient_app/pages/login/register.dart'; import 'package:hmg_patient_app/pages/login/register_new.dart'; +import 'package:hmg_patient_app/pages/login/user-login-agreement-page.dart'; +import 'package:hmg_patient_app/pages/rateAppointment/rate_appointment_doctor.dart'; +import 'package:hmg_patient_app/services/authentication/auth_provider.dart'; +import 'package:hmg_patient_app/services/clinic_services/get_clinic_service.dart'; import 'package:hmg_patient_app/theme/colors.dart'; +import 'package:hmg_patient_app/uitl/app_shared_preferences.dart'; +import 'package:hmg_patient_app/uitl/app_toast.dart'; +import 'package:hmg_patient_app/uitl/gif_loader_dialog_utils.dart'; import 'package:hmg_patient_app/uitl/translations_delegate_base.dart'; +import 'package:hmg_patient_app/uitl/utils.dart'; import 'package:hmg_patient_app/widgets/buttons/defaultButton.dart'; import 'package:hmg_patient_app/widgets/others/app_scaffold_widget.dart'; +import 'package:hmg_patient_app/widgets/otp/sms-popup.dart'; +import 'package:hmg_patient_app/widgets/text/app_texts_widget.dart'; import 'package:hmg_patient_app/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:intl/src/intl/date_format.dart'; +import 'package:provider/provider.dart'; + +enum OTPType { sms, whatsapp } class WelcomeLogin extends StatefulWidget { @override @@ -20,6 +49,46 @@ class WelcomeLogin extends StatefulWidget { class _WelcomeLogin extends State { bool isLoading = true; + TextEditingController nationIdController = TextEditingController(); + TextEditingController phoneController = TextEditingController(); + bool isDubai = false; + var _availableBiometrics; + final authService = AuthProvider(); + var sharedPref = AppSharedPreferences(); + bool authenticated = false; + late int mobileNumber; + String errorMsg = ''; + SelectDeviceIMEIRES? user; + var registerd_data; + bool isMoreOption = false; + var zipCode; + var patientOutSA; + var loginTokenID; + var loginType; + var deviceToken; + var lastLogin; + + AuthenticatedUserObject authenticatedUserObject = locator(); + AppointmentRateViewModel appointmentRateViewModel = locator(); + late ProjectViewModel projectViewModel; + + late ToDoCountProviderModel toDoProvider; + + + late int selectedOption; + + bool onlySMSBox = false; + var userData; + + late BuildContext _context; + + late bool _loading; + + int fingrePrintBefore = 0; + + var dob; + late int isHijri; + var healthId; @override void initState() { @@ -28,10 +97,15 @@ class _WelcomeLogin extends State { } Widget build(BuildContext context) { + + projectViewModel = Provider.of(context); + toDoProvider = Provider.of(context); + return AppScaffold( appBarTitle: TranslationBase.of(context).welcome, isShowDecPage: false, isShowAppBar: true, + isshowBackButton: false, showNewAppBar: true, backgroundColor: Color(0xffF8F8F8), showNewAppBarTitle: false, @@ -55,68 +129,623 @@ class _WelcomeLogin extends State { ], ), ), + Spacer(), Expanded( child: Container( - padding: EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), - child: Column( - children: [ - Text( - // TranslationBase.of(context).welcome, - "Welcome to Dr. Sulaiman Al Habib Medical Group", - style: TextStyle(fontSize: 36, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.4, height: 47 / 36), - ), - SizedBox(height: 16) - ], + padding: EdgeInsets.only(top: 30, bottom: 0, right: 21, left: 21), + child: Text( + // TranslationBase.of(context).welcome, + "Welcome to Dr. Sulaiman Al Habib Medical Group", + style: TextStyle(fontSize: 36, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.4, height: 47 / 36), ), ), ), Container( - color: Colors.white, - padding: EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( + padding: EdgeInsets.only(top: 16, bottom: 10, right: 21, left: 21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Directionality( + textDirection: TextDirection.ltr, + child: inputWidget( + "National ID. or File No", + "1xxxxxxxx", + nationIdController, + isEnable: true, + prefix: null, + hasSelection: false, + isBorderAllowed: false, + isAllowLeadingIcon: true, + leadingIcon: "assets/images/svg/student-card.svg", + ), + ), + ], + ), + ), + SizedBox( + height: 15, + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Container( + padding: EdgeInsets.only(top: 0, bottom: 16, right: 21, left: 21), child: DefaultButton( TranslationBase.of(context).login, - () => { - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (context) => OtpVerificationBottomSheet( - countryCode: "+966", // Default is +966 as in your example - initialPhoneNumber: "574345434", // Optional initial value - onOtpRequested: (phoneNumber, viaWhatsApp) { - // Handle OTP request here - print("Requesting OTP for $phoneNumber via ${viaWhatsApp ? "WhatsApp" : "SMS"}"); - Navigator.pop(context); - }, - )) - - // Navigator.of(context).push(FadePage(page: RegisterNew())), - // locator().loginRegistration.visited_alhabib_group(false), + () { + bool isValid = validateIqama(nationIdController.text); + print("Iqama is valid: $isValid"); + + if (isValid) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + isDismissible: false, + backgroundColor: Colors.transparent, + builder: (context) => Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: SingleChildScrollView( + child: GenericBottomSheet( + countryCode: "966", // Default is +966 as in your example + initialPhoneNumber: "", // + textController: phoneController, + buttons: [ + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: CustomButton( + text: "Send me OTP on SMS", + onPressed: () { + onOtpBtnPressed(OTPType.sms); + }, + backgroundColor: Colors.red, + borderColor: Colors.red, + textColor: Colors.white, + icon: "assets/images/svg/message.svg", + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: AppText( + "OR", + fontSize: 16, + fontFamily: 'poppins', + color: Color(0xFF2E3039), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: CustomButton( + text: "Send me OTP on WhatsApp", + onPressed: () { + onOtpBtnPressed(OTPType.whatsapp); + }, + backgroundColor: Colors.white, + borderColor: Color(0xFF2E3039), + textColor: Color(0xFF2E3039), + icon: "assets/images/svg/whatsapp.svg", + ), + ), + ], + ), + ), + )); + } else { + Utils.showErrorToast("Please enter a valid Iqama number."); + } }, - color: CustomColors.accentColor, + // color: CustomColors., textColor: Colors.white, ), ), - // SizedBox(width: 8), - // Expanded( - // child: DefaultButton( - // TranslationBase.of(context).yes, - // () => { - // Navigator.of(context).push(FadePage(page: LoginType())), - // locator().loginRegistration.visited_alhabib_group(true), - // }, - // color: CustomColors.green, - // ), - // ), - ], - ), + ), + // SizedBox(width: 8), + // Expanded( + // child: DefaultButton( + // TranslationBase.of(context).yes, + // () => { + // Navigator.of(context).push(FadePage(page: LoginType())), + // locator().loginRegistration.visited_alhabib_group(true), + // }, + // color: CustomColors.green, + // ), + // ), + ], ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + color: Colors.black, + fontSize: 16, + height: 26 / 16, + fontFamily: 'poppins', + fontWeight: FontWeight.w500, + ), + children: [ + TextSpan(text: 'Don’t have an account? '), + TextSpan( + text: 'Register now', + style: const TextStyle( + color: Colors.red, + fontSize: 16, + height: 26 / 16, + fontFamily: 'poppins', + fontWeight: FontWeight.w500, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.of(context).push(FadePage(page: RegisterNew())); + // Example: Navigator.push(context, MaterialPageRoute(builder: (context) => RegisterScreen())); + }, + ), + ], + ), + ), + ], + ) ], ), ); } -} + + void onOtpBtnPressed(OTPType type) { + if (phoneController.text.isEmpty) { + Utils.showErrorToast("Please enter your phone number."); + return; + } + if (type == OTPType.whatsapp && !phoneController.text.startsWith("+966")) { + Utils.showErrorToast("WhatsApp OTP requires a phone number starting with +966."); + return; + } + + print("Requesting OTP for ${phoneController.text} via ${type == OTPType.whatsapp ? "WhatsApp" : "SMS"} and ${nationIdController.text}"); + // Navigator.pop(context); + + checkUserAuthentication(type == OTPType.sms ? 1 : 2); + } + + bool validateIqama(String iqamaNumber) { + // Remove any non-digit characters + String cleanedIqama = iqamaNumber.replaceAll(RegExp(r'[^0-9]'), ''); + + // Check if length is 10 digits + if (cleanedIqama.length != 10) { + return false; + } + + // Check if first digit is 2 or 1 (common for Iqama) + int firstDigit = int.parse(cleanedIqama[0]); + if (firstDigit != 2 && firstDigit != 1) { + return false; + } + + // Checksum validation (similar to Saudi National ID) + int sum = 0; + for (int i = 0; i < 10; i++) { + int digit = int.parse(cleanedIqama[i]); + int weight = (i % 2 == 0) ? 2 : 1; // Alternate weights: 2, 1, 2, 1... + int product = digit * weight; + sum += (product > 9) ? product - 9 : product; // Sum digits if product > 9 + } + + return sum % 10 == 0; + } + + checkUserAuthentication(type) { + showLoader(true); + var req = getCommonRequest(type: type); + req.logInTokenID = ""; + + var request = CheckPatientAuthenticationReq.fromJson(req.toJson()); + + sharedPref.setObject(REGISTER_DATA_FOR_REGISTER, request); + authService + .checkPatientAuthentication(request) + .then((value) => { + GifLoaderDialogUtils.hideDialog(context), + if (value['isSMSSent']) + { + sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']), + this.loginTokenID = value['LogInTokenID'], + sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), + // Future.delayed(Duration(seconds: 1), () { + this.sendActivationCode(type) + // }) + } + else + { + if (value['IsAuthenticated']) {this.checkActivationCode()} + } + }) + .catchError((err) { + print(err); + GifLoaderDialogUtils.hideDialog(context); + }); + } + + sendActivationCode(type) async { + var request = this.getCommonRequest(type: type); + request.sMSSignature = await SMSOTP.getSignature(); + GifLoaderDialogUtils.showMyDialog(context); + if (healthId != null || isDubai) { + if (!isDubai) { + request.dob = dob; //isHijri == 1 ? dob : dateFormat2.format(dateFormat.parse(dob)); + } + request.healthId = healthId; + request.isHijri = isHijri; + await this.authService.sendActivationCodeRegister(request).then((result) { + GifLoaderDialogUtils.hideDialog(context); + if (result != null && result['isSMSSent'] == true) { + this.startSMSService(type); + } + }).catchError((r) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: r); + }); + } else { + request.dob = ""; + request.healthId = ""; + request.isHijri = 0; + await this.authService.sendActivationCode(request).then((result) { + GifLoaderDialogUtils.hideDialog(context); + if (result != null && result['isSMSSent'] == true) { + this.startSMSService(type); + } + }).catchError((r) { + GifLoaderDialogUtils.hideDialog(context); + AppToast.showErrorToast(message: r.toString()); + }); + } + } + + checkActivationCode({value}) async { + // Navigator.pop(context); + GifLoaderDialogUtils.showMyDialog(context); + var request = this.getCommonRequest().toJson(); + dynamic res; + if (healthId != null || isDubai) { + if (isDubai) { + request['DOB'] = dob; + } + request['HealthId'] = healthId; + request['IsHijri'] = isHijri; + + authService + .checkActivationCodeRegister(request, value) + .then((result) => { + res = result, + if (result is Map) + { + result = CheckActivationCode.fromJson(result as Map), + if (this.registerd_data != null && this.registerd_data.isRegister == true) + { + // if(widget.isDubai ==false){ + // widget.changePageViewIndex!(1), + // if(widget.isDubai ==false){ + + Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew)), + } + } + else + { + Navigator.of(context).pop(), + GifLoaderDialogUtils.hideDialog(context), + Future.delayed(Duration(seconds: 1), () { + AppToast.showErrorToast(message: result); + }), + // projectViewModel.analytics.loginRegistration.login_fail(error: result), + // projectViewModel.analytics.errorTracking.log('otp_verification_at_confirm_login', error: result), + } + }) + .catchError((err) { + print(err); + GifLoaderDialogUtils.hideDialog(context); + Future.delayed(Duration(seconds: 1), () { + AppToast.showErrorToast(message: err); + // startSMSService(tempType); + }); + }); + } else { + authService + .checkActivationCode(request, value) + .then((result) async => { + res = result, + if (result is Map) + { + result = CheckActivationCode.fromJson(result as Map), + if (result.errorCode == '699') + { + //699 block run here + GifLoaderDialogUtils.hideDialog(context), + Future.delayed(Duration(seconds: 2), () { + AppToast.showErrorToast(message: result.errorEndUserMessage); + Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: WelcomeLogin)); + }) + } + else if (this.registerd_data != null && this.registerd_data.isRegister == true) + { + // widget.changePageViewIndex!(1), + Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew)), + } + else + { + sharedPref.remove(FAMILY_FILE), + result.list.isFamily = false, + userData = result.list, + sharedPref.setString(BLOOD_TYPE, result.patientBloodType ?? ""), + //Remove o+ from here Added by Aamir + authenticatedUserObject.user = result.list, + projectViewModel.setPrivilege(privilegeList: res), + await sharedPref.setObject(MAIN_USER, result.list), + await sharedPref.setObject(USER_PROFILE, result.list), + loginTokenID = result.logInTokenID, + await sharedPref.setObject(LOGIN_TOKEN_ID, result.logInTokenID), + await sharedPref.setString(TOKEN, result.authenticationTokenID), + checkIfUserAgreedBefore(result), + // projectViewModel.analytics.loginRegistration.login_successful(), + } + } + else + { + // Navigator.of(context).pop(), + GifLoaderDialogUtils.hideDialog(context), + Future.delayed(Duration(seconds: 1), () { + Navigator.of(context).pop(); + AppToast.showErrorToast(message: result, localContext: context); + startSMSService(tempType); + }), + + // projectViewModel.analytics.loginRegistration.login_fail(error: result), + // projectViewModel.analytics.errorTracking.log('otp_verification_at_confirm_login', error: result) + } + }) + .catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + Future.delayed(Duration(seconds: 1), () { + print(err); + AppToast.showErrorToast(message: err); + // startSMSService(tempType); + }); + }); + } + } + + var tempType; + + startSMSService(type) { + tempType = type; + SMSOTP( + context, + type, + phoneController.text, + (value) { + this.checkActivationCode(value: value); + }, + () => { + Navigator.pop(context), + }, + ).displayDialog(context); + } + + showLoader(bool isTrue) { + setState(() { + isLoading = isTrue; + }); + } + + setDefault() async { + showLoader(true); + if (await sharedPref.getObject(IMEI_USER_DATA) != null) user = SelectDeviceIMEIRES.fromJson(await sharedPref.getObject(IMEI_USER_DATA)); + + if (await sharedPref.getObject(REGISTER_DATA_FOR_LOGIIN) != null) { + isMoreOption = true; + this.registerd_data = await CheckPatientAuthenticationReq.fromJson(await sharedPref.getObject(REGISTER_DATA_FOR_LOGIIN)); + } + + this.mobileNumber = this.registerd_data != null ? this.registerd_data.patientMobileNumber : int.parse(this.user!.mobile!); + this.zipCode = this.registerd_data != null + ? this.registerd_data.zipCode + : this.user!.outSA == true + ? "971" + : "966"; + this.patientOutSA = this.registerd_data != null + ? this.registerd_data.zipCode == "966" + ? 0 + : 1 + : this.user!.outSA; + if (this.registerd_data != null) { + this.loginTokenID = await sharedPref.getString(LOGIN_TOKEN_ID); + this.loginType = this.registerd_data.searchType; + } + var nhic = await sharedPref.getObject(NHIC_DATA); + if (nhic != null) { + final DateFormat dateFormat = DateFormat('MM/dd/yyyy'); + final DateFormat dateFormat2 = DateFormat('dd/MM/yyyy'); + dob = nhic['IsHijri'] ? nhic['DateOfBirth'] : dateFormat2.format(dateFormat.parse(nhic['DateOfBirth'])); + + isHijri = nhic['IsHijri'] ? 1 : 0; + healthId = nhic['HealthId']; + } + this.deviceToken = await sharedPref.getString(PUSH_TOKEN); + this.lastLogin = await sharedPref.getInt(LAST_LOGIN) != null + ? await sharedPref.getInt(LAST_LOGIN) + : user != null + ? user!.logInType + : null; + + showLoader(false); + //this.cs.sharedService.getStorage(AuthenticationService.LAST_LOGIN); + } + + getCommonRequest({type}) { + var fileNo = false; + var request = SendActivationRequest(); + request.patientMobileNumber = int.parse(phoneController.text); + request.mobileNo = '0' + phoneController.text.toString(); + request.deviceToken = this.deviceToken; + request.projectOutSA = this.patientOutSA == true ? true : false; + request.loginType = type == 1 ? type : 2; + request.oTPSendType = type == 1 ? type : 2; //this.selectedOption == 1 ? 1 : 2; + request.zipCode = "966"; + + request.logInTokenID = this.loginTokenID ?? ""; + + if (this.registerd_data != null) { + request.searchType = this.registerd_data.searchType != null ? this.registerd_data.searchType : 1; + request.patientID = this.registerd_data.patientID != null ? this.registerd_data.patientID : 0; + request.patientIdentificationID = request.nationalID = this.registerd_data.patientIdentificationID != null ? this.registerd_data.patientIdentificationID : '0'; + request.dob = this.registerd_data.dob; + request.isRegister = this.registerd_data.isRegister; + } else { + request.searchType = request.searchType != null ? request.searchType : 1; + if (fileNo) { + request.patientID = this.user!.patientID != null ? this.user!.patientID : 0; + } else { + request.patientID = 0; + } + request.nationalID = nationIdController != null ? nationIdController.text : '0'; + request.patientIdentificationID = nationIdController != null ? nationIdController.text : '0'; + request.isRegister = false; + } + request.deviceTypeID = request.searchType; + return request; + } + + checkIfUserAgreedBefore(CheckActivationCode result) { + if (projectViewModel.havePrivilege(109)) { + this.authService.checkIfUserAgreed().then((result) { + if (result['IsPatientAlreadyAgreed']) { + goToHome(); + } else { + this.authService.getUserAgreementContent().then((result) { + GifLoaderDialogUtils.hideDialog(AppGlobal.context); + Navigator.pushAndRemoveUntil( + context, + FadePage( + page: UserLoginAgreementPage( + userAgreementText: result['UserAgreementContent'], + authenticatedUserObject: authenticatedUserObject, + appointmentRateViewModel: appointmentRateViewModel, + selectedOption: selectedOption, + isArabic: projectViewModel.isArabic, + ), + ), + (r) => false); + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + print(err); + }); + } + }).catchError((err) { + GifLoaderDialogUtils.hideDialog(context); + print(err); + }); + } else { + goToHome(); + } + } + + Future goToHome() async { + authenticatedUserObject.isLogin = true; + appointmentRateViewModel.isLogin = true; + projectViewModel.isLogin = true; + projectViewModel.user = authenticatedUserObject.user; + await authenticatedUserObject.getUser(getUser: true); + + getToDoCount(); + checkIfIsInPatient(); + + appointmentRateViewModel + .getIsLastAppointmentRatedList(projectViewModel.isArabic ? 1 : 2) + .then((_) { + GifLoaderDialogUtils.hideDialog(AppGlobal.context); + + if (appointmentRateViewModel.isHaveAppointmentNotRate) { + Navigator.pushAndRemoveUntil( + context, + FadePage(page: RateAppointmentDoctor()), + (route) => false, + ); + } else { + Navigator.pushAndRemoveUntil( + context, + FadePage(page: LandingPage()), + (route) => false, + ); + } + insertIMEI(); + }).catchError((error) { + print(error); + }); + } + + void getToDoCount() { + toDoProvider.setState(0, 0, true, "0"); + ClinicListService() + .getActiveAppointmentNo(context) + .then((res) { + if (res['MessageStatus'] == 1) { + toDoProvider.setState( + res['AppointmentActiveNumber'], + res['AncillaryOrderListCount'], + true, + "0", + ); + } + }).catchError((err) => print(err)); + } + + insertIMEI() { + authService.insertDeviceImei(selectedOption).then((value) => {}).catchError((err) { + print(err); + }); + } + + void checkIfIsInPatient() { + final service = ClinicListService(); + service.checkIfInPatientAPI(context).then((res) { + if (res['MessageStatus'] != 1) return; + + final isAdmitted = res['isAdmitted'] == true; + final hasAdmissionRequest = res['hasAdmissionRequests'] == true; + + print("IS ADMITTED: $isAdmitted"); + print("Has Admission Request: $hasAdmissionRequest"); + + if (isAdmitted && res['PatientAdmittedInformation']?.isNotEmpty == true) { + final info = GetAdmissionInfoResponseModel.fromJson(res['PatientAdmittedInformation'][0]); + projectViewModel.setInPatientProjectID(res['PatientAdmittedInformation'][0]['ProjectID']); + projectViewModel.setInPatientAdmissionInfo(info); + projectViewModel.setIsPatientAdmitted(true); + } + + if (hasAdmissionRequest && res['MedicalInstruction']?.isNotEmpty == true) { + final reqInfo = GetAdmissionRequestInfoResponseModel.fromJson(res['MedicalInstruction'][0]); + projectViewModel.setInPatientProjectID(res['MedicalInstruction'][0]['projectId']); + projectViewModel.setInPatientAdmissionRequest(reqInfo); + projectViewModel.setPatientHasAdmissionRequest(true); + } + }); + } + + } + + + + + + diff --git a/lib/splashPage.dart b/lib/splashPage.dart index b7faad2f..ebff30a2 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -7,6 +7,7 @@ import 'package:hmg_patient_app/config/shared_pref_kay.dart'; import 'package:hmg_patient_app/models/Appointments/DoctorListResponse.dart'; import 'package:hmg_patient_app/pages/BookAppointment/SearchResultsByRegion.dart'; import 'package:hmg_patient_app/pages/landing/landing_page.dart'; +import 'package:hmg_patient_app/pages/login/welcome.dart'; import 'package:hmg_patient_app/theme/theme_notifier.dart'; import 'package:hmg_patient_app/theme/theme_value.dart'; import 'package:hmg_patient_app/uitl/LocalNotification.dart'; @@ -38,7 +39,7 @@ class _SplashScreenState extends State { @override void initState() { - AppGlobal.context = context; + // AppGlobal.context = context; super.initState(); print("Splash init called............."); Timer( @@ -50,7 +51,8 @@ class _SplashScreenState extends State { if (!_privilegeService.hasError) { Navigator.of(context).pushReplacement( MaterialPageRoute( - builder: (BuildContext context) => LandingPage(), + builder: (BuildContext context) => WelcomeLogin(), + // builder: (BuildContext context) => LandingPage(), ), ); } else {} diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index 19dc0b7c..36ebc210 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -82,6 +82,7 @@ class AppScaffold extends StatefulWidget { final ValueChanged? changeCurrentTab; final int? currentTab; final bool isShowPharmacyAppbar; + final bool isshowBackButton; final Widget? customAppBar; AppScaffold setOnAppBarCartClick(VoidCallback onClick) { @@ -127,6 +128,7 @@ class AppScaffold extends StatefulWidget { appBar, this.customAppBar, this.isLocalLoader = false, + this.isshowBackButton = true, this.backButtonTab, this.changeCurrentTab, this.currentTab, @@ -240,6 +242,7 @@ class _AppScaffoldState extends State { showDropDown: widget.showDropDown, dropdownIndexValue: widget.dropdownIndexValue, dropDownList: widget.dropDownList ?? [], + isShowBackButton: widget.isshowBackButton, dropDownIndexChange: widget.dropDownIndexChange, appBarIcons: widget.appBarIcons, onTap: () { @@ -256,6 +259,7 @@ class _AppScaffoldState extends State { isPharmacy: widget.isPharmacy, showPharmacyCart: widget.showPharmacyCart, isOfferPackages: widget.isOfferPackages, + isshowBackButton: widget.isshowBackButton, showOfferPackagesCart: widget.showOfferPackagesCart, isShowDecPage: widget.isShowDecPage, backButtonTab: () { @@ -285,7 +289,7 @@ class _AppScaffoldState extends State { bottomNavigationBar: widget.isBottomBar ? BottomNavPharmacyBar( changeIndex: changeCurrentTab, - index: widget.currentTab==null ? 0: widget.currentTab!, + index: widget.currentTab == null ? 0 : widget.currentTab!, ) : null, floatingActionButton: widget.floatingActionButton, @@ -336,6 +340,8 @@ class _AppScaffoldState extends State { class NewAppBarWidget extends StatelessWidget implements PreferredSizeWidget { final bool showTitle; + bool isShowBackButton; + final String title; final bool? showDropDown; final int? dropdownIndexValue; @@ -345,7 +351,17 @@ class NewAppBarWidget extends StatelessWidget implements PreferredSizeWidget { VoidCallback? onTap; - NewAppBarWidget({Key? key, this.showTitle = false, this.showDropDown = false, this.title = "", this.dropDownList, this.appBarIcons, this.dropdownIndexValue, this.dropDownIndexChange, this.onTap}) + NewAppBarWidget( + {Key? key, + this.showTitle = false, + this.showDropDown = false, + this.title = "", + this.dropDownList, + this.appBarIcons, + this.dropdownIndexValue, + this.dropDownIndexChange, + this.onTap, + this.isShowBackButton = true}) : super(key: key); @override @@ -357,9 +373,11 @@ class NewAppBarWidget extends StatelessWidget implements PreferredSizeWidget { backgroundColor: showTitle ? Colors.white : Colors.transparent, // backgroundColor: Colors.red, // automaticallyImplyLeading: false, - leading: ArrowBack( - onTap: onTap, - ), + leading: isShowBackButton + ? ArrowBack( + onTap: onTap, + ) + : null, titleSpacing: -8, // centerTitle: false, title: Row( @@ -446,6 +464,7 @@ class AppBarWidget extends StatefulWidget implements PreferredSizeWidget { final bool showPharmacyCart; final bool showOfferPackagesCart; final bool isShowDecPage; + final bool isshowBackButton; final VoidCallback? backButtonTab; Function(String)? badgeUpdater; @@ -455,6 +474,7 @@ class AppBarWidget extends StatefulWidget implements PreferredSizeWidget { this.showHomeAppBarIcon, this.appBarIcons, this.isPharmacy = true, + this.isshowBackButton = true, this.showPharmacyCart = true, this.isOfferPackages = false, this.showOfferPackagesCart = false, @@ -496,20 +516,22 @@ class AppBarWidgetState extends State { title: Text(widget.authenticatedUserObject.isLogin || !widget.isShowDecPage ? widget.appBarTitle!.toUpperCase() : TranslationBase.of(context).serviceInformationTitle, // style: TextStyle(fontWeight: FontWeight.bold, color: Theme.of(context).textTheme.headline1!.color, fontFamily: projectViewModel.isArabic ? 'Cairo' : 'WorkSans')), style: TextStyle(fontWeight: FontWeight.bold, color: CustomColors.white, fontFamily: projectViewModel.isArabic ? 'Cairo' : 'WorkSans')), - leading: Builder( - builder: (BuildContext context) { - return ArrowBack( - onTap: widget.backButtonTab, - ); - }, - ), + leading: widget.isshowBackButton + ? Builder( + builder: (BuildContext context) { + return ArrowBack( + onTap: widget.backButtonTab, + ); + }, + ) + : null, centerTitle: true, actions: [ (widget.isPharmacy && widget.showPharmacyCart) ? IconButton( icon: badge_import.Badge( badgeContent: Text( - orderPreviewViewModel.cartResponse.quantityCount !=null? orderPreviewViewModel.cartResponse.quantityCount.toString() :"", + orderPreviewViewModel.cartResponse.quantityCount != null ? orderPreviewViewModel.cartResponse.quantityCount.toString() : "", style: TextStyle(color: Colors.white), ), child: Icon(Icons.shopping_cart)),