Compare commits

..

2 Commits

Author SHA1 Message Date
WaseemAbbasi22 5137f2dd34 bug fixes 1 month ago
WaseemAbbasi22 359c796b72 ATOMS-2016 ,ATOMS-2018 bugs fixed 2 months ago

@ -65,7 +65,7 @@ import 'package:test_sa/modules/site_request_module/providers/site_request_provi
import 'package:test_sa/modules/site_request_module/screens/site_request_form_screen.dart'; import 'package:test_sa/modules/site_request_module/screens/site_request_form_screen.dart';
import 'package:test_sa/modules/site_request_module/screens/site_request_history_screen.dart'; import 'package:test_sa/modules/site_request_module/screens/site_request_history_screen.dart';
import 'package:test_sa/modules/applicationDemo/providers/application_demo_request_provider.dart'; import 'package:test_sa/modules/applicationDemo/providers/application_demo_request_provider.dart';
import 'package:test_sa/modules/applicationDemo/screens/demo_request_form_screen.dart'; import 'package:test_sa/modules/applicationDemo/screens/application_demo_request_form_screen.dart';
import 'package:test_sa/modules/tm_module/gas_refill/create_gas_refill_request.dart'; import 'package:test_sa/modules/tm_module/gas_refill/create_gas_refill_request.dart';
import 'package:test_sa/modules/tm_module/gas_refill/update_gas_refill_request.dart'; import 'package:test_sa/modules/tm_module/gas_refill/update_gas_refill_request.dart';
import 'package:test_sa/new_views/app_style/app_themes.dart'; import 'package:test_sa/new_views/app_style/app_themes.dart';

