improvements

export_module_ui_ux_enhancement_signup
WaseemAbbasi22 3 weeks ago
parent 69c09f7bd0
commit cdc6953605

@ -61,6 +61,7 @@ class URLs {
static get signUpGetCompaniesByAssetGroup => "$_baseUrl/Company/GetCompaniesByAssetGroup"; static get signUpGetCompaniesByAssetGroup => "$_baseUrl/Company/GetCompaniesByAssetGroup";
static get signUpGetSiteList => "$_baseUrl/Customer/GetSiteList"; static get signUpGetSiteList => "$_baseUrl/Customer/GetSiteList";
static get signUpGetDepartmentAutoComplete => "$_baseUrl/Department/GetDepartmentAutoCompleteByAssetGroup"; static get signUpGetDepartmentAutoComplete => "$_baseUrl/Department/GetDepartmentAutoCompleteByAssetGroup";
static get signUpGetDepartmentsBySitesAndAssetGroup => "$_baseUrl/Department/GetDepartmentsBySitesAndAssetGroup";
// Site Request APIs // Site Request APIs
static get getSiteRequestTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=4016"; // get site request types 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 static get getDemoRequests => "$_baseUrl/DemoRequest/GetDemoRequests"; // get demo request history
// Application Demo Request APIs // 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 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 sendDemoUserOtp => "$_baseUrl/DemoUser/EmailVerification"; // post send OTP to user
static get verifyDemoUserOtp => "$_baseUrl/DemoUser/VerifyOtp"; // post verify OTP static get verifyDemoUserOtp => "$_baseUrl/DemoUser/VerifyOtp"; // post verify OTP

@ -1,11 +1,11 @@
import 'dart:developer';
import 'package:flutter/material.dart'; 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/controllers/api_routes/urls.dart';
import 'package:test_sa/modules/applicationDemo/models/application_demo_request_model.dart'; import 'package:test_sa/modules/applicationDemo/models/application_demo_request_model.dart';
import 'package:test_sa/modules/applicationDemo/models/role_model.dart'; import 'package:test_sa/modules/applicationDemo/models/role_model.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http;
/// Provider for managing application demo request operations
class ApplicationDemoRequestProvider extends ChangeNotifier { class ApplicationDemoRequestProvider extends ChangeNotifier {
bool _loading = false; bool _loading = false;
bool _roleLoading = false; bool _roleLoading = false;
@ -13,7 +13,6 @@ class ApplicationDemoRequestProvider extends ChangeNotifier {
String? _errorMessage; String? _errorMessage;
String? _successMessage; String? _successMessage;
// Getters
bool get loading => _loading; bool get loading => _loading;
bool get roleLoading => _roleLoading; bool get roleLoading => _roleLoading;
@ -24,7 +23,6 @@ class ApplicationDemoRequestProvider extends ChangeNotifier {
List<ApplicationDemoRoleModel> get roles => _roles; List<ApplicationDemoRoleModel> get roles => _roles;
// Setter
set loading(bool value) { set loading(bool value) {
_loading = value; _loading = value;
notifyListeners(); notifyListeners();
@ -35,29 +33,30 @@ class ApplicationDemoRequestProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
/// Get headers without authentication token for public APIs
Map<String, String> get _unauthenticatedHeaders => { Map<String, String> get _unauthenticatedHeaders => {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first, 'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first,
}; };
/// Fetches available roles from the server (without authentication) Future<int> fetchRoles({String? searchText}) async {
Future<int> fetchRoles() async {
if (roleLoading) return -2; if (roleLoading) return -2;
roleLoading = true; roleLoading = true;
_errorMessage = null; _errorMessage = null;
notifyListeners(); notifyListeners();
try { try {
final response = await http.get( final response = await ApiManager.instance.post(URLs.getApplicationDemoRoles, headers: _unauthenticatedHeaders, body: {'searchText': searchText ?? ''});
Uri.parse(URLs.getApplicationDemoRoles),
headers: _unauthenticatedHeaders,
);
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
final List<dynamic> responseData = jsonDecode(response.body); final Map<String, dynamic> responseData = jsonDecode(response.body);
_roles = responseData.map((json) => ApplicationDemoRoleModel.fromJson(json)).toList(); List<dynamic> 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; roleLoading = false;
notifyListeners(); notifyListeners();
@ -87,10 +86,10 @@ class ApplicationDemoRequestProvider extends ChangeNotifier {
try { try {
final requestBody = request.toJson(); final requestBody = request.toJson();
final response = await http.post( final response = await ApiManager.instance.post(
Uri.parse(URLs.submitApplicationDemoRequest), URLs.submitApplicationDemoRequest,
headers: _unauthenticatedHeaders, headers: _unauthenticatedHeaders,
body: json.encode(requestBody), body: requestBody,
); );
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
@ -134,10 +133,10 @@ class ApplicationDemoRequestProvider extends ChangeNotifier {
'typeSend': typeSend, 'typeSend': typeSend,
}; };
final response = await http.post( final response = await ApiManager.instance.post(
Uri.parse(URLs.sendDemoUserOtp), URLs.sendDemoUserOtp,
headers: _unauthenticatedHeaders, headers: _unauthenticatedHeaders,
body: json.encode(requestBody), body: requestBody,
); );
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
@ -185,10 +184,10 @@ class ApplicationDemoRequestProvider extends ChangeNotifier {
requestBody['phoneNumber'] = phoneNumber; requestBody['phoneNumber'] = phoneNumber;
} }
final response = await http.post( final response = await ApiManager.instance.post(
Uri.parse(URLs.verifyDemoUserOtp), URLs.verifyDemoUserOtp,
headers: _unauthenticatedHeaders, headers: _unauthenticatedHeaders,
body: json.encode(requestBody), body: requestBody,
); );
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {

@ -18,7 +18,7 @@ class DepartmentModel extends Base {
factory DepartmentModel.fromJson(Map<String, dynamic> json) { factory DepartmentModel.fromJson(Map<String, dynamic> json) {
return DepartmentModel( return DepartmentModel(
id: json['id'], id: json['id'],
departmentName: json['departmentName'], departmentName: json['departmentName']??json['name'],
departmentCode: json['departmentCode'], departmentCode: json['departmentCode'],
ntCode: json['ntCode'], ntCode: json['ntCode'],
operationalHours: json['operationalHours'], operationalHours: json['operationalHours'],

@ -6,9 +6,9 @@ class SignUpRequestModel {
final String? emailAddress; final String? emailAddress;
final String? mobileNumber; final String? mobileNumber;
final String? extensionNumber; final String? extensionNumber;
final int? siteId; final List<int>? siteIds;
final String? erpSite; final String? erpSite;
final int? departmentId; final List<int>? departmentIds;
final String? erpDepartment; final String? erpDepartment;
final String? role; final String? role;
final bool isFromERP; final bool isFromERP;
@ -21,9 +21,9 @@ class SignUpRequestModel {
this.emailAddress, this.emailAddress,
this.mobileNumber, this.mobileNumber,
this.extensionNumber, this.extensionNumber,
this.siteId, this.siteIds,
this.erpSite, this.erpSite,
this.departmentId, this.departmentIds,
this.erpDepartment, this.erpDepartment,
this.role, this.role,
required this.isFromERP, required this.isFromERP,
@ -32,19 +32,15 @@ class SignUpRequestModel {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'assetGroupId': assetGroupId ?? 0, 'assetGroupId': assetGroupId ?? 0,
'companyId': companyId ?? 0, 'companyId': companyId ?? 0,
'employeeId': employeeId ?? '', 'employeeId': employeeId ?? '',
'fullName': fullName ?? '', 'fullName': fullName ?? '',
'emailAddress': emailAddress ?? '', 'emailAddress': emailAddress ?? '',
'mobileNumber': mobileNumber ?? '', 'mobileNumber': mobileNumber ?? '',
'extensionNumber': extensionNumber ?? '', 'extensionNumber': extensionNumber ?? '',
if(siteId!=null) 'siteIds': siteIds,
'siteId': siteId,
// 'siteId': siteId ?? 0,
'erpSite': erpSite ?? '', 'erpSite': erpSite ?? '',
if(departmentId!=null) 'departmentIds': departmentIds,
'departmentId': departmentId,
'erpDepartment': erpDepartment ?? '', 'erpDepartment': erpDepartment ?? '',
'role': role ?? '', 'role': role ?? '',
'isFromERP': isFromERP, 'isFromERP': isFromERP,

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:http/http.dart' as http; 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/controllers/api_routes/urls.dart';
import 'package:test_sa/modules/signup/models/department_model.dart'; import 'package:test_sa/modules/signup/models/department_model.dart';
import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/loading_list_notifier.dart';
@ -28,8 +29,9 @@ class SignupDepartmentProvider extends LoadingListNotifier<DepartmentModel> {
'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first, 'X-Timezone-Offset': DateTime.now().timeZoneOffset.toString().split(".").first,
}; };
final response = await http.get( final response = await ApiManager.instance.get(
Uri.parse('${URLs.signUpGetDepartmentAutoComplete}?assetGroupId=$id'), '${URLs.signUpGetDepartmentAutoComplete}?assetGroupId=$id',
// Uri.parse('${URLs.signUpGetDepartmentAutoComplete}?assetGroupId=$id'),
headers: headers, headers: headers,
); );
@ -71,4 +73,68 @@ class SignupDepartmentProvider extends LoadingListNotifier<DepartmentModel> {
return -1; return -1;
} }
} }
/// Fetches departments based on selected sites and asset group
Future<int> getDepartmentsBySites({
required List<int> 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;
}
}
} }

@ -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_lazy_loading.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/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/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/new_views/swipe_module/dialoge/single_btn_dialog.dart';
import 'package:test_sa/views/widgets/dialogs/dialog.dart'; import 'package:test_sa/views/widgets/dialogs/dialog.dart';
@ -62,8 +63,8 @@ class _SignUpScreenState extends State<SignUpScreen> {
// Selected values // Selected values
AssetGroup? _selectedAssetGroup; AssetGroup? _selectedAssetGroup;
Company? _selectedCompany; Company? _selectedCompany;
SiteModel? _selectedSite; List<SiteModel> _selectedSite=[];
DepartmentModel? _selectedDepartment; List<DepartmentModel> _selectedDepartment=[];
EmployeeERPModel? _employeeERPData; // Store the ERP employee data EmployeeERPModel? _employeeERPData; // Store the ERP employee data
bool _isHMGGroup = false; bool _isHMGGroup = false;
bool _employeeFetched = false; bool _employeeFetched = false;
@ -352,43 +353,92 @@ class _SignUpScreenState extends State<SignUpScreen> {
} }
Widget _buildSiteDropdown() { Widget _buildSiteDropdown() {
return SingleItemDropDownMenu<SiteModel, SignupSiteProvider>(
return MultipleItemDropDownMenu<SiteModel, SignupSiteProvider>(
context: context, context: context,
title: "Site", title: "Site",
initialValue: _selectedSite, initialValue: _selectedSite,
showAsFullScreenDialog: true,
requestById: _selectedAssetGroup?.id, requestById: _selectedAssetGroup?.id,
onSelect: (value) { // staticData: provider.roles,
// loading: provider.roleLoading,
showAsFullScreenDialog: true,
onSelect: (selectedSites) {
setState(() { 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
}, // Fetch departments based on selected sites
validator: (value) { if (_selectedSite.isNotEmpty && _selectedAssetGroup?.id != null) {
if (value == null) return "Site is required"; final siteIds = _selectedSite.map((site) => site.id ?? 0).where((id) => id != 0).toList();
return null; if (siteIds.isNotEmpty) {
_departmentProvider.getDepartmentsBySites(
siteIds: siteIds,
assetGroupId: _selectedAssetGroup!.id!,
);
}
} else {
// If no sites selected, clear departments
_departmentProvider.items = [];
_departmentProvider.notifyListeners();
}
}, },
); );
// return SingleItemDropDownMenu<SiteModel, SignupSiteProvider>(
// 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() { Widget _buildDepartmentDropdown() {
return SingleItemDropDownMenu<DepartmentModel, SignupDepartmentProvider>(
return MultipleItemDropDownMenu<DepartmentModel, SignupDepartmentProvider>(
context: context, context: context,
title: "Department", title: "Department",
initialValue: _selectedDepartment, initialValue: _selectedDepartment,
showAsFullScreenDialog: true,
// showAsBottomSheet: true,
requestById: _selectedAssetGroup?.id, requestById: _selectedAssetGroup?.id,
onSelect: (value) { // staticData: provider.roles,
// loading: provider.roleLoading,
showAsFullScreenDialog: true,
onSelect: (selectedDepartments) {
setState(() { 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<DepartmentModel, SignupDepartmentProvider>(
// 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() { Widget _buildRoleField() {
@ -482,8 +532,8 @@ class _SignUpScreenState extends State<SignUpScreen> {
_mobileController.clear(); _mobileController.clear();
_extensionController.clear(); _extensionController.clear();
_roleController.clear(); _roleController.clear();
_selectedSite = null; _selectedSite = [];
_selectedDepartment = null; _selectedDepartment = [];
_employeeFetched = false; _employeeFetched = false;
_employeeERPData = null; _employeeERPData = null;
} }
@ -520,13 +570,13 @@ class _SignUpScreenState extends State<SignUpScreen> {
} }
// Site is mandatory for HMG // Site is mandatory for HMG
if (_selectedSite == null) { if (_selectedSite.isEmpty) {
Fluttertoast.showToast(msg: "Site is required"); Fluttertoast.showToast(msg: "Site is required");
return; return;
} }
// //
// // Department is mandatory for HMG // // Department is mandatory for HMG
if (_selectedDepartment == null) { if (_selectedDepartment.isEmpty) {
Fluttertoast.showToast(msg: "Department is required"); Fluttertoast.showToast(msg: "Department is required");
return; return;
} }
@ -560,13 +610,13 @@ class _SignUpScreenState extends State<SignUpScreen> {
} }
// Site is mandatory for Non-HMG // Site is mandatory for Non-HMG
if (_selectedSite == null) { if (_selectedSite.isEmpty) {
Fluttertoast.showToast(msg: "Site is required"); Fluttertoast.showToast(msg: "Site is required");
return; return;
} }
// Department is mandatory for Non-HMG // Department is mandatory for Non-HMG
if (_selectedDepartment == null) { if (_selectedDepartment.isEmpty) {
Fluttertoast.showToast(msg: "Department is required"); Fluttertoast.showToast(msg: "Department is required");
return; return;
} }
@ -620,9 +670,11 @@ class _SignUpScreenState extends State<SignUpScreen> {
mobileNumber: _mobileController.text, mobileNumber: _mobileController.text,
extensionNumber: _extensionController.text.isEmpty ? null : _extensionController.text, extensionNumber: _extensionController.text.isEmpty ? null : _extensionController.text,
// For HMG: send both selected IDs and ERP data // 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, // erpSite: _isHMGGroup ? _employeeERPData?.branchCode : null,
departmentId: _selectedDepartment?.id, departmentIds: _selectedDepartment.map((department) => department.id??0).toList(),
// departmentIds: _selectedDepartment?.id,
// erpDepartment: _isHMGGroup ? _employeeERPData?.branchName : null, // erpDepartment: _isHMGGroup ? _employeeERPData?.branchName : null,
role: _roleController.text, role: _roleController.text,
isFromERP: _isHMGGroup, isFromERP: _isHMGGroup,

Loading…
Cancel
Save