diff --git a/lib/auth/employee_login_screen.dart b/lib/auth/employee_login_screen.dart index ccb76de..5d88eca 100644 --- a/lib/auth/employee_login_screen.dart +++ b/lib/auth/employee_login_screen.dart @@ -143,7 +143,7 @@ class _EmployeeLoginScreenState extends ConsumerState { final termsFontSize = r.fontSize(mobile: 10.5, tablet: 11.34, desktop: 12); final linkFontSize = r.fontSize(mobile: 13, tablet: 14, desktop: 15); final otherLoginFontSize = r.fontSize(mobile: 12, tablet: 13, desktop: 14); - +final pinTitleFontSize = r.fontSize(mobile: 20, tablet: 24, desktop: 26); final pinBoxWidth = r.getValue(mobile: 55, tablet: 60, desktop: 68); final pinBoxHeight = r.getValue(mobile: 55, tablet: 60, desktop: 68); final pinFontSize = r.fontSize(mobile: 22, tablet: 28, desktop: 32); @@ -219,8 +219,17 @@ class _EmployeeLoginScreenState extends ConsumerState { ), ), SizedBox(height: spacingLG), - - // Email Input + Align( + alignment: Alignment.centerLeft, + child: Text( + "Enter Your Mail ID *", + style: AppTextStyles.semiBold.copyWith( + fontSize: 14, + color: AppColors.authheading, + ), + ), + ), + SizedBox(height: spacingSM), CommanTextFormField( controller: _emailController, hintText: 'Enter your Email', @@ -233,7 +242,18 @@ class _EmployeeLoginScreenState extends ConsumerState { } }, ), - SizedBox(height: spacingMD), + SizedBox(height: spacingSM), + Align( + alignment: Alignment.centerLeft, + child: Text( + "Enter Your Pin *", + style: AppTextStyles.semiBold.copyWith( + fontSize: 14, + color: AppColors.authheading, + ), + ), + ), + SizedBox(height: spacingSM), // PIN Boxes Row( @@ -319,7 +339,7 @@ class _EmployeeLoginScreenState extends ConsumerState { ); }, child: Text( - "Forgot Password?", + "Forgot PIN?", style: AppTextStyles.bold.copyWith( fontSize: linkFontSize, color: AppColors.authchange, diff --git a/lib/auth/login_screen.dart b/lib/auth/login_screen.dart index ea28318..6b2ebcb 100644 --- a/lib/auth/login_screen.dart +++ b/lib/auth/login_screen.dart @@ -139,6 +139,7 @@ class _LoginScreenState extends ConsumerState { final logoWidth = r.getValue(mobile: 120, tablet: 141, desktop: 160); final logoHeight = r.getValue(mobile: 85, tablet: 100, desktop: 115); final titleFontSize = r.fontSize(mobile: 26, tablet: 32, desktop: 36); + final pinTitleFontSize = r.fontSize(mobile: 20, tablet: 24, desktop: 26); final subtitleFontSize = r.fontSize(mobile: 13, tablet: 14, desktop: 15); final termsFontSize = r.fontSize(mobile: 10.5, tablet: 11.34, desktop: 12); final signupFontSize = r.fontSize(mobile: 13, tablet: 14, desktop: 15); @@ -208,6 +209,17 @@ class _LoginScreenState extends ConsumerState { ), ), SizedBox(height: spacingLG), + Align( + alignment: Alignment.centerLeft, + child: Text( + "Enter Your Mail ID *", + style: AppTextStyles.semiBold.copyWith( + fontSize: 14, + color: AppColors.authheading, + ), + ), + ), + SizedBox(height: spacingSM), CommanTextFormField( controller: _emailController, hintText: 'Enter your Email', @@ -220,8 +232,18 @@ class _LoginScreenState extends ConsumerState { } }, ), - SizedBox(height: spacingMD), - + SizedBox(height: spacingSM), + Align( + alignment: Alignment.centerLeft, + child: Text( + "Enter Your Pin *", + style: AppTextStyles.semiBold.copyWith( + fontSize: 14, + color: AppColors.authheading, + ), + ), + ), + SizedBox(height: spacingSM), // PIN Boxes Row( mainAxisAlignment: MainAxisAlignment.center, @@ -306,7 +328,7 @@ class _LoginScreenState extends ConsumerState { ); }, child: Text( - "Forgot Password?", + "Forgot PIN?", style: AppTextStyles.bold.copyWith( fontSize: signupFontSize, color: AppColors.authchange, diff --git a/lib/consts/comman_webscoket.dart b/lib/consts/comman_webscoket.dart index 23642f0..d4c34bf 100644 --- a/lib/consts/comman_webscoket.dart +++ b/lib/consts/comman_webscoket.dart @@ -40,7 +40,7 @@ class CommonWebSocketService { /// Connect WS using LOCAL USER ID Future connect({ required String userId, - String baseUrl = "wss://taxglide.amrithaa.net:443/reverb", + String baseUrl = "wss://app.taxglide.in:443/reverb", String appKey = "2yj0lyzc9ylw2h03ts6i", }) async { try { diff --git a/lib/consts/details_webscokect.dart b/lib/consts/details_webscokect.dart index 4d13843..5185bf9 100644 --- a/lib/consts/details_webscokect.dart +++ b/lib/consts/details_webscokect.dart @@ -40,7 +40,7 @@ class DetailsWebscokect { /// Connect WS using LOCAL USER ID Future connect({ required String userId, - String baseUrl = "wss://taxglide.amrithaa.net:443/reverb", + String baseUrl = "wss://app.taxglide.in:443/reverb", String appKey = "2yj0lyzc9ylw2h03ts6i", }) async { try { diff --git a/lib/consts/download_helper.dart b/lib/consts/download_helper.dart index b23ac3c..390d57a 100644 --- a/lib/consts/download_helper.dart +++ b/lib/consts/download_helper.dart @@ -10,7 +10,7 @@ import 'package:gal/gal.dart'; import 'package:taxglide/services/notification_service.dart'; class DownloadHelper { - static const String API_BASE_URL = "https://www.taxglide.amrithaa.net/api/"; + static const String API_BASE_URL = "https://www.app.taxglide.in/api/"; /// Request storage permission based on Android version static Future requestStoragePermission() async { diff --git a/lib/consts/notification_webscoket.dart b/lib/consts/notification_webscoket.dart index 06ee431..97d6551 100644 --- a/lib/consts/notification_webscoket.dart +++ b/lib/consts/notification_webscoket.dart @@ -69,7 +69,7 @@ class NotificationWebSocket { Future connect({ required String userId, required ProviderContainer container, - String baseUrl = 'wss://taxglide.amrithaa.net:443/reverb', + String baseUrl = 'wss://app.taxglide.in:443/reverb', String appKey = '2yj0lyzc9ylw2h03ts6i', }) async { if (_isConnected && _userId == userId) { diff --git a/lib/controller/api_consts.dart b/lib/controller/api_consts.dart index 686ff66..847390f 100644 --- a/lib/controller/api_consts.dart +++ b/lib/controller/api_consts.dart @@ -1,5 +1,5 @@ class ConstsApi { - static const String baseUrl = "https://www.taxglide.amrithaa.net"; + static const String baseUrl = "https://www.app.taxglide.in"; static const String login = "$baseUrl/api/otp/sms/request"; static const String verifyOtp = "$baseUrl/api/otp/email/verify"; diff --git a/lib/router/consts_routers.dart b/lib/router/consts_routers.dart index ef7eaaa..e4f0879 100644 --- a/lib/router/consts_routers.dart +++ b/lib/router/consts_routers.dart @@ -14,5 +14,6 @@ class ConstRouters { static const String staff = '/staff'; static const String employeekycdetailslist = '/employeekycdetailslist'; static const String mpinSet = '/mpinSet'; - static const String forgotPassword = '/forgotPassword'; + static const String forgotPassword = '/forgotPassword'; + static const String changePin = '/changePin'; } diff --git a/lib/router/router.dart b/lib/router/router.dart index 0860e29..bfd09e8 100644 --- a/lib/router/router.dart +++ b/lib/router/router.dart @@ -15,6 +15,7 @@ import 'package:taxglide/view/screens/profile/kyc_details_list.dart'; import 'package:taxglide/view/screens/profile/policy_screen.dart'; import 'package:taxglide/view/screens/profile/staff_list_screen.dart'; import 'package:taxglide/view/screens/profile/terms_and_condition_screen.dart'; +import 'package:taxglide/view/screens/profile/change_pin_screen.dart'; class AppRoutes { static final routes = [ @@ -57,5 +58,9 @@ class AppRoutes { name: ConstRouters.forgotPassword, page: () => const ForgotScreen(), ), + GetPage( + name: ConstRouters.changePin, + page: () => const ChangePinScreen(), + ), ]; } diff --git a/lib/view/Mahi_chat/webscoket.dart b/lib/view/Mahi_chat/webscoket.dart index da9517a..8cc9669 100644 --- a/lib/view/Mahi_chat/webscoket.dart +++ b/lib/view/Mahi_chat/webscoket.dart @@ -39,7 +39,7 @@ class ChatWebSocketService { /// Connect to WebSocket for a specific chat Future connect({ required String chatId, - String baseUrl = "wss://taxglide.amrithaa.net:443/reverb", + String baseUrl = "wss://app.taxglide.in:443/reverb", String appKey = "2yj0lyzc9ylw2h03ts6i", }) async { try { diff --git a/lib/view/screens/profile/change_pin_screen.dart b/lib/view/screens/profile/change_pin_screen.dart new file mode 100644 index 0000000..85aaac3 --- /dev/null +++ b/lib/view/screens/profile/change_pin_screen.dart @@ -0,0 +1,378 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:get/get.dart'; +import 'package:taxglide/consts/app_asstes.dart'; +import 'package:taxglide/consts/app_colors.dart'; +import 'package:taxglide/consts/comman_button.dart'; +import 'package:taxglide/consts/comman_container_auth.dart'; +import 'package:taxglide/consts/responsive_helper.dart'; +import 'package:taxglide/consts/validation_popup.dart'; +import 'package:taxglide/controller/api_contoller.dart'; +import 'package:taxglide/view/Main_controller/main_controller.dart'; +import 'package:taxglide/consts/app_style.dart'; + +class ChangePinScreen extends ConsumerStatefulWidget { + const ChangePinScreen({super.key}); + + @override + ConsumerState createState() => _ChangePinScreenState(); +} + +class _ChangePinScreenState extends ConsumerState { + final ValidationPopup _validationPopup = ValidationPopup(); + final int pinLength = 4; + final List _controllers = []; + final List _focusNodes = []; + String pinValue = ''; + + final List _confirmControllers = []; + final List _confirmFocusNodes = []; + String confirmPinValue = ''; + + @override + void initState() { + super.initState(); + _initControllers(); + } + + void _initControllers() { + for (var c in _controllers) c.dispose(); + for (var f in _focusNodes) f.dispose(); + for (var c in _confirmControllers) c.dispose(); + for (var f in _confirmFocusNodes) f.dispose(); + + _controllers.clear(); + _focusNodes.clear(); + _confirmControllers.clear(); + _confirmFocusNodes.clear(); + + pinValue = ''; + confirmPinValue = ''; + + for (int i = 0; i < pinLength; i++) { + _controllers.add(TextEditingController()); + _focusNodes.add(FocusNode()); + _confirmControllers.add(TextEditingController()); + _confirmFocusNodes.add(FocusNode()); + } + } + + @override + void dispose() { + for (var c in _controllers) c.dispose(); + for (var f in _focusNodes) f.dispose(); + for (var c in _confirmControllers) c.dispose(); + for (var f in _confirmFocusNodes) f.dispose(); + super.dispose(); + } + + void _handleAction() async { + if (pinValue.length != pinLength) { + _validationPopup.showErrorMessage(context, "Please enter all 4 digits"); + return; + } + + if (confirmPinValue.length != pinLength) { + _validationPopup.showErrorMessage(context, "Please confirm your PIN"); + return; + } + + if (pinValue != confirmPinValue) { + _validationPopup.showErrorMessage(context, "PINs do not match"); + return; + } + + // Call API to set/change PIN + await ref.read(changePinProvider.notifier).changePin(pinValue); + final state = ref.read(changePinProvider); + + state.when( + data: (result) { + if (result['success'] == true) { + _validationPopup.showSuccessMessage( + context, + "MPIN Set Successfully!", + ); + Future.delayed(const Duration(seconds: 1), () { + Navigator.of(context).pop(); + }); + } else { + _validationPopup.showErrorMessage( + context, + result['error'] ?? "Failed to set MPIN. Please try again.", + ); + } + }, + loading: () {}, + error: (error, stack) { + _validationPopup.showErrorMessage( + context, + "Failed to set MPIN. Please try again.", + ); + }, + ); + } + + void _onPinChange(int index, String value) { + if (value.isNotEmpty && index < pinLength - 1) { + _focusNodes[index + 1].requestFocus(); + } + if (value.isEmpty && index > 0) { + _focusNodes[index - 1].requestFocus(); + } + setState(() { + pinValue = _controllers.map((c) => c.text).join(); + }); + } + + void _onConfirmPinChange(int index, String value) { + if (value.isNotEmpty && index < pinLength - 1) { + _confirmFocusNodes[index + 1].requestFocus(); + } + if (value.isEmpty && index > 0) { + _confirmFocusNodes[index - 1].requestFocus(); + } + setState(() { + confirmPinValue = _confirmControllers.map((c) => c.text).join(); + }); + } + + @override + Widget build(BuildContext context) { + final pinState = ref.watch(changePinProvider); + final isLoading = pinState is AsyncLoading; + + final r = ResponsiveUtils(context); + + final logoWidth = r.getValue(mobile: 120, tablet: 141, desktop: 160); + final logoHeight = r.getValue(mobile: 85, tablet: 100, desktop: 115); + final titleFontSize = r.fontSize(mobile: 26, tablet: 32, desktop: 36); + final subtitleFontSize = r.fontSize(mobile: 13, tablet: 14, desktop: 15); + + final boxWidth = r.getValue(mobile: 57, tablet: 60, desktop: 68); + final boxHeight = r.getValue(mobile: 57, tablet: 56, desktop: 64); + final pinFontSize = r.fontSize(mobile: 22, tablet: 28, desktop: 32); + final boxMargin = r.getValue(mobile: 5, tablet: 6, desktop: 8); + final boxRadius = r.getValue(mobile: 5, tablet: 6, desktop: 8); + + final spacingSM = r.spacing(mobile: 20, tablet: 20, desktop: 24); + final spacingLG = r.spacing(mobile: 50, tablet: 50, desktop: 50); + + return Scaffold( + body: Stack( + children: [ + Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFFFFF8F0), + Color(0xFFEBC894), + Color(0xFFE8DAF2), + Color(0xFFB49EF4), + ], + stops: [0.0, 0.3, 0.6, 1.0], + ), + ), + ), + SingleChildScrollView( + child: SizedBox( + height: r.screenHeight, + child: Center( + child: CommonContainerAuth( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + AppAssets.taxgildelogoauth, + width: logoWidth, + height: logoHeight, + fit: BoxFit.contain, + ), + SizedBox(height: spacingSM), + Text( + "Change Your PIN", + textAlign: TextAlign.center, + style: AppTextStyles.semiBold.copyWith( + fontSize: titleFontSize, + color: AppColors.authheading, + ), + ), + SizedBox(height: spacingSM), + Text( + "Set a 4-digit security PIN for your account", + textAlign: TextAlign.center, + style: AppTextStyles.semiBold.copyWith( + fontSize: subtitleFontSize, + color: AppColors.authleading, + ), + ), + SizedBox(height: spacingLG), + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: boxMargin * 2), + child: Text( + "Enter PIN *", + style: AppTextStyles.medium.copyWith( + fontSize: subtitleFontSize, + color: AppColors.authheading, + ), + ), + ), + ), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(pinLength, (index) { + bool isFilled = _controllers[index].text.isNotEmpty; + return Container( + margin: EdgeInsets.symmetric(horizontal: boxMargin), + width: boxWidth, + height: boxHeight, + decoration: BoxDecoration( + color: isFilled ? AppColors.commanbutton : Colors.white, + borderRadius: BorderRadius.circular(boxRadius), + border: Border.all(color: const Color(0xFFDFDFDF)), + boxShadow: [ + BoxShadow( + color: const Color(0xFFBDBDBD).withOpacity(0.25), + blurRadius: 7, + offset: const Offset(0, 1), + ), + ], + ), + child: Center( + child: KeyboardListener( + focusNode: FocusNode(), + onKeyEvent: (event) { + if (event is KeyDownEvent && + event.logicalKey == + LogicalKeyboardKey.backspace) { + if (_controllers[index].text.isEmpty && + index > 0) { + _focusNodes[index - 1].requestFocus(); + } + } + }, + child: TextField( + controller: _controllers[index], + focusNode: _focusNodes[index], + textAlign: TextAlign.center, + keyboardType: TextInputType.number, + maxLength: 1, + obscureText: true, + enabled: !isLoading, + style: TextStyle( + fontFamily: "Gilroy", + fontWeight: FontWeight.w400, + fontSize: pinFontSize, + color: isFilled ? Colors.white : Colors.black, + ), + decoration: const InputDecoration( + counterText: '', + border: InputBorder.none, + ), + onChanged: (value) => + _onPinChange(index, value), + ), + ), + ), + ); + }), + ), + SizedBox(height: spacingSM), + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: boxMargin * 2), + child: Text( + "Confirm PIN *", + style: AppTextStyles.medium.copyWith( + fontSize: subtitleFontSize, + color: AppColors.authheading, + ), + ), + ), + ), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(pinLength, (index) { + bool isFilled = _confirmControllers[index].text.isNotEmpty; + return Container( + margin: EdgeInsets.symmetric(horizontal: boxMargin), + width: boxWidth, + height: boxHeight, + decoration: BoxDecoration( + color: isFilled ? AppColors.commanbutton : Colors.white, + borderRadius: BorderRadius.circular(boxRadius), + border: Border.all(color: const Color(0xFFDFDFDF)), + boxShadow: [ + BoxShadow( + color: const Color(0xFFBDBDBD).withOpacity(0.25), + blurRadius: 7, + offset: const Offset(0, 1), + ), + ], + ), + child: Center( + child: KeyboardListener( + focusNode: FocusNode(), + onKeyEvent: (event) { + if (event is KeyDownEvent && + event.logicalKey == + LogicalKeyboardKey.backspace) { + if (_confirmControllers[index].text.isEmpty && + index > 0) { + _confirmFocusNodes[index - 1].requestFocus(); + } + } + }, + child: TextField( + controller: _confirmControllers[index], + focusNode: _confirmFocusNodes[index], + textAlign: TextAlign.center, + keyboardType: TextInputType.number, + maxLength: 1, + obscureText: true, + enabled: !isLoading, + style: TextStyle( + fontFamily: "Gilroy", + fontWeight: FontWeight.w400, + fontSize: pinFontSize, + color: isFilled ? Colors.white : Colors.black, + ), + decoration: const InputDecoration( + counterText: '', + border: InputBorder.none, + ), + onChanged: (value) => + _onConfirmPinChange(index, value), + ), + ), + ), + ); + }), + ), + SizedBox(height: spacingLG), + isLoading + ? const CircularProgressIndicator() + : CommanButton( + text: "Set PIN", + onPressed: _handleAction, + ), + ], + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/view/screens/profile/employee_profile/employee_profile_screen.dart b/lib/view/screens/profile/employee_profile/employee_profile_screen.dart index 3747358..5a70c6c 100644 --- a/lib/view/screens/profile/employee_profile/employee_profile_screen.dart +++ b/lib/view/screens/profile/employee_profile/employee_profile_screen.dart @@ -144,6 +144,18 @@ class _EmployeeProfileScreenState extends ConsumerState { }, ), const SizedBox(height: 16), + _buildMenuItem( + id: 'change_pin', + icon: Icons.lock_outline, + title: 'Change PIN', + onTap: () { + setState(() { + selectedItem = 'change_pin'; + }); + Get.toNamed(ConstRouters.changePin); + }, + ), + const SizedBox(height: 16), _buildMenuItem( id: 'terms', diff --git a/lib/view/screens/profile/profile_screen.dart b/lib/view/screens/profile/profile_screen.dart index 2335a60..730c563 100644 --- a/lib/view/screens/profile/profile_screen.dart +++ b/lib/view/screens/profile/profile_screen.dart @@ -152,6 +152,18 @@ class _ProfileScreenState extends ConsumerState { }, ), const SizedBox(height: 16), + _buildMenuItem( + id: 'change_pin', + icon: Icons.lock_outline, + title: 'Change PIN', + onTap: () { + setState(() { + selectedItem = 'change_pin'; + }); + Get.toNamed(ConstRouters.changePin); + }, + ), + const SizedBox(height: 16), if (userRole != "employee") _buildMenuItem( id: 'Staff',