@ -32,12 +32,12 @@ import 'package:test_sa/new_views/swipe_module/dialoge/acknowledge_work_dialog.d
import 'package:test_sa/providers/service_request_providers/reject_reason_provider.dart'; import 'package:test_sa/providers/service_request_providers/reject_reason_provider.dart';
class FooterActionButton { class FooterActionButton {
static Widget footerContainer({required Widget child, required BuildContext context}) { static Widget footerContainer({required Widget child, required BuildContext context, bool safeAreaTop = true}) {
return Container( return Container(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
padding: const EdgeInsets.only(left: 16, right: 16, top: 12, bottom: 12), padding: const EdgeInsets.only(left: 16, right: 16, top: 12, bottom: 12),
color: AppColor.background(context), color: AppColor.background(context),
child: SafeArea(child: child), child: SafeArea(top: safeAreaTop, child: child),
); );
} }

@ -3,6 +3,7 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/validator/validator.dart'; import 'package:test_sa/controllers/validator/validator.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_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/cm_module/views/components/action_button/footer_action_button.dart';
@ -62,6 +63,9 @@ class _SignUpScreenState extends State<SignUpScreen> {
bool _employeeFetched = false; bool _employeeFetched = false;
bool _isSubmitting = false; bool _isSubmitting = false;
// Autovalidate mode - enables validation on user interaction after first submit attempt
AutovalidateMode _autovalidateMode = AutovalidateMode.disabled;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -100,6 +104,7 @@ class _SignUpScreenState extends State<SignUpScreen> {
padding: EdgeInsets.all(16.toScreenWidth), padding: EdgeInsets.all(16.toScreenWidth),
child: Form( child: Form(
key: _formKey, key: _formKey,
autovalidateMode: _autovalidateMode, // Set autovalidate mode
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -135,7 +140,7 @@ class _SignUpScreenState extends State<SignUpScreen> {
Widget _buildAssetGroupDropdown() { Widget _buildAssetGroupDropdown() {
return SingleItemDropDownMenu<AssetGroup, AssetGroupProvider>( return SingleItemDropDownMenu<AssetGroup, AssetGroupProvider>(
context: context, context: context,
title: "Asset Group", title: "Group".addTranslation,
initialValue: _selectedAssetGroup, initialValue: _selectedAssetGroup,
showAsFullScreenDialog: true, showAsFullScreenDialog: true,
showAsBottomSheet: false, showAsBottomSheet: false,
@ -154,7 +159,7 @@ class _SignUpScreenState extends State<SignUpScreen> {
} }
}, },
validator: (value) { validator: (value) {
if (value == null) return "Asset Group is required"; if (value == null) return "Group is required";
return null; return null;
}, },
); );
@ -240,15 +245,8 @@ class _SignUpScreenState extends State<SignUpScreen> {
controller: _employeeIdController, controller: _employeeIdController,
labelText: "Employee ID", labelText: "Employee ID",
textInputType: TextInputType.number, textInputType: TextInputType.number,
onChange: (value) {
// Clear validation errors on user interaction
// if (_formKey.currentState != null) {
// _formKey.currentState!.validate();
// }
},
validator: (value) { validator: (value) {
if (_employeeIdController.text.isEmpty) return "Employee ID is required"; if (_employeeIdController.text.isEmpty) return "Employee ID is required";
// if (!Validator.isNumeric(_employeeIdController.text)) return "Employee ID must be numeric";
return null; return null;
}, },
), ),
@ -487,6 +485,10 @@ class _SignUpScreenState extends State<SignUpScreen> {
Future<void> _submitForm() async { Future<void> _submitForm() async {
// Validate form fields // Validate form fields
if (!_formKey.currentState!.validate()) { if (!_formKey.currentState!.validate()) {
// Enable autovalidation after first submit attempt
setState(() {
_autovalidateMode = AutovalidateMode.onUserInteraction;
});
Fluttertoast.showToast(msg: "Please fill all required fields"); Fluttertoast.showToast(msg: "Please fill all required fields");
return; return;
} }

@ -40,19 +40,32 @@ class SiteRequestProvider extends ChangeNotifier {
// Getters // Getters
bool get loading => _loading; bool get loading => _loading;
bool get isLoadingMore => _isLoadingMore; bool get isLoadingMore => _isLoadingMore;
String? get errorMessage => _errorMessage; String? get errorMessage => _errorMessage;
int get currentPage => _currentPage; int get currentPage => _currentPage;
bool get hasMoreData => _hasMoreData; bool get hasMoreData => _hasMoreData;
List<RequestTypeModel> get requestTypes => _requestTypes; List<RequestTypeModel> get requestTypes => _requestTypes;
List<SiteRequestSiteModel> get userCurrentSites => _userCurrentSites; List<SiteRequestSiteModel> get userCurrentSites => _userCurrentSites;
List<SiteRequestModel> get requestHistory => _requestHistory; List<SiteRequestModel> get requestHistory => _requestHistory;
// User helper methods // User helper methods
String getCurrentUserEmployeeId(UserProvider userProvider) => userProvider.user?.userID ?? ''; String getCurrentUserUserId(UserProvider userProvider) => userProvider.user?.userID ?? '';
String getCurrentUserEmployeeId(UserProvider userProvider) => userProvider.user?.employeeId ?? '';
String getCurrentUserFullName(UserProvider userProvider) => userProvider.user?.username ?? ''; String getCurrentUserFullName(UserProvider userProvider) => userProvider.user?.username ?? '';
String getCurrentUserEmail(UserProvider userProvider) => userProvider.user?.email ?? ''; String getCurrentUserEmail(UserProvider userProvider) => userProvider.user?.email ?? '';
String getCurrentUserMobile(UserProvider userProvider) => userProvider.user?.phoneNumber ?? ''; String getCurrentUserMobile(UserProvider userProvider) => userProvider.user?.phoneNumber ?? '';
String getCurrentUserExtension(UserProvider userProvider) => userProvider.user?.extensionNo ?? ''; String getCurrentUserExtension(UserProvider userProvider) => userProvider.user?.extensionNo ?? '';
String getCurrentUserRole(UserProvider userProvider) { String getCurrentUserRole(UserProvider userProvider) {
@ -63,6 +76,7 @@ class SiteRequestProvider extends ChangeNotifier {
} }
List<String> getCurrentUserAssignedSites(UserProvider userProvider) => []; List<String> getCurrentUserAssignedSites(UserProvider userProvider) => [];
bool hasAssignedSites(List<String> assignedSites) => assignedSites.isNotEmpty; bool hasAssignedSites(List<String> assignedSites) => assignedSites.isNotEmpty;
// Setter // Setter
@ -118,8 +132,7 @@ class SiteRequestProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
try { try {
final isChangeSiteRequest = _requestTypes.any((type) => final isChangeSiteRequest = _requestTypes.any((type) => type.identifier == request.requestType && (type.name?.toLowerCase().contains('change') ?? false));
type.identifier == request.requestType && (type.name?.toLowerCase().contains('change') ?? false));
final requestBody = _buildRequestBody(request, userProvider, isChangeSiteRequest); final requestBody = _buildRequestBody(request, userProvider, isChangeSiteRequest);
@ -164,7 +177,7 @@ class SiteRequestProvider extends ChangeNotifier {
body: { body: {
"pageSize": size, "pageSize": size,
"pageNumber": page, "pageNumber": page,
"userId": getCurrentUserEmployeeId(userProvider), "userId": getCurrentUserUserId(userProvider),
}, },
); );
@ -245,16 +258,8 @@ class SiteRequestProvider extends ChangeNotifier {
"id": 0, "id": 0,
"siteId": int.tryParse(request.siteIds[index]) ?? 0, "siteId": int.tryParse(request.siteIds[index]) ?? 0,
"siteName": request.siteNames[index], "siteName": request.siteNames[index],
"oldSiteId": (isChangeSiteRequest && "oldSiteId": (isChangeSiteRequest && request.oldSiteIds != null && index < request.oldSiteIds!.length) ? int.tryParse(request.oldSiteIds![index]) ?? 0 : 0,
request.oldSiteIds != null && "oldSitName": (isChangeSiteRequest && request.oldSiteNames != null && index < request.oldSiteNames!.length) ? request.oldSiteNames![index] : ""
index < request.oldSiteIds!.length)
? int.tryParse(request.oldSiteIds![index]) ?? 0
: 0,
"oldSitName": (isChangeSiteRequest &&
request.oldSiteNames != null &&
index < request.oldSiteNames!.length)
? request.oldSiteNames![index]
: ""
}; };
}).toList(); }).toList();
@ -270,7 +275,7 @@ class SiteRequestProvider extends ChangeNotifier {
return { return {
"id": 0, "id": 0,
"userId": getCurrentUserEmployeeId(userProvider), "userId": getCurrentUserUserId(userProvider),
"requestTypeId": int.tryParse(request.requestType) ?? 0, "requestTypeId": int.tryParse(request.requestType) ?? 0,
"siteIds": siteIdsArray, "siteIds": siteIdsArray,
"departmentIds": departmentIdsArray, "departmentIds": departmentIdsArray,
@ -322,9 +327,7 @@ class SiteRequestProvider extends ChangeNotifier {
final data = json.decode(response.body); final data = json.decode(response.body);
if (data['isSuccess'] == true) { if (data['isSuccess'] == true) {
final siteRequests = (data['data'] as List?) final siteRequests = (data['data'] as List?)?.map((item) => SiteRequestModel.fromJson(item)).toList() ?? [];
?.map((item) => SiteRequestModel.fromJson(item))
.toList() ?? [];
if (loadMore) { if (loadMore) {
_requestHistory.addAll(siteRequests); _requestHistory.addAll(siteRequests);

@ -1,9 +1,12 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/models/new_models/site.dart';
@ -159,7 +162,7 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
Widget _buildRequestTypeDropdown() { Widget _buildRequestTypeDropdown() {
return SingleItemDropDownMenu<RequestTypeModel, NullableLoadingProvider>( return SingleItemDropDownMenu<RequestTypeModel, NullableLoadingProvider>(
context: context, context: context,
title: "Type of Site Request", title: "Type of site request".addTranslation,
initialValue: _selectedRequestType, initialValue: _selectedRequestType,
staticData: _provider.requestTypes, staticData: _provider.requestTypes,
showAsFullScreenDialog: true, showAsFullScreenDialog: true,
@ -175,7 +178,7 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
// Fetch user's current sites if Change Site or Remove Site is selected // Fetch user's current sites if Change Site or Remove Site is selected
if ((_isChangeSiteRequest() || _isRemoveSiteRequest()) && value != null) { if ((_isChangeSiteRequest() || _isRemoveSiteRequest()) && value != null) {
final userId = _provider.getCurrentUserEmployeeId(_userProvider); final userId = _provider.getCurrentUserUserId(_userProvider);
await _provider.fetchUserCurrentSites(userId); await _provider.fetchUserCurrentSites(userId);
} }
@ -200,28 +203,34 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
children: [ children: [
InfoHeader16Widget("Requester Information"), InfoHeader16Widget("Requester Information"),
// 8.height, // 8.height,
// InfoTextWidget(
// label: "Employee ID".addTranslation,
// value: _provider.getCurrentUserEmployeeId(_userProvider),
// showEmptyValue: true,
// ),
InfoTextWidget( InfoTextWidget(
label: "Full Name", label: "Full Name".addTranslation,
value: _provider.getCurrentUserFullName(_userProvider), value: _provider.getCurrentUserFullName(_userProvider),
showEmptyValue: true, showEmptyValue: true,
), ),
InfoTextWidget( InfoTextWidget(
label: "Email Address", label: "Email Address".addTranslation,
value: _provider.getCurrentUserEmail(_userProvider), value: _provider.getCurrentUserEmail(_userProvider),
showEmptyValue: true, showEmptyValue: true,
), ),
InfoTextWidget( InfoTextWidget(
label: "Mobile Number", label: "Mobile Number".addTranslation,
value: _provider.getCurrentUserMobile(_userProvider), value: _provider.getCurrentUserMobile(_userProvider),
showEmptyValue: true, showEmptyValue: true,
), ),
InfoTextWidget( InfoTextWidget(
label: "Extension Number", label: "Extension Number".addTranslation,
value: _provider.getCurrentUserExtension(_userProvider), value: _provider.getCurrentUserExtension(_userProvider),
showEmptyValue: true, showEmptyValue: true,
), ),
InfoTextWidget( InfoTextWidget(
label: "Role", label: "Role".addTranslation,
value: _provider.getCurrentUserRole(_userProvider), value: _provider.getCurrentUserRole(_userProvider),
showEmptyValue: true, showEmptyValue: true,
), ),
@ -311,7 +320,7 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
Widget _buildSiteMultiSelect() { Widget _buildSiteMultiSelect() {
return MultipleItemDropDownMenu<Site, SiteProvider>( return MultipleItemDropDownMenu<Site, SiteProvider>(
context: context, context: context,
title: context.translation.bySite, title: context.translation.site,
initialValue: _selectedSites, initialValue: _selectedSites,
showAsBottomSheet: true, showAsBottomSheet: true,
backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white, backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white,
@ -338,7 +347,7 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
Widget _buildDepartmentMultiSelect() { Widget _buildDepartmentMultiSelect() {
return MultipleItemDropDownMenu<Department, DepartmentBySitesProvider>( return MultipleItemDropDownMenu<Department, DepartmentBySitesProvider>(
context: context, context: context,
title: "Departments", title: "Department".addTranslation,
initialValue: _selectedDepartments, initialValue: _selectedDepartments,
showAsBottomSheet: true, showAsBottomSheet: true,
backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white, backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white,
@ -380,16 +389,12 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
builder: (context, siteProvider, child) { builder: (context, siteProvider, child) {
// Get ALL user's current site IDs to exclude from new site selection // Get ALL user's current site IDs to exclude from new site selection
final allUserCurrentSiteIds = _provider.userCurrentSites.map((s) => s.identifier ?? '').toSet(); final allUserCurrentSiteIds = _provider.userCurrentSites.map((s) => s.identifier ?? '').toSet();
// Filter out already selected new sites and ALL user's current sites // Filter out already selected new sites and ALL user's current sites
final alreadySelectedNewSites = _siteReplacements.values.where((r) => r.newSite != null).map((r) => r.newSite!.identifier).toSet(); final alreadySelectedNewSites = _siteReplacements.values.where((r) => r.newSite != null).map((r) => r.newSite!.identifier).toSet();
final filteredSites = siteProvider.items.where((site) { final filteredSites = siteProvider.items.where((site) {
final siteId = site.identifier ?? ''; final siteId = site.identifier ?? '';
// Exclude ALL user's current sites (not just selected old sites) // Exclude ALL user's current sites (not just selected old sites)
if (allUserCurrentSiteIds.contains(siteId)) return false; if (allUserCurrentSiteIds.contains(siteId)) return false;
// Exclude already selected new sites (except current one) // Exclude already selected new sites (except current one)
if (replacement?.newSite?.identifier != siteId && alreadySelectedNewSites.contains(siteId)) { if (replacement?.newSite?.identifier != siteId && alreadySelectedNewSites.contains(siteId)) {
return false; return false;
@ -397,7 +402,6 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
return true; return true;
}).toList(); }).toList();
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -502,6 +506,7 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
// Validation for Change Site request // Validation for Change Site request
if (_isChangeSiteRequest()) { if (_isChangeSiteRequest()) {
if (_selectedOldSites.isEmpty) { if (_selectedOldSites.isEmpty) {
"Please select at least one site".showToast;
return; return;
} }
@ -555,7 +560,7 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
final request = SiteRequestModel( final request = SiteRequestModel(
requestType: _selectedRequestType!.identifier?.toString() ?? '', requestType: _selectedRequestType!.identifier?.toString() ?? '',
employeeId: _provider.getCurrentUserEmployeeId(_userProvider), employeeId: _provider.getCurrentUserUserId(_userProvider),
fullName: _provider.getCurrentUserFullName(_userProvider), fullName: _provider.getCurrentUserFullName(_userProvider),
emailAddress: _provider.getCurrentUserEmail(_userProvider), emailAddress: _provider.getCurrentUserEmail(_userProvider),
mobileNumber: _provider.getCurrentUserMobile(_userProvider), mobileNumber: _provider.getCurrentUserMobile(_userProvider),
@ -582,8 +587,12 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
}); });
// API will handle success/error toast messages // API will handle success/error toast messages
if (success && mounted) { if (success && mounted) {
Navigator.pushReplacementNamed(context, SiteRequestHistoryScreen.routeName); UserProvider userProvider = Provider.of<UserProvider>(context, listen: false);
await _provider.fetchSiteRequests(pageNumber: 1, pageSize: 10, userProvider: userProvider);
Navigator.pop(context);
// Navigator.pushReplacementNamed(context, SiteRequestHistoryScreen.routeName);
} }
} else { } else {
// For Add Site and Remove Site request types // For Add Site and Remove Site request types
@ -605,7 +614,7 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
final request = SiteRequestModel( final request = SiteRequestModel(
requestType: _selectedRequestType!.identifier?.toString() ?? '', requestType: _selectedRequestType!.identifier?.toString() ?? '',
employeeId: _provider.getCurrentUserEmployeeId(_userProvider), employeeId: _provider.getCurrentUserUserId(_userProvider),
fullName: _provider.getCurrentUserFullName(_userProvider), fullName: _provider.getCurrentUserFullName(_userProvider),
emailAddress: _provider.getCurrentUserEmail(_userProvider), emailAddress: _provider.getCurrentUserEmail(_userProvider),
mobileNumber: _provider.getCurrentUserMobile(_userProvider), mobileNumber: _provider.getCurrentUserMobile(_userProvider),

@ -41,13 +41,18 @@ class AppFilledButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return AnimatedContainer(
duration: const Duration(milliseconds: 250),
height: height.toScreenHeight, height: height.toScreenHeight,
width: maxWidth ? double.infinity : width, width: maxWidth ? double.infinity : width,
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
color: disableButton ? context.isDark ?AppColor.neutral20 :AppColor.neutral140 : (buttonColor ?? AppColor.primary10), color: disableButton
? context.isDark
? AppColor.neutral20
: AppColor.neutral140
: (buttonColor ?? AppColor.primary10),
border: showBorder ? Border.all(color: textColor ?? AppColor.background(context)) : null, border: showBorder ? Border.all(color: textColor ?? AppColor.background(context)) : null,
), ),
child: loading child: loading

@ -12,12 +12,13 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
final String? title; final String? title;
final List<Widget>? actions; final List<Widget>? actions;
final Function? onBackPress; final Function? onBackPress;
final Color? backgroundColor;
final bool showHomeActionButton; final bool showHomeActionButton;
final bool showBackButton; final bool showBackButton;
final VoidCallback? onWillPopScope; final VoidCallback? onWillPopScope;
final TextStyle? titleStyle; final TextStyle? titleStyle;
const DefaultAppBar({this.title, this.onBackPress, this.onWillPopScope, this.actions, this.titleStyle, this.showHomeActionButton = false, this.showBackButton = true, Key? key}) : super(key: key); const DefaultAppBar({this.title, this.onBackPress, this.onWillPopScope, this.actions,this.backgroundColor, this.titleStyle, this.showHomeActionButton = false, this.showBackButton = true, Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -41,6 +42,7 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
return AppBar( return AppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
titleSpacing: 16, titleSpacing: 16,
backgroundColor:backgroundColor,
title: Row( title: Row(
children: [ children: [
if (showBackButton) if (showBackButton)

@ -9,8 +9,10 @@ import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/general_response_model.dart'; import 'package:test_sa/models/new_models/general_response_model.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.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/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/forget_password_module/reset_password_view.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'; import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
@ -78,12 +80,18 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
String otpMethodValue = widget.data['typeSend'] == "SMS" ? widget.data['phoneNumber']["phoneNumber"] : widget.data["phoneNumber"]['email']; String otpMethodValue = widget.data['typeSend'] == "SMS" ? widget.data['phoneNumber']["phoneNumber"] : widget.data["phoneNumber"]['email'];
return Scaffold( return Scaffold(
appBar: const DefaultAppBar(
title: '',
backgroundColor: Colors.transparent,
),
body: Column( body: Column(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [ children: [
Text(context.translation.otpVerification, style: AppTextStyles.heading2.copyWith(color: AppColor.headingTextColor(context), fontWeight: FontWeight.w500)), Text(context.translation.otpVerification, style: AppTextStyles.heading2.copyWith(color: AppColor.headingTextColor(context), fontWeight: FontWeight.w500)),
8.height, 8.height,
@ -139,13 +147,17 @@ class _ForgetPasswordVerifyOtpViewState extends State<ForgetPasswordVerifyOtpVie
], ],
), ),
).center.expanded, ).center.expanded,
AppFilledButton( FooterActionButton.footerContainer(
safeAreaTop: false,
context: context,
child: AppFilledButton(
label: context.translation.verify, label: context.translation.verify,
maxWidth: true, maxWidth: true,
onPressed: verifyOtp, onPressed: verifyOtp,
), ),
),
], ],
).paddingOnly(start: 20, end: 20, bottom: 16), ),
); );
} }

@ -7,9 +7,11 @@ import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/general_response_model.dart'; import 'package:test_sa/models/new_models/general_response_model.dart';
import 'package:test_sa/models/new_models/update_password.dart'; import 'package:test_sa/models/new_models/update_password.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.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/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/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/pages/login_page.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_header_widget.dart';
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
@ -40,9 +42,14 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
return Form( return Form(
key: _formKey, key: _formKey,
child: Scaffold( child: Scaffold(
appBar: const DefaultAppBar(
title: '',
backgroundColor: Colors.transparent,
),
body: Column( body: Column(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -57,6 +64,10 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField, validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField,
labelText: context.translation.password, labelText: context.translation.password,
obscureText: !_passwordVisible, obscureText: !_passwordVisible,
onChange: (value) {
newPassword = value;
setState(() {});
},
suffixIcon: Icon( suffixIcon: Icon(
// Based on passwordVisible state choose the icon // Based on passwordVisible state choose the icon
_passwordVisible ? Icons.visibility : Icons.visibility_off, _passwordVisible ? Icons.visibility : Icons.visibility_off,
@ -67,9 +78,10 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
_passwordVisible = !_passwordVisible; _passwordVisible = !_passwordVisible;
}); });
}), }),
onSaved: (value) { // onSaved: (value) {
newPassword = value; //
}, // newPassword = value;
// },
), ),
16.height, 16.height,
AppTextFormField( AppTextFormField(
@ -77,36 +89,99 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
labelText: context.translation.confirmPassword, labelText: context.translation.confirmPassword,
obscureText: !_confirmPasswordVisible, obscureText: !_confirmPasswordVisible,
showBorder: true, showBorder: true,
validator: (value) => Validator.isValidPassword(value!) onChange: (value) {
? null
: value.isEmpty
? context.translation.requiredField
: context.translation.passwordLengthMessage,
onSaved: (value) {
confirmPassword = value; confirmPassword = value;
setState(() {});
}, },
// validator: (value) => Validator.isValidPassword(value!)
// ? null
// : value.isEmpty
// ? context.translation.requiredField
// : context.translation.passwordLengthMessage,
// onSaved: (value) {
// confirmPassword = value;
// },
suffixIcon: Icon(_confirmPasswordVisible ? Icons.visibility : Icons.visibility_off, color: AppColor.icon2Color(context)).paddingOnly(end: 12).onPress(() { suffixIcon: Icon(_confirmPasswordVisible ? Icons.visibility : Icons.visibility_off, color: AppColor.icon2Color(context)).paddingOnly(end: 12).onPress(() {
setState(() { setState(() {
_confirmPasswordVisible = !_confirmPasswordVisible; _confirmPasswordVisible = !_confirmPasswordVisible;
}); });
}), }),
), ),
12.height,
passwordConstraintsUI('At least one upper case', checkRegEx(r'[A-Z]')),
8.height,
passwordConstraintsUI('At least one special character', checkRegEx(r'[^\w\s]')),
8.height,
passwordConstraintsUI('At least one numeric', checkRegEx(r'[0-9]')),
8.height,
passwordConstraintsUI('Minimum 8 characters', newPassword.length >= 8),
8.height,
passwordConstraintsUI('Confirm password must match', newPassword.isNotEmpty && newPassword == confirmPassword),
], ],
), ),
).center.expanded, ).center.expanded,
AppFilledButton(label: context.translation.resetPassword, maxWidth: true, onPressed: () => _resetPassword(context)), FooterActionButton.footerContainer(
safeAreaTop: false,
context: context,
child: AppFilledButton(label: context.translation.resetPassword, disableButton: !isPasswordCompliant(newPassword, 8), maxWidth: true, onPressed: () => _resetPassword(context))),
], ],
).paddingOnly(start: 16, end: 16, bottom: 24, top: 24), ),
), ),
); );
} }
bool checkRegEx(String pattern) {
return RegExp(pattern).hasMatch(newPassword);
}
bool isPasswordCompliant(String? password, int minLength) {
if (password == null || password.isEmpty) {
return false;
}
bool hasUppercase = password.contains(RegExp(r'[A-Z]'));
bool hasDigits = password.contains(RegExp(r'[0-9]'));
bool hasSpecialCharacter = password.contains(RegExp(r'[^\w\s]'));
// bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'));
bool hasMinLength = password.length >= minLength;
bool isMatched = password == confirmPassword;
return hasDigits && hasUppercase && hasMinLength && isMatched && hasSpecialCharacter;
}
Widget passwordConstraintsUI(String description, bool check) {
return Row(
children: [
4.width,
SizedBox(
width: 12,
height: 12,
// activeColor: AppColor.primary10,
// checkColor: AppColor.white10,
child: Checkbox(
fillColor: MaterialStateProperty.all(AppColor.primary10),
side: BorderSide(color: AppColor.icon2Color(context).withValues(alpha: .3), width: 1.0),
checkColor: AppColor.white10,
value: check,
onChanged: null,
activeColor: AppColor.blueStatus(context),
// side: BorderSide(color: AppColor.loadingColor(context), width: 1.0),
visualDensity: const VisualDensity(horizontal: -4.0, vertical: -4.0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
),
12.width,
InfoTextLabelWidget(label: description),
],
);
}
Future<void> _resetPassword(BuildContext context) async { Future<void> _resetPassword(BuildContext context) async {
if (!_formKey.currentState!.validate()) return; // if (!_formKey.currentState!.validate()) return;
_formKey.currentState?.save(); // _formKey.currentState?.save();
if (newPassword != confirmPassword) { // if (newPassword != confirmPassword) {
Fluttertoast.showToast(msg: 'Password not matched try again'); // Fluttertoast.showToast(msg: 'Password not matched try again');
} else { // } else {
UserProvider userProvider = Provider.of<UserProvider>(context, listen: false); UserProvider userProvider = Provider.of<UserProvider>(context, listen: false);
UpdatePasswordModel updatePasswordModel = UpdatePasswordModel updatePasswordModel =
UpdatePasswordModel(password: newPassword, confirmPassword: confirmPassword, userId: userProvider.verifyOtpModel.userId, token: userProvider.verifyOtpModel.token); UpdatePasswordModel(password: newPassword, confirmPassword: confirmPassword, userId: userProvider.verifyOtpModel.userId, token: userProvider.verifyOtpModel.token);
@ -116,6 +191,6 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
confirmPassword = ''; confirmPassword = '';
Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true); Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
} }
} // }
} }
} }

@ -16,7 +16,7 @@ import 'package:test_sa/models/new_models/general_response_model.dart';
import 'package:test_sa/modules/cx_module/chat/chat_page.dart'; import 'package:test_sa/modules/cx_module/chat/chat_page.dart';
import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/modules/cx_module/survey/survey_page.dart';
import 'package:test_sa/modules/signup/screens/signup_screen.dart'; import 'package:test_sa/modules/signup/screens/signup_screen.dart';
import 'package:test_sa/modules/applicationDemo/screens/demo_request_form_screen.dart'; import 'package:test_sa/modules/applicationDemo/screens/application_demo_request_form_screen.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; 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/forget_password_module/forget_passwod_verify_otp.dart';
import 'package:test_sa/new_views/pages/land_page/land_page.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart';

Loading…
Cancel
Save