diff --git a/lib/modules/signup/screens/signup_screen.dart b/lib/modules/signup/screens/signup_screen.dart index 330ca3a4..4d0d379b 100644 --- a/lib/modules/signup/screens/signup_screen.dart +++ b/lib/modules/signup/screens/signup_screen.dart @@ -3,6 +3,7 @@ import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/validator/validator.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/widget_extensions.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; @@ -62,6 +63,9 @@ class _SignUpScreenState extends State { bool _employeeFetched = false; bool _isSubmitting = false; + // Autovalidate mode - enables validation on user interaction after first submit attempt + AutovalidateMode _autovalidateMode = AutovalidateMode.disabled; + @override void initState() { super.initState(); @@ -100,6 +104,7 @@ class _SignUpScreenState extends State { padding: EdgeInsets.all(16.toScreenWidth), child: Form( key: _formKey, + autovalidateMode: _autovalidateMode, // Set autovalidate mode child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -135,7 +140,7 @@ class _SignUpScreenState extends State { Widget _buildAssetGroupDropdown() { return SingleItemDropDownMenu( context: context, - title: "Asset Group", + title: "Group".addTranslation, initialValue: _selectedAssetGroup, showAsFullScreenDialog: true, showAsBottomSheet: false, @@ -154,7 +159,7 @@ class _SignUpScreenState extends State { } }, validator: (value) { - if (value == null) return "Asset Group is required"; + if (value == null) return "Group is required"; return null; }, ); @@ -240,15 +245,8 @@ class _SignUpScreenState extends State { controller: _employeeIdController, labelText: "Employee ID", textInputType: TextInputType.number, - onChange: (value) { - // Clear validation errors on user interaction - // if (_formKey.currentState != null) { - // _formKey.currentState!.validate(); - // } - }, validator: (value) { if (_employeeIdController.text.isEmpty) return "Employee ID is required"; - // if (!Validator.isNumeric(_employeeIdController.text)) return "Employee ID must be numeric"; return null; }, ), @@ -487,6 +485,10 @@ class _SignUpScreenState extends State { Future _submitForm() async { // Validate form fields if (!_formKey.currentState!.validate()) { + // Enable autovalidation after first submit attempt + setState(() { + _autovalidateMode = AutovalidateMode.onUserInteraction; + }); Fluttertoast.showToast(msg: "Please fill all required fields"); return; } diff --git a/lib/modules/site_request_module/providers/site_request_provider.dart b/lib/modules/site_request_module/providers/site_request_provider.dart index d9ed2b68..a717822e 100644 --- a/lib/modules/site_request_module/providers/site_request_provider.dart +++ b/lib/modules/site_request_module/providers/site_request_provider.dart @@ -40,19 +40,32 @@ class SiteRequestProvider extends ChangeNotifier { // Getters bool get loading => _loading; + bool get isLoadingMore => _isLoadingMore; + String? get errorMessage => _errorMessage; + int get currentPage => _currentPage; + bool get hasMoreData => _hasMoreData; + List get requestTypes => _requestTypes; + List get userCurrentSites => _userCurrentSites; + List get requestHistory => _requestHistory; // 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 getCurrentUserEmail(UserProvider userProvider) => userProvider.user?.email ?? ''; + String getCurrentUserMobile(UserProvider userProvider) => userProvider.user?.phoneNumber ?? ''; + String getCurrentUserExtension(UserProvider userProvider) => userProvider.user?.extensionNo ?? ''; String getCurrentUserRole(UserProvider userProvider) { @@ -63,6 +76,7 @@ class SiteRequestProvider extends ChangeNotifier { } List getCurrentUserAssignedSites(UserProvider userProvider) => []; + bool hasAssignedSites(List assignedSites) => assignedSites.isNotEmpty; // Setter @@ -118,8 +132,7 @@ class SiteRequestProvider extends ChangeNotifier { notifyListeners(); try { - final isChangeSiteRequest = _requestTypes.any((type) => - type.identifier == request.requestType && (type.name?.toLowerCase().contains('change') ?? false)); + final isChangeSiteRequest = _requestTypes.any((type) => type.identifier == request.requestType && (type.name?.toLowerCase().contains('change') ?? false)); final requestBody = _buildRequestBody(request, userProvider, isChangeSiteRequest); @@ -164,7 +177,7 @@ class SiteRequestProvider extends ChangeNotifier { body: { "pageSize": size, "pageNumber": page, - "userId": getCurrentUserEmployeeId(userProvider), + "userId": getCurrentUserUserId(userProvider), }, ); @@ -245,16 +258,8 @@ class SiteRequestProvider extends ChangeNotifier { "id": 0, "siteId": int.tryParse(request.siteIds[index]) ?? 0, "siteName": request.siteNames[index], - "oldSiteId": (isChangeSiteRequest && - request.oldSiteIds != null && - index < request.oldSiteIds!.length) - ? int.tryParse(request.oldSiteIds![index]) ?? 0 - : 0, - "oldSitName": (isChangeSiteRequest && - request.oldSiteNames != null && - index < request.oldSiteNames!.length) - ? request.oldSiteNames![index] - : "" + "oldSiteId": (isChangeSiteRequest && request.oldSiteIds != null && index < request.oldSiteIds!.length) ? int.tryParse(request.oldSiteIds![index]) ?? 0 : 0, + "oldSitName": (isChangeSiteRequest && request.oldSiteNames != null && index < request.oldSiteNames!.length) ? request.oldSiteNames![index] : "" }; }).toList(); @@ -270,7 +275,7 @@ class SiteRequestProvider extends ChangeNotifier { return { "id": 0, - "userId": getCurrentUserEmployeeId(userProvider), + "userId": getCurrentUserUserId(userProvider), "requestTypeId": int.tryParse(request.requestType) ?? 0, "siteIds": siteIdsArray, "departmentIds": departmentIdsArray, @@ -322,9 +327,7 @@ class SiteRequestProvider extends ChangeNotifier { final data = json.decode(response.body); if (data['isSuccess'] == true) { - final siteRequests = (data['data'] as List?) - ?.map((item) => SiteRequestModel.fromJson(item)) - .toList() ?? []; + final siteRequests = (data['data'] as List?)?.map((item) => SiteRequestModel.fromJson(item)).toList() ?? []; if (loadMore) { _requestHistory.addAll(siteRequests); diff --git a/lib/modules/site_request_module/screens/site_request_form_screen.dart b/lib/modules/site_request_module/screens/site_request_form_screen.dart index 2da589b0..1dde072a 100644 --- a/lib/modules/site_request_module/screens/site_request_form_screen.dart +++ b/lib/modules/site_request_module/screens/site_request_form_screen.dart @@ -1,9 +1,12 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/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/context_extension.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/site.dart'; @@ -159,7 +162,7 @@ class _SiteRequestFormScreenState extends State { Widget _buildRequestTypeDropdown() { return SingleItemDropDownMenu( context: context, - title: "Type of Site Request", + title: "Type of site request".addTranslation, initialValue: _selectedRequestType, staticData: _provider.requestTypes, showAsFullScreenDialog: true, @@ -175,7 +178,7 @@ class _SiteRequestFormScreenState extends State { // Fetch user's current sites if Change Site or Remove Site is selected if ((_isChangeSiteRequest() || _isRemoveSiteRequest()) && value != null) { - final userId = _provider.getCurrentUserEmployeeId(_userProvider); + final userId = _provider.getCurrentUserUserId(_userProvider); await _provider.fetchUserCurrentSites(userId); } @@ -200,28 +203,34 @@ class _SiteRequestFormScreenState extends State { children: [ InfoHeader16Widget("Requester Information"), // 8.height, + // InfoTextWidget( + // label: "Employee ID".addTranslation, + // value: _provider.getCurrentUserEmployeeId(_userProvider), + // showEmptyValue: true, + // ), InfoTextWidget( - label: "Full Name", + label: "Full Name".addTranslation, value: _provider.getCurrentUserFullName(_userProvider), showEmptyValue: true, ), + InfoTextWidget( - label: "Email Address", + label: "Email Address".addTranslation, value: _provider.getCurrentUserEmail(_userProvider), showEmptyValue: true, ), InfoTextWidget( - label: "Mobile Number", + label: "Mobile Number".addTranslation, value: _provider.getCurrentUserMobile(_userProvider), showEmptyValue: true, ), InfoTextWidget( - label: "Extension Number", + label: "Extension Number".addTranslation, value: _provider.getCurrentUserExtension(_userProvider), showEmptyValue: true, ), InfoTextWidget( - label: "Role", + label: "Role".addTranslation, value: _provider.getCurrentUserRole(_userProvider), showEmptyValue: true, ), @@ -311,7 +320,7 @@ class _SiteRequestFormScreenState extends State { Widget _buildSiteMultiSelect() { return MultipleItemDropDownMenu( context: context, - title: context.translation.bySite, + title: context.translation.site, initialValue: _selectedSites, showAsBottomSheet: true, backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white, @@ -338,7 +347,7 @@ class _SiteRequestFormScreenState extends State { Widget _buildDepartmentMultiSelect() { return MultipleItemDropDownMenu( context: context, - title: "Departments", + title: "Department".addTranslation, initialValue: _selectedDepartments, showAsBottomSheet: true, backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white, @@ -380,16 +389,12 @@ class _SiteRequestFormScreenState extends State { builder: (context, siteProvider, child) { // Get ALL user's current site IDs to exclude from new site selection final allUserCurrentSiteIds = _provider.userCurrentSites.map((s) => s.identifier ?? '').toSet(); - // 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 filteredSites = siteProvider.items.where((site) { final siteId = site.identifier ?? ''; - // Exclude ALL user's current sites (not just selected old sites) if (allUserCurrentSiteIds.contains(siteId)) return false; - // Exclude already selected new sites (except current one) if (replacement?.newSite?.identifier != siteId && alreadySelectedNewSites.contains(siteId)) { return false; @@ -397,7 +402,6 @@ class _SiteRequestFormScreenState extends State { return true; }).toList(); - return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -502,6 +506,7 @@ class _SiteRequestFormScreenState extends State { // Validation for Change Site request if (_isChangeSiteRequest()) { if (_selectedOldSites.isEmpty) { + "Please select at least one site".showToast; return; } @@ -555,7 +560,7 @@ class _SiteRequestFormScreenState extends State { final request = SiteRequestModel( requestType: _selectedRequestType!.identifier?.toString() ?? '', - employeeId: _provider.getCurrentUserEmployeeId(_userProvider), + employeeId: _provider.getCurrentUserUserId(_userProvider), fullName: _provider.getCurrentUserFullName(_userProvider), emailAddress: _provider.getCurrentUserEmail(_userProvider), mobileNumber: _provider.getCurrentUserMobile(_userProvider), @@ -582,8 +587,12 @@ class _SiteRequestFormScreenState extends State { }); // API will handle success/error toast messages + if (success && mounted) { - Navigator.pushReplacementNamed(context, SiteRequestHistoryScreen.routeName); + UserProvider userProvider = Provider.of(context, listen: false); + await _provider.fetchSiteRequests(pageNumber: 1, pageSize: 10, userProvider: userProvider); + Navigator.pop(context); + // Navigator.pushReplacementNamed(context, SiteRequestHistoryScreen.routeName); } } else { // For Add Site and Remove Site request types @@ -605,7 +614,7 @@ class _SiteRequestFormScreenState extends State { final request = SiteRequestModel( requestType: _selectedRequestType!.identifier?.toString() ?? '', - employeeId: _provider.getCurrentUserEmployeeId(_userProvider), + employeeId: _provider.getCurrentUserUserId(_userProvider), fullName: _provider.getCurrentUserFullName(_userProvider), emailAddress: _provider.getCurrentUserEmail(_userProvider), mobileNumber: _provider.getCurrentUserMobile(_userProvider),