From cdc695360557087f5c91a1873ea5f8cf841a8457 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:39:31 +0300 Subject: [PATCH] improvements --- lib/controllers/api_routes/urls.dart | 4 +- .../application_demo_request_provider.dart | 45 ++++---- .../signup/models/department_model.dart | 2 +- .../signup/models/signup_request_model.dart | 16 +-- .../providers/signup_department_provider.dart | 70 +++++++++++- lib/modules/signup/screens/signup_screen.dart | 108 +++++++++++++----- 6 files changed, 180 insertions(+), 65 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 5fde2d74..0f67db7d 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -61,6 +61,7 @@ class URLs { static get signUpGetCompaniesByAssetGroup => "$_baseUrl/Company/GetCompaniesByAssetGroup"; static get signUpGetSiteList => "$_baseUrl/Customer/GetSiteList"; static get signUpGetDepartmentAutoComplete => "$_baseUrl/Department/GetDepartmentAutoCompleteByAssetGroup"; + static get signUpGetDepartmentsBySitesAndAssetGroup => "$_baseUrl/Department/GetDepartmentsBySitesAndAssetGroup"; // Site Request APIs static get getSiteRequestTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=4016"; // get site request types @@ -586,7 +587,8 @@ class URLs { static get getDemoRequests => "$_baseUrl/DemoRequest/GetDemoRequests"; // get demo request history // Application Demo Request APIs - static get getApplicationDemoRoles => "$_baseUrl/Account/GetRolesByAssetGroupId?assetGroupId=6"; // get roles for application demo request + // static get getApplicationDemoRoles => "$_baseUrl/Account/GetRolesByAssetGroupId?assetGroupId=6"; // get roles for application demo request + static get getApplicationDemoRoles => "$_baseUrl/RoleDemo/GetDemoRolesAutoComplete"; // get roles for application demo request static get submitApplicationDemoRequest => "$_baseUrl/DemoUser/CreateDemoUser"; // post submit application demo request// get application demo request history static get sendDemoUserOtp => "$_baseUrl/DemoUser/EmailVerification"; // post send OTP to user static get verifyDemoUserOtp => "$_baseUrl/DemoUser/VerifyOtp"; // post verify OTP diff --git a/lib/modules/applicationDemo/providers/application_demo_request_provider.dart b/lib/modules/applicationDemo/providers/application_demo_request_provider.dart index 19ed3842..7eb00961 100644 --- a/lib/modules/applicationDemo/providers/application_demo_request_provider.dart +++ b/lib/modules/applicationDemo/providers/application_demo_request_provider.dart @@ -1,11 +1,11 @@ +import 'dart:developer'; import 'package:flutter/material.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/modules/applicationDemo/models/application_demo_request_model.dart'; import 'package:test_sa/modules/applicationDemo/models/role_model.dart'; import 'dart:convert'; -import 'package:http/http.dart' as http; -/// Provider for managing application demo request operations class ApplicationDemoRequestProvider extends ChangeNotifier { bool _loading = false; bool _roleLoading = false; @@ -13,7 +13,6 @@ class ApplicationDemoRequestProvider extends ChangeNotifier { String? _errorMessage; String? _successMessage; - // Getters bool get loading => _loading; bool get roleLoading => _roleLoading; @@ -24,7 +23,6 @@ class ApplicationDemoRequestProvider extends ChangeNotifier { List get roles => _roles; - // Setter set loading(bool value) { _loading = value; notifyListeners(); @@ -35,29 +33,30 @@ class ApplicationDemoRequestProvider extends ChangeNotifier { notifyListeners(); } - /// Get headers without authentication token for public APIs Map get _unauthenticatedHeaders => { 'Content-Type': 'application/json', 'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first, }; - /// Fetches available roles from the server (without authentication) - Future fetchRoles() async { + Future fetchRoles({String? searchText}) async { if (roleLoading) return -2; - roleLoading = true; _errorMessage = null; notifyListeners(); try { - final response = await http.get( - Uri.parse(URLs.getApplicationDemoRoles), - headers: _unauthenticatedHeaders, - ); + final response = await ApiManager.instance.post(URLs.getApplicationDemoRoles, headers: _unauthenticatedHeaders, body: {'searchText': searchText ?? ''}); if (response.statusCode >= 200 && response.statusCode < 300) { - final List responseData = jsonDecode(response.body); - _roles = responseData.map((json) => ApplicationDemoRoleModel.fromJson(json)).toList(); + final Map responseData = jsonDecode(response.body); + List rolesList = []; + if (responseData.containsKey('data')) { + rolesList = responseData['data'] is List ? responseData['data'] : []; + } else if (responseData.containsKey('roles')) { + rolesList = responseData['roles'] is List ? responseData['roles'] : []; + } + + _roles = rolesList.map((json) => ApplicationDemoRoleModel.fromJson(json)).toList(); roleLoading = false; notifyListeners(); @@ -87,10 +86,10 @@ class ApplicationDemoRequestProvider extends ChangeNotifier { try { final requestBody = request.toJson(); - final response = await http.post( - Uri.parse(URLs.submitApplicationDemoRequest), + final response = await ApiManager.instance.post( + URLs.submitApplicationDemoRequest, headers: _unauthenticatedHeaders, - body: json.encode(requestBody), + body: requestBody, ); if (response.statusCode >= 200 && response.statusCode < 300) { @@ -134,10 +133,10 @@ class ApplicationDemoRequestProvider extends ChangeNotifier { 'typeSend': typeSend, }; - final response = await http.post( - Uri.parse(URLs.sendDemoUserOtp), + final response = await ApiManager.instance.post( + URLs.sendDemoUserOtp, headers: _unauthenticatedHeaders, - body: json.encode(requestBody), + body: requestBody, ); if (response.statusCode >= 200 && response.statusCode < 300) { @@ -185,10 +184,10 @@ class ApplicationDemoRequestProvider extends ChangeNotifier { requestBody['phoneNumber'] = phoneNumber; } - final response = await http.post( - Uri.parse(URLs.verifyDemoUserOtp), + final response = await ApiManager.instance.post( + URLs.verifyDemoUserOtp, headers: _unauthenticatedHeaders, - body: json.encode(requestBody), + body: requestBody, ); if (response.statusCode >= 200 && response.statusCode < 300) { diff --git a/lib/modules/signup/models/department_model.dart b/lib/modules/signup/models/department_model.dart index 148c6f9f..2fc094c6 100644 --- a/lib/modules/signup/models/department_model.dart +++ b/lib/modules/signup/models/department_model.dart @@ -18,7 +18,7 @@ class DepartmentModel extends Base { factory DepartmentModel.fromJson(Map json) { return DepartmentModel( id: json['id'], - departmentName: json['departmentName'], + departmentName: json['departmentName']??json['name'], departmentCode: json['departmentCode'], ntCode: json['ntCode'], operationalHours: json['operationalHours'], diff --git a/lib/modules/signup/models/signup_request_model.dart b/lib/modules/signup/models/signup_request_model.dart index 88bd954d..cfc73a28 100644 --- a/lib/modules/signup/models/signup_request_model.dart +++ b/lib/modules/signup/models/signup_request_model.dart @@ -6,9 +6,9 @@ class SignUpRequestModel { final String? emailAddress; final String? mobileNumber; final String? extensionNumber; - final int? siteId; + final List? siteIds; final String? erpSite; - final int? departmentId; + final List? departmentIds; final String? erpDepartment; final String? role; final bool isFromERP; @@ -21,9 +21,9 @@ class SignUpRequestModel { this.emailAddress, this.mobileNumber, this.extensionNumber, - this.siteId, + this.siteIds, this.erpSite, - this.departmentId, + this.departmentIds, this.erpDepartment, this.role, required this.isFromERP, @@ -32,19 +32,15 @@ class SignUpRequestModel { Map toJson() { return { 'assetGroupId': assetGroupId ?? 0, - 'companyId': companyId ?? 0, 'employeeId': employeeId ?? '', 'fullName': fullName ?? '', 'emailAddress': emailAddress ?? '', 'mobileNumber': mobileNumber ?? '', 'extensionNumber': extensionNumber ?? '', - if(siteId!=null) - 'siteId': siteId, - // 'siteId': siteId ?? 0, + 'siteIds': siteIds, 'erpSite': erpSite ?? '', - if(departmentId!=null) - 'departmentId': departmentId, + 'departmentIds': departmentIds, 'erpDepartment': erpDepartment ?? '', 'role': role ?? '', 'isFromERP': isFromERP, diff --git a/lib/modules/signup/providers/signup_department_provider.dart b/lib/modules/signup/providers/signup_department_provider.dart index cc35912b..9e56f45f 100644 --- a/lib/modules/signup/providers/signup_department_provider.dart +++ b/lib/modules/signup/providers/signup_department_provider.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:developer'; import 'package:http/http.dart' as http; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/modules/signup/models/department_model.dart'; import 'package:test_sa/providers/loading_list_notifier.dart'; @@ -28,8 +29,9 @@ class SignupDepartmentProvider extends LoadingListNotifier { 'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first, }; - final response = await http.get( - Uri.parse('${URLs.signUpGetDepartmentAutoComplete}?assetGroupId=$id'), + final response = await ApiManager.instance.get( + '${URLs.signUpGetDepartmentAutoComplete}?assetGroupId=$id', + // Uri.parse('${URLs.signUpGetDepartmentAutoComplete}?assetGroupId=$id'), headers: headers, ); @@ -71,4 +73,68 @@ class SignupDepartmentProvider extends LoadingListNotifier { return -1; } } + + /// Fetches departments based on selected sites and asset group + Future getDepartmentsBySites({ + required List siteIds, + required int assetGroupId, + }) async { + log('Fetching departments for sites: $siteIds and asset group: $assetGroupId'); + + if (loading) return -2; + + if (siteIds.isEmpty) { + log('Department fetch: Site IDs are empty, clearing items'); + items = []; + notifyListeners(); + return -1; + } + + loading = true; + notifyListeners(); + + try { + final headers = { + 'Content-Type': 'application/json', + 'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first, + }; + + final body = { + 'siteIds': siteIds, + 'assetGroupId': assetGroupId, + }; + + final response = await ApiManager.instance.post( + URLs.signUpGetDepartmentsBySitesAndAssetGroup, + headers: headers, + body: body, + ); + + stateCode = response.statusCode; + + if (response.statusCode >= 200 && response.statusCode < 300) { + final data = json.decode(response.body); + if (data is Map && data['data'] != null && data['data'] is List) { + items = (data['data'] as List).map((item) => DepartmentModel.fromJson(item)).toList(); + } else if (data is List) { + items = data.map((item) => DepartmentModel.fromJson(item)).toList(); + } else { + items = []; + } + } else { + items = []; + } + + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + log('Department by sites API error: $error'); + loading = false; + stateCode = -1; + items = []; + notifyListeners(); + return -1; + } + } } diff --git a/lib/modules/signup/screens/signup_screen.dart b/lib/modules/signup/screens/signup_screen.dart index 1c41e343..f1cb495a 100644 --- a/lib/modules/signup/screens/signup_screen.dart +++ b/lib/modules/signup/screens/signup_screen.dart @@ -27,6 +27,7 @@ import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.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/common_widgets/multiple_item_drop_down_menu.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/new_views/swipe_module/dialoge/single_btn_dialog.dart'; import 'package:test_sa/views/widgets/dialogs/dialog.dart'; @@ -62,8 +63,8 @@ class _SignUpScreenState extends State { // Selected values AssetGroup? _selectedAssetGroup; Company? _selectedCompany; - SiteModel? _selectedSite; - DepartmentModel? _selectedDepartment; + List _selectedSite=[]; + List _selectedDepartment=[]; EmployeeERPModel? _employeeERPData; // Store the ERP employee data bool _isHMGGroup = false; bool _employeeFetched = false; @@ -352,43 +353,92 @@ class _SignUpScreenState extends State { } Widget _buildSiteDropdown() { - return SingleItemDropDownMenu( + + return MultipleItemDropDownMenu( context: context, title: "Site", initialValue: _selectedSite, - showAsFullScreenDialog: true, requestById: _selectedAssetGroup?.id, - onSelect: (value) { + // staticData: provider.roles, + // loading: provider.roleLoading, + showAsFullScreenDialog: true, + onSelect: (selectedSites) { setState(() { - _selectedSite = value; + _selectedSite = selectedSites ?? []; + // Clear departments when sites change + _selectedDepartment = []; + // _rolesValidationError = null; // Clear error when roles are selected }); - // No need to fetch departments when site changes - they are independent - }, - validator: (value) { - if (value == null) return "Site is required"; - return null; + + // Fetch departments based on selected sites + if (_selectedSite.isNotEmpty && _selectedAssetGroup?.id != null) { + final siteIds = _selectedSite.map((site) => site.id ?? 0).where((id) => id != 0).toList(); + if (siteIds.isNotEmpty) { + _departmentProvider.getDepartmentsBySites( + siteIds: siteIds, + assetGroupId: _selectedAssetGroup!.id!, + ); + } + } else { + // If no sites selected, clear departments + _departmentProvider.items = []; + _departmentProvider.notifyListeners(); + } }, ); + // return SingleItemDropDownMenu( + // context: context, + // title: "Site", + // initialValue: _selectedSite, + // showAsFullScreenDialog: true, + // requestById: _selectedAssetGroup?.id, + // onSelect: (value) { + // setState(() { + // _selectedSite = value; + // }); + // // No need to fetch departments when site changes - they are independent + // }, + // validator: (value) { + // if (value == null) return "Site is required"; + // return null; + // }, + // ); } Widget _buildDepartmentDropdown() { - return SingleItemDropDownMenu( + + return MultipleItemDropDownMenu( context: context, title: "Department", initialValue: _selectedDepartment, - showAsFullScreenDialog: true, - // showAsBottomSheet: true, requestById: _selectedAssetGroup?.id, - onSelect: (value) { + // staticData: provider.roles, + // loading: provider.roleLoading, + showAsFullScreenDialog: true, + onSelect: (selectedDepartments) { setState(() { - _selectedDepartment = value; + _selectedDepartment = selectedDepartments ?? []; + // _rolesValidationError = null; // Clear error when roles are selected }); }, - validator: (value) { - if (value == null) return "Department is required"; - return null; - }, ); + // return SingleItemDropDownMenu( + // context: context, + // title: "Department", + // initialValue: _selectedDepartment, + // showAsFullScreenDialog: true, + // // showAsBottomSheet: true, + // requestById: _selectedAssetGroup?.id, + // onSelect: (value) { + // setState(() { + // _selectedDepartment = value; + // }); + // }, + // validator: (value) { + // if (value == null) return "Department is required"; + // return null; + // }, + // ); } Widget _buildRoleField() { @@ -482,8 +532,8 @@ class _SignUpScreenState extends State { _mobileController.clear(); _extensionController.clear(); _roleController.clear(); - _selectedSite = null; - _selectedDepartment = null; + _selectedSite = []; + _selectedDepartment = []; _employeeFetched = false; _employeeERPData = null; } @@ -520,13 +570,13 @@ class _SignUpScreenState extends State { } // Site is mandatory for HMG - if (_selectedSite == null) { + if (_selectedSite.isEmpty) { Fluttertoast.showToast(msg: "Site is required"); return; } // // // Department is mandatory for HMG - if (_selectedDepartment == null) { + if (_selectedDepartment.isEmpty) { Fluttertoast.showToast(msg: "Department is required"); return; } @@ -560,13 +610,13 @@ class _SignUpScreenState extends State { } // Site is mandatory for Non-HMG - if (_selectedSite == null) { + if (_selectedSite.isEmpty) { Fluttertoast.showToast(msg: "Site is required"); return; } // Department is mandatory for Non-HMG - if (_selectedDepartment == null) { + if (_selectedDepartment.isEmpty) { Fluttertoast.showToast(msg: "Department is required"); return; } @@ -620,9 +670,11 @@ class _SignUpScreenState extends State { mobileNumber: _mobileController.text, extensionNumber: _extensionController.text.isEmpty ? null : _extensionController.text, // For HMG: send both selected IDs and ERP data - siteId: _selectedSite?.id, + // siteId: _selectedSite?.id, + siteIds: _selectedSite.map((site) => site.id??0).toList(), // erpSite: _isHMGGroup ? _employeeERPData?.branchCode : null, - departmentId: _selectedDepartment?.id, + departmentIds: _selectedDepartment.map((department) => department.id??0).toList(), + // departmentIds: _selectedDepartment?.id, // erpDepartment: _isHMGGroup ? _employeeERPData?.branchName : null, role: _roleController.text, isFromERP: _isHMGGroup,