ui improvements

export_module_ui_ux_enhancement_signup
Sikander Saleem 6 hours ago
parent 7186fb13c0
commit 15187d30f4

@ -276,7 +276,7 @@ class UserProvider extends ChangeNotifier {
// }
// return response.statusCode;
// }
Future<GeneralResponseModel> sendForgetPasswordOtp({required BuildContext context, required String employeeId}) async {
Future<GeneralResponseModel> sendForgetPasswordOtp({required BuildContext context, required String employeeId, required String typeSend}) async {
GeneralResponseModel generalResponseModel = GeneralResponseModel(responseCode: -1);
if (_loading == true) return generalResponseModel;
_loading = true;
@ -284,7 +284,7 @@ class UserProvider extends ChangeNotifier {
Response response;
try {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
response = await ApiManager.instance.post(URLs.sendForgetPasswordOtp + '?employeeId=$employeeId', showToast: false, body: {});
response = await ApiManager.instance.post(URLs.sendForgetPasswordOtp, showToast: false, body: {"employeeId": employeeId, "typeSend": typeSend});
generalResponseModel = GeneralResponseModel.fromJson(json.decode(response.body));
_loading = false;
if (response.statusCode >= 200 && response.statusCode < 300) {

@ -72,81 +72,82 @@ class _ApplicationDemoRequestFormScreenState extends State<ApplicationDemoReques
autovalidateMode: AutovalidateMode.disabled,
child: Column(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppTextFormField(
controller: _fullNameController,
labelText: 'Full Name *',
textInputType: TextInputType.name,
validator: (value) {
if (!_formSubmitted && _fullNameController.text.isEmpty) return null;
if (_fullNameController.text.isEmpty) return 'Full Name is required';
return null;
},
),
16.height,
AppTextFormField(
controller: _emailController,
labelText: 'Email Address *',
textInputType: TextInputType.emailAddress,
validator: (value) {
if (!_formSubmitted && _emailController.text.isEmpty) return null;
if (_emailController.text.isEmpty) return 'Email is required';
if (!Validator.isEmail(_emailController.text)) return 'Invalid email format';
return null;
},
),
16.height,
AppTextFormField(
controller: _mobileController,
labelText: 'Mobile Number *',
textInputType: TextInputType.phone,
validator: (value) {
if (!_formSubmitted && _mobileController.text.isEmpty) return null;
if (_mobileController.text.isEmpty) return 'Mobile Number is required';
if (!Validator.isPhoneNumber(_mobileController.text)) return 'Invalid mobile number';
return null;
},
),
16.height,
AppTextFormField(
controller: _companyNameController,
labelText: 'Company Name *',
textInputType: TextInputType.text,
validator: (value) {
if (!_formSubmitted && _companyNameController.text.isEmpty) return null;
if (_companyNameController.text.isEmpty) return 'Company Name is required';
return null;
},
),
16.height,
MultipleItemDropDownMenu<ApplicationDemoRoleModel, NullableLoadingProvider>(
context: context,
title: 'Select Roles *',
initialValue: _selectedRoles,
staticData: provider.roles,
loading: provider.roleLoading,
showAsFullScreenDialog: true,
onSelect: (selectedRoles) {
setState(() {
_selectedRoles = selectedRoles ?? [];
_rolesValidationError = null; // Clear error when roles are selected
});
},
),
if (_rolesValidationError != null)
Padding(
padding: const EdgeInsets.only(top: 8, left: 16),
child: Text(
_rolesValidationError!,
style: AppTextStyles.tinyFont.copyWith(
color: AppColor.red30,
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
spacing: 12,
children: [
AppTextFormField(
controller: _fullNameController,
labelText: 'Full Name *',
textInputType: TextInputType.name,
validator: (value) {
if (!_formSubmitted && _fullNameController.text.isEmpty) return null;
if (_fullNameController.text.isEmpty) return 'Full Name is required';
return null;
},
),
AppTextFormField(
controller: _emailController,
labelText: 'Email Address *',
textInputType: TextInputType.emailAddress,
validator: (value) {
if (!_formSubmitted && _emailController.text.isEmpty) return null;
if (_emailController.text.isEmpty) return 'Email is required';
if (!Validator.isEmail(_emailController.text)) return 'Invalid email format';
return null;
},
),
AppTextFormField(
controller: _mobileController,
labelText: 'Mobile Number *',
textInputType: TextInputType.phone,
validator: (value) {
if (!_formSubmitted && _mobileController.text.isEmpty) return null;
if (_mobileController.text.isEmpty) return 'Mobile Number is required';
if (!Validator.isPhoneNumber(_mobileController.text)) return 'Invalid mobile number';
return null;
},
),
AppTextFormField(
controller: _companyNameController,
labelText: 'Company Name *',
textInputType: TextInputType.text,
validator: (value) {
if (!_formSubmitted && _companyNameController.text.isEmpty) return null;
if (_companyNameController.text.isEmpty) return 'Company Name is required';
return null;
},
),
MultipleItemDropDownMenu<ApplicationDemoRoleModel, NullableLoadingProvider>(
context: context,
title: 'Select Roles *',
initialValue: _selectedRoles,
staticData: provider.roles,
loading: provider.roleLoading,
showAsFullScreenDialog: true,
onSelect: (selectedRoles) {
setState(() {
_selectedRoles = selectedRoles ?? [];
_rolesValidationError = null; // Clear error when roles are selected
});
},
),
if (_rolesValidationError != null)
Padding(
padding: const EdgeInsets.only(top: 8, left: 16),
child: Text(
_rolesValidationError!,
style: AppTextStyles.tinyFont.copyWith(
color: AppColor.red30,
),
),
),
),
],
).paddingAll(16).expanded,
],
).toShadowContainer(context, borderRadius: 20),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(

@ -5,6 +5,7 @@ import 'package:test_sa/controllers/validator/validator.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/signup/models/company_model.dart';
import 'package:test_sa/modules/signup/models/group_model.dart';
import 'package:test_sa/modules/signup/models/signup_request_model.dart';
@ -95,41 +96,35 @@ class _SignUpScreenState extends State<SignUpScreen> {
appBar: const DefaultAppBar(title: "Sign Up"),
body: Column(
children: [
Expanded(
SingleChildScrollView(
padding: EdgeInsets.all(16.toScreenWidth),
child: Form(
key: _formKey,
child: SingleChildScrollView(
padding: EdgeInsets.all(16.toScreenWidth),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildAssetGroupDropdown(),
16.height,
if (_selectedAssetGroup != null) ...[
_buildCompanyDropdown(),
16.height,
],
if (_selectedCompany != null) ..._buildDynamicFields(),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 12,
children: [
_buildAssetGroupDropdown(),
// 16.height,
if (_selectedAssetGroup != null) ...[
_buildCompanyDropdown(),
// 16.height,
],
),
),
if (_selectedCompany != null) ..._buildDynamicFields(),
],
).toShadowContainer(context, borderRadius: 20),
),
),
).expanded,
if (_selectedCompany != null)
Container(
padding: EdgeInsets.all(16.toScreenWidth),
decoration: BoxDecoration(
color: AppColor.background(context),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, -2),
),
],
),
child: SafeArea(
child: _buildSubmitButton(),
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
label: "Submit",
maxWidth: true,
loading: _isSubmitting,
disableButton: _isSubmitting,
onPressed: _submitForm,
),
),
],
@ -199,20 +194,20 @@ class _SignUpScreenState extends State<SignUpScreen> {
if (_isHMGGroup) {
return [
_buildEmployeeIdField(),
16.height,
// 16.height,
if (_employeeFetched) ...[
_buildReadOnlyField("Full Name", _fullNameController),
_buildReadOnlyField("Email Address", _emailController),
_buildReadOnlyField("Mobile Number", _mobileController),
// _buildReadOnlyField("Site", _siteController),
// _buildReadOnlyField("Department", _departmentController),
16.height,
// 16.height,
_buildExtensionField(),
16.height,
// 16.height,
_buildSiteDropdown(),
16.height,
// 16.height,
_buildDepartmentDropdown(),
16.height,
// 16.height,
_buildRoleField(),
],
];
@ -220,17 +215,17 @@ class _SignUpScreenState extends State<SignUpScreen> {
return [
// Employee ID is auto-generated for Non-HMG, so not shown during signup
_buildFullNameField(),
16.height,
// 16.height,
_buildEmailField(),
16.height,
// 16.height,
_buildMobileField(),
16.height,
// 16.height,
_buildExtensionField(),
16.height,
// 16.height,
_buildSiteDropdown(),
16.height,
// 16.height,
_buildDepartmentDropdown(),
16.height,
// 16.height,
_buildRoleField(),
];
}
@ -285,7 +280,7 @@ class _SignUpScreenState extends State<SignUpScreen> {
}
Widget _buildReadOnlyField(String label, TextEditingController controller) {
if(controller.text.isEmpty) {
if (controller.text.isEmpty) {
return const SizedBox();
}
return Column(
@ -403,16 +398,6 @@ class _SignUpScreenState extends State<SignUpScreen> {
);
}
Widget _buildSubmitButton() {
return AppFilledButton(
label: "Submit",
maxWidth: true,
loading: _isSubmitting,
disableButton: _isSubmitting,
onPressed: _submitForm,
);
}
Future<void> _fetchEmployeeDetails(String employeeId) async {
final employee = await _signUpProvider.getEmployeeFromERP(employeeId);
@ -436,7 +421,7 @@ class _SignUpScreenState extends State<SignUpScreen> {
_emailController.text = employee.employeeEmailAddress ?? '';
_mobileController.text = employee.employeeMobileNumber ?? '';
//Todo need to map site and department from ERP data
_departmentController.text = '';
_departmentController.text = '';
_siteController.text = employee.branchCode ?? '';
});
} else {

@ -12,6 +12,7 @@ import 'package:test_sa/models/new_models/general_response_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/forget_password_module/reset_password_view.dart';
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
class ForgetPasswordVerifyOtpView extends StatefulWidget {
Map<String, dynamic> data = {};
@ -65,9 +66,9 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
color: Colors.black,
),
decoration: BoxDecoration(
color: AppColor.white10,
color: AppColor.background(context),
borderRadius: BorderRadius.circular(15),
border: Border.all(color: AppColor.white10, width: 1),
border: Border.all(color: AppColor.borderColor(context), width: 1),
),
);
@ -82,17 +83,17 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
context.translation.otpVerification.heading2(context).custom(color: AppColor.white936, fontWeight: FontWeight.w500),
Text(context.translation.otpVerification, style: AppTextStyles.heading2.copyWith(color: AppColor.headingTextColor(context), fontWeight: FontWeight.w500)),
8.height,
'${context.translation.pleaseEnterTheOtpSentTo} ${widget.data['phoneNumber']}'.bodyText2(context).custom(color: AppColor.neutral120, fontWeight: FontWeight.w500),
40.height,
InfoTextLabelWidget(label: '${context.translation.pleaseEnterTheOtpSentTo} ${widget.data['phoneNumber']}'),
32.height,
Center(
child: Pinput(
length: 4,
defaultPinTheme: defaultPinTheme,
focusedPinTheme: defaultPinTheme.copyWith(
decoration: defaultPinTheme.decoration?.copyWith(
border: Border.all(color: AppColor.neutral40, width: 1),
border: Border.all(color: AppColor.borderColor(context), width: 1),
),
),
onCompleted: (pin) {
@ -112,10 +113,7 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
? () async {
UserProvider _userProvider = Provider.of<UserProvider>(context, listen: false);
String employeeId = widget.data['employeeId'];
GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(
context: context,
employeeId: employeeId,
);
GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(context: context, employeeId: employeeId, typeSend: widget.data['typeSend']);
// Restart the timer
_startTimer();

@ -11,6 +11,8 @@ import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/pages/login_page.dart';
import 'package:test_sa/views/widgets/item_views/info_header_widget.dart';
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
import '../../controllers/providers/api/user_provider.dart';
import '../../controllers/validator/validator.dart';
@ -45,9 +47,9 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
context.translation.resetPassword.heading2(context).custom(color: AppColor.white936, fontWeight: FontWeight.w500),
Text(context.translation.resetPassword, style: AppTextStyles.heading2.copyWith(color: AppColor.headingTextColor(context), fontWeight: FontWeight.w500)),
8.height,
context.translation.pleaseEnterTheNewPassword.bodyText2(context).custom(color: AppColor.neutral120, fontWeight: FontWeight.w500),
InfoTextLabelWidget(label: context.translation.pleaseEnterTheNewPassword),
32.height,
AppTextFormField(
initialValue: "",
@ -56,10 +58,11 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
labelText: context.translation.password,
obscureText: !_passwordVisible,
suffixIcon: Icon(
// Based on passwordVisible state choose the icon
_passwordVisible ? Icons.visibility : Icons.visibility_off,
color: context.isDark ? AppColor.neutral10 : AppColor.neutral20,
).paddingOnly(end: 12).onPress(() {
// Based on passwordVisible state choose the icon
_passwordVisible ? Icons.visibility : Icons.visibility_off,
color: AppColor.icon2Color(context))
.paddingOnly(end: 12)
.onPress(() {
setState(() {
_passwordVisible = !_passwordVisible;
});
@ -82,10 +85,7 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
onSaved: (value) {
confirmPassword = value;
},
suffixIcon: Icon(
_confirmPasswordVisible ? Icons.visibility : Icons.visibility_off,
color: context.isDark ? AppColor.neutral10 : AppColor.neutral20,
).paddingOnly(end: 12).onPress(() {
suffixIcon: Icon(_confirmPasswordVisible ? Icons.visibility : Icons.visibility_off, color: AppColor.icon2Color(context)).paddingOnly(end: 12).onPress(() {
setState(() {
_confirmPasswordVisible = !_confirmPasswordVisible;
});
@ -107,11 +107,11 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
if (newPassword != confirmPassword) {
Fluttertoast.showToast(msg: 'Password not matched try again');
} else {
UserProvider userProvider = Provider.of<UserProvider>(context,listen: false);
UserProvider userProvider = Provider.of<UserProvider>(context, listen: false);
UpdatePasswordModel updatePasswordModel =
UpdatePasswordModel(password: newPassword, confirmPassword: confirmPassword, userId: userProvider.verifyOtpModel.userId, token: userProvider.verifyOtpModel.token);
GeneralResponseModel generalResponseModel = await userProvider.updateNewPassword(context: context, updatePasswordModel: updatePasswordModel);
if (generalResponseModel.isSuccess==true) {
if (generalResponseModel.isSuccess == true) {
newPassword = '';
confirmPassword = '';
Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);

@ -20,6 +20,7 @@ import 'package:test_sa/modules/applicationDemo/screens/demo_request_form_screen
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/forget_password_module/forget_passwod_verify_otp.dart';
import 'package:test_sa/new_views/pages/land_page/land_page.dart';
import 'package:test_sa/views/widgets/dialogs/dialog.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../controllers/providers/api/user_provider.dart';
@ -160,14 +161,29 @@ class _LoginPageState extends State<LoginPage> {
Align(
alignment: AlignmentDirectional.centerEnd,
child: context.translation.forgotPassword.bodyText(context).custom(color: AppColor.primary10, fontWeight: FontWeight.w500).onPress(() async {
String? methodType;
bool result = await showDialog(
context: context,
builder: (_) =>
AAlertDialog(title: "OTP Verification".addTranslation, content: "Please choose the OTP verification method".addTranslation, button1Text: "SMS", button2Text: "Email"),
);
if (result == true) {
methodType = "SMS";
} else {
methodType = "EMAIL";
}
if (methodType == null) {
return;
}
if (userNameController.text.isNotEmpty) {
GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(context: context, employeeId: userNameController.text);
GeneralResponseModel response = await _userProvider.sendForgetPasswordOtp(context: context, employeeId: userNameController.text, typeSend: methodType);
if (response.isSuccess == true) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ForgetPasswordVerifyOtpView(
data: {'employeeId': userNameController.text, 'phoneNumber': response.data},
data: {'employeeId': userNameController.text, 'phoneNumber': response.data, 'typeSend': methodType},
)));
// Navigator.push(context, ForgetPasswordVerifyOtpView.routeName);
} else {

@ -9,8 +9,10 @@ import 'package:test_sa/new_views/app_style/app_color.dart';
class AAlertDialog extends StatelessWidget {
final String? title;
final String? content;
final String? button1Text;
final String? button2Text;
const AAlertDialog({Key? key, this.title, this.content}) : super(key: key);
const AAlertDialog({Key? key, this.title, this.content, this.button1Text, this.button2Text}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -21,14 +23,14 @@ class AAlertDialog extends StatelessWidget {
actions: <Widget>[
TextButton(
// child: Text(_subtitle.confirm),
child: Text(context.translation.confirm),
child: Text(button1Text ?? context.translation.confirm),
onPressed: () {
Navigator.of(context).pop(true);
},
),
TextButton(
// child: Text(_subtitle.cancel),
child: Text(context.translation.cancel),
child: Text(button2Text ?? context.translation.cancel),
onPressed: () {
Navigator.of(context).pop(false);
},
@ -43,14 +45,14 @@ class AAlertDialog extends StatelessWidget {
actions: <Widget>[
TextButton(
// child: Text(_subtitle.confirm),
child: Text(context.translation.confirm, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))),
child: Text(button1Text ?? context.translation.confirm, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))),
onPressed: () {
Navigator.of(context).pop(true);
},
),
TextButton(
// child: Text(_subtitle.cancel),
child: Text(context.translation.cancel, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))),
child: Text(button2Text ?? context.translation.cancel, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))),
onPressed: () {
Navigator.of(context).pop(false);
},
@ -59,7 +61,3 @@ class AAlertDialog extends StatelessWidget {
);
}
}

Loading…
Cancel
Save