improvements

export_module_ui_ux_enhancement_signup
WaseemAbbasi22 1 week ago
parent 61472df110
commit 8ad2e79b1e

@ -14,9 +14,11 @@ class SiteRequestModel {
final List<String>? oldSiteNames; // For Change Site request final List<String>? oldSiteNames; // For Change Site request
final List<String>? departmentIds; final List<String>? departmentIds;
final List<String>? departmentNames; final List<String>? departmentNames;
final List<String>? oldDepartmentIds; // For Change Site request - old departments
final List<String>? oldDepartmentNames; // For Change Site request - old departments
final String role; final String role;
final String status; // Pending, Approved, Rejected final String ?status; // Pending, Approved, Rejected
final DateTime requestDate; final DateTime? requestDate;
SiteRequestModel({ SiteRequestModel({
this.id, this.id,
@ -32,9 +34,11 @@ class SiteRequestModel {
this.oldSiteNames, this.oldSiteNames,
this.departmentIds, this.departmentIds,
this.departmentNames, this.departmentNames,
this.oldDepartmentIds,
this.oldDepartmentNames,
required this.role, required this.role,
required this.status, this.status,
required this.requestDate, this.requestDate,
}); });
/// Converts model to JSON for API submission /// Converts model to JSON for API submission
@ -54,8 +58,8 @@ class SiteRequestModel {
'departmentIds': departmentIds, 'departmentIds': departmentIds,
'departmentNames': departmentNames, 'departmentNames': departmentNames,
'role': role, 'role': role,
'status': status, // 'status': status,
'requestDate': requestDate.toIso8601String(), // 'requestDate': requestDate?.toIso8601String(),
}; };
} }
@ -78,6 +82,8 @@ class SiteRequestModel {
oldSiteNames: sitesData['oldSiteNames'], oldSiteNames: sitesData['oldSiteNames'],
departmentIds: departmentsData['departmentIds'], departmentIds: departmentsData['departmentIds'],
departmentNames: departmentsData['departmentNames'], departmentNames: departmentsData['departmentNames'],
oldDepartmentIds: departmentsData['oldDepartmentIds'],
oldDepartmentNames: departmentsData['oldDepartmentNames'],
role: json['role'] ?? '', role: json['role'] ?? '',
status: _parseStatus(json), status: _parseStatus(json),
requestDate: _parseDate(json), requestDate: _parseDate(json),
@ -156,6 +162,8 @@ class SiteRequestModel {
static Map<String, List<String>?> _parseDepartmentsFromJson(Map<String, dynamic> json) { static Map<String, List<String>?> _parseDepartmentsFromJson(Map<String, dynamic> json) {
List<String>? departmentIds; List<String>? departmentIds;
List<String>? departmentNames; List<String>? departmentNames;
List<String>? oldDepartmentIds;
List<String>? oldDepartmentNames;
if (json['departments'] != null && if (json['departments'] != null &&
json['departments'] is List && json['departments'] is List &&
@ -165,12 +173,22 @@ class SiteRequestModel {
for (var dept in json['departments']) { for (var dept in json['departments']) {
departmentIds.add(dept['departmentId']?.toString() ?? ''); departmentIds.add(dept['departmentId']?.toString() ?? '');
departmentNames.add(dept['departmentName'] ?? ''); departmentNames.add(dept['departmentName'] ?? '');
// Check for old department data in Change Site requests
if (dept['oldDepartmentId'] != null && dept['oldDepartmentId'] != 0) {
oldDepartmentIds ??= [];
oldDepartmentNames ??= [];
oldDepartmentIds.add(dept['oldDepartmentId']?.toString() ?? '');
oldDepartmentNames.add(dept['oldDepartmentName'] ?? '');
}
} }
} }
return { return {
'departmentIds': departmentIds, 'departmentIds': departmentIds,
'departmentNames': departmentNames, 'departmentNames': departmentNames,
'oldDepartmentIds': oldDepartmentIds,
'oldDepartmentNames': oldDepartmentNames,
}; };
} }

@ -99,7 +99,9 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
return Scaffold( return Scaffold(
backgroundColor: AppColor.scaffoldBackground(context), backgroundColor: AppColor.scaffoldBackground(context),
appBar: const DefaultAppBar(title: "Site Request"), appBar: const DefaultAppBar(title: "Site Request"),
body: _isLoadingData ?const ALoading().center:Column( body: _isLoadingData
? const ALoading().center
: Column(
children: [ children: [
Expanded( Expanded(
child: Form( child: Form(
@ -242,11 +244,13 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
Widget _buildOldSiteDropdown() { Widget _buildOldSiteDropdown() {
return MultipleItemDropDownMenu<SiteRequestSiteModel, NullableLoadingProvider>( return MultipleItemDropDownMenu<SiteRequestSiteModel, NullableLoadingProvider>(
context: context, context: context,
title: "Old Site (Current Site)", title: "Current Sites",
initialValue: _selectedOldSites.map((s) => SiteRequestSiteModel( initialValue: _selectedOldSites
.map((s) => SiteRequestSiteModel(
id: s.identifier ?? '', id: s.identifier ?? '',
name: s.name ?? '', name: s.name ?? '',
)).toList(), ))
.toList(),
staticData: _provider.userCurrentSites, staticData: _provider.userCurrentSites,
showAsBottomSheet: true, showAsBottomSheet: true,
backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white, backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white,
@ -288,10 +292,12 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
return MultipleItemDropDownMenu<SiteRequestSiteModel, NullableLoadingProvider>( return MultipleItemDropDownMenu<SiteRequestSiteModel, NullableLoadingProvider>(
context: context, context: context,
title: "Site to Remove", title: "Site to Remove",
initialValue: _selectedSites.map((s) => SiteRequestSiteModel( initialValue: _selectedSites
.map((s) => SiteRequestSiteModel(
id: s.identifier ?? '', id: s.identifier ?? '',
name: s.name ?? '', name: s.name ?? '',
)).toList(), ))
.toList(),
staticData: _provider.userCurrentSites, staticData: _provider.userCurrentSites,
showAsBottomSheet: true, showAsBottomSheet: true,
backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white, backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white,
@ -384,20 +390,29 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
return Consumer<SiteProvider>( return Consumer<SiteProvider>(
builder: (context, siteProvider, child) { builder: (context, siteProvider, child) {
// Filter out already selected new sites and the current old site // 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 final alreadySelectedNewSites = _siteReplacements.values
.where((r) => r.newSite != null) .where((r) => r.newSite != null)
.map((r) => r.newSite!.identifier) .map((r) => r.newSite!.identifier)
.toSet(); .toSet();
final filteredSites = siteProvider.items.where((site) { final filteredSites = siteProvider.items.where((site) {
// Exclude the old site itself final siteId = site.identifier ?? '';
if (site.identifier == oldSiteId) return false;
// 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) // Exclude already selected new sites (except current one)
if (replacement?.newSite?.identifier != site.identifier && if (replacement?.newSite?.identifier != siteId &&
alreadySelectedNewSites.contains(site.identifier)) { alreadySelectedNewSites.contains(siteId)) {
return false; return false;
} }
return true; return true;
}).toList(); }).toList();
@ -599,8 +614,8 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
departmentIds: departmentIds.isNotEmpty ? departmentIds : null, departmentIds: departmentIds.isNotEmpty ? departmentIds : null,
departmentNames: departmentNames.isNotEmpty ? departmentNames : null, departmentNames: departmentNames.isNotEmpty ? departmentNames : null,
role: _provider.getCurrentUserRole(_userProvider), role: _provider.getCurrentUserRole(_userProvider),
status: 'Pending', // status: 'Pending',
requestDate: DateTime.now(), // requestDate: DateTime.now(),
); );
final success = await _provider.submitSiteRequest(request, _userProvider); final success = await _provider.submitSiteRequest(request, _userProvider);
@ -647,8 +662,8 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
departmentIds: _selectedDepartments.isNotEmpty ? _selectedDepartments.map((d) => d.identifier ?? '').toList() : null, departmentIds: _selectedDepartments.isNotEmpty ? _selectedDepartments.map((d) => d.identifier ?? '').toList() : null,
departmentNames: _selectedDepartments.isNotEmpty ? _selectedDepartments.map((d) => d.name ?? '').toList() : null, departmentNames: _selectedDepartments.isNotEmpty ? _selectedDepartments.map((d) => d.name ?? '').toList() : null,
role: _provider.getCurrentUserRole(_userProvider), role: _provider.getCurrentUserRole(_userProvider),
status: 'Pending', // status: 'Pending',
requestDate: DateTime.now(), // requestDate: DateTime.now(),
); );
final success = await _provider.submitSiteRequest(request, _userProvider); final success = await _provider.submitSiteRequest(request, _userProvider);
@ -663,7 +678,9 @@ 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);
} }
} }
} }

@ -67,7 +67,13 @@ class _SiteRequestHistoryScreenState extends State<SiteRequestHistoryScreen> {
} }
Future<void> _refreshData() async { Future<void> _refreshData() async {
setState(() {
_isLoadingData = true;
});
await _provider.refreshSiteRequests(userProvider: _userProvider); await _provider.refreshSiteRequests(userProvider: _userProvider);
if (mounted) {
setState(() => _isLoadingData = false);
}
} }
@override @override
@ -149,21 +155,42 @@ class _SiteRequestHistoryScreenState extends State<SiteRequestHistoryScreen> {
_buildRequestHeader(request), _buildRequestHeader(request),
InfoHeaderWidget("Site Request #${request.id ?? 'N/A'}"), InfoHeaderWidget("Site Request #${request.id ?? 'N/A'}"),
_buildUserInfo(request), _buildUserInfo(request),
// Show old sites if present (for Change Site requests)
if (request.oldSiteNames != null && request.oldSiteNames!.isNotEmpty)
_buildOldSitesSection(request),
// Show new/current sites only if they are not empty and not all null
if (_hasValidSiteNames(request.siteNames))
_buildSitesSection(request), _buildSitesSection(request),
if (request.departmentNames != null && request.departmentNames!.isNotEmpty) // Show old departments if present (for Change Site requests)
if (request.oldDepartmentNames != null && request.oldDepartmentNames!.isNotEmpty)
_buildOldDepartmentsSection(request),
// Show new departments only if they are not empty and not all null
if (_hasValidDepartmentNames(request.departmentNames))
_buildDepartmentsSection(request), _buildDepartmentsSection(request),
], ],
).toShadowContainer(context).paddingOnly(bottom: 16); ).toShadowContainer(context).paddingOnly(bottom: 16);
} }
// Helper method to check if site names list has valid (non-null, non-empty) values
bool _hasValidSiteNames(List<String> siteNames) {
return siteNames.isNotEmpty && siteNames.any((name) => name.isNotEmpty);
}
// Helper method to check if department names list has valid (non-null, non-empty) values
bool _hasValidDepartmentNames(List<String>? departmentNames) {
return departmentNames != null &&
departmentNames.isNotEmpty &&
departmentNames.any((name) => name.isNotEmpty);
}
Widget _buildRequestHeader(SiteRequestModel request) { Widget _buildRequestHeader(SiteRequestModel request) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
StatusLabel( StatusLabel(
label: request.status, label: request.status,
textColor: _getStatusTextColor(request.status), textColor: _getStatusTextColor(request.status ?? ''),
backgroundColor: _getStatusColor(request.status), backgroundColor: _getStatusColor(request.status ?? ''),
), ),
8.width, 8.width,
StatusLabel( StatusLabel(
@ -185,19 +212,70 @@ class _SiteRequestHistoryScreenState extends State<SiteRequestHistoryScreen> {
InfoTextWidget(label: "Employee ID", value: request.employeeId), InfoTextWidget(label: "Employee ID", value: request.employeeId),
InfoTextWidget(label: "Email", value: request.emailAddress), InfoTextWidget(label: "Email", value: request.emailAddress),
InfoTextWidget(label: "Mobile", value: request.mobileNumber, showEmptyValue: true), InfoTextWidget(label: "Mobile", value: request.mobileNumber, showEmptyValue: true),
if (request.extensionNumber != null && request.extensionNumber!.isNotEmpty) if (request.extensionNumber != null && request.extensionNumber!.isNotEmpty) InfoTextWidget(label: "Extension", value: request.extensionNumber!, showEmptyValue: true),
InfoTextWidget(label: "Extension", value: request.extensionNumber!, showEmptyValue: true),
InfoTextWidget(label: "Role", value: request.role), InfoTextWidget(label: "Role", value: request.role),
], ],
); );
} }
Widget _buildOldSitesSection(SiteRequestModel request) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Old Sites:",
style: TextStyle(
fontSize: 14,
color: AppColor.labelTextStyleColor(context),
fontWeight: FontWeight.w500,
),
),
8.height,
Wrap(
runSpacing: 4.toScreenHeight,
spacing: 4.toScreenWidth,
children: request.oldSiteNames!.map((site) => _buildChip(site, isOld: true)).toList(),
),
],
).paddingOnly(bottom: 8);
}
Widget _buildSitesSection(SiteRequestModel request) { Widget _buildSitesSection(SiteRequestModel request) {
// Determine label based on whether old sites exist
final label = (request.oldSiteNames != null && request.oldSiteNames!.isNotEmpty)
? "New Sites:"
: "Sites:";
// Filter out null or empty site names
final validSiteNames = request.siteNames.where((site) => site.isNotEmpty).toList();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 14,
color: AppColor.labelTextStyleColor(context),
fontWeight: FontWeight.w500,
),
),
8.height,
Wrap(
runSpacing: 4.toScreenHeight,
spacing: 4.toScreenWidth,
children: validSiteNames.map((site) => _buildChip(site)).toList(),
),
],
).paddingOnly(bottom: 8);
}
Widget _buildOldDepartmentsSection(SiteRequestModel request) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Sites:", "Old Departments:",
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
color: AppColor.labelTextStyleColor(context), color: AppColor.labelTextStyleColor(context),
@ -208,18 +286,26 @@ class _SiteRequestHistoryScreenState extends State<SiteRequestHistoryScreen> {
Wrap( Wrap(
runSpacing: 4.toScreenHeight, runSpacing: 4.toScreenHeight,
spacing: 4.toScreenWidth, spacing: 4.toScreenWidth,
children: request.siteNames.map((site) => _buildChip(site)).toList(), children: request.oldDepartmentNames!.map((dept) => _buildChip(dept, isOld: true)).toList(),
), ),
], ],
).paddingOnly(bottom: 8); ).paddingOnly(bottom: 8);
} }
Widget _buildDepartmentsSection(SiteRequestModel request) { Widget _buildDepartmentsSection(SiteRequestModel request) {
// Determine label based on whether old departments exist
final label = (request.oldDepartmentNames != null && request.oldDepartmentNames!.isNotEmpty)
? "New Departments:"
: "Departments:";
// Filter out null or empty department names
final validDepartmentNames = request.departmentNames!.where((dept) => dept.isNotEmpty).toList();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Departments:", label,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
color: AppColor.labelTextStyleColor(context), color: AppColor.labelTextStyleColor(context),
@ -230,20 +316,28 @@ class _SiteRequestHistoryScreenState extends State<SiteRequestHistoryScreen> {
Wrap( Wrap(
runSpacing: 4.toScreenHeight, runSpacing: 4.toScreenHeight,
spacing: 4.toScreenWidth, spacing: 4.toScreenWidth,
children: request.departmentNames!.map((dept) => _buildChip(dept)).toList(), children: validDepartmentNames.map((dept) => _buildChip(dept)).toList(),
), ),
], ],
); );
} }
Widget _buildChip(String label) { Widget _buildChip(String label, {bool isOld = false}) {
return Chip( return Chip(
backgroundColor: AppColor.backgroundTabBarColor(context), backgroundColor: isOld
side: BorderSide(color: AppColor.border2Color(context)), ? AppColor.redStatusColor.withValues(alpha: 0.1)
: AppColor.backgroundTabBarColor(context),
side: BorderSide(
color: isOld
? AppColor.redStatusColor.withValues(alpha: 0.3)
: AppColor.border2Color(context),
),
label: Text(label), label: Text(label),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
labelStyle: AppTextStyles.tinyFont2.copyWith( labelStyle: AppTextStyles.tinyFont2.copyWith(
color: AppColor.labelTextStyleColor(context), color: isOld
? AppColor.redStatusTextColor
: AppColor.labelTextStyleColor(context),
), ),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
padding: EdgeInsets.symmetric(horizontal: 8.toScreenWidth, vertical: 4.toScreenHeight), padding: EdgeInsets.symmetric(horizontal: 8.toScreenWidth, vertical: 4.toScreenHeight),

Loading…
Cancel
Save