|
|
|
|
@ -1,5 +1,3 @@
|
|
|
|
|
import 'dart:developer';
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:fluttertoast/fluttertoast.dart';
|
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
@ -13,18 +11,19 @@ import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
|
|
|
|
|
import 'package:test_sa/providers/department_by_sites_provider.dart';
|
|
|
|
|
import 'package:test_sa/modules/site_request_module/models/request_type_model.dart';
|
|
|
|
|
import 'package:test_sa/modules/site_request_module/models/site_request_model.dart';
|
|
|
|
|
import 'package:test_sa/modules/site_request_module/models/dropdown_models.dart';
|
|
|
|
|
import 'package:test_sa/modules/site_request_module/providers/site_request_provider.dart';
|
|
|
|
|
import 'package:test_sa/modules/site_request_module/screens/site_request_history_screen.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_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/single_item_drop_down_menu.dart';
|
|
|
|
|
import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart';
|
|
|
|
|
import 'package:test_sa/providers/loading_list_notifier.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/loaders/app_loading.dart';
|
|
|
|
|
|
|
|
|
|
class SiteRequestFormScreen extends StatefulWidget {
|
|
|
|
|
static const String routeName = "/site_request_form";
|
|
|
|
|
@ -43,8 +42,15 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
|
|
|
|
|
RequestTypeModel? _selectedRequestType;
|
|
|
|
|
List<Site> _selectedSites = [];
|
|
|
|
|
List<Site> _selectedOldSites = []; // For Change Site - old sites
|
|
|
|
|
List<Department> _selectedDepartments = [];
|
|
|
|
|
|
|
|
|
|
// Map to track replacements: oldSiteId -> {newSite, departments}
|
|
|
|
|
Map<String, SiteReplacement> _siteReplacements = {};
|
|
|
|
|
|
|
|
|
|
// Track which site IDs have already loaded departments to prevent infinite API calls
|
|
|
|
|
Set<int> _loadedDepartmentSiteIds = {};
|
|
|
|
|
|
|
|
|
|
bool _isSubmitting = false;
|
|
|
|
|
bool _isLoadingData = true;
|
|
|
|
|
|
|
|
|
|
@ -58,6 +64,7 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
// Load data after first frame to access context
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
|
|
|
_provider = Provider.of<SiteRequestProvider>(context, listen: false);
|
|
|
|
|
_userProvider = Provider.of<UserProvider>(context, listen: false);
|
|
|
|
|
|
|
|
|
|
// Initialize department provider with empty state
|
|
|
|
|
final departmentProvider = Provider.of<DepartmentBySitesProvider>(context, listen: false);
|
|
|
|
|
@ -76,26 +83,23 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _isChangeSiteRequest() {
|
|
|
|
|
return _selectedRequestType?.name?.toLowerCase().contains('change') ?? false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _isRemoveSiteRequest() {
|
|
|
|
|
return _selectedRequestType?.name?.toLowerCase().contains('remove') ?? false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
_provider = Provider.of<SiteRequestProvider>(context);
|
|
|
|
|
_userProvider = Provider.of<UserProvider>(context);
|
|
|
|
|
|
|
|
|
|
// Show loading indicator while fetching initial data
|
|
|
|
|
if (_isLoadingData) {
|
|
|
|
|
return Scaffold(
|
|
|
|
|
backgroundColor: AppColor.scaffoldBackground(context),
|
|
|
|
|
appBar: const DefaultAppBar(title: "Site Request"),
|
|
|
|
|
body: const Center(
|
|
|
|
|
child: AppLazyLoading(),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Scaffold(
|
|
|
|
|
backgroundColor: AppColor.scaffoldBackground(context),
|
|
|
|
|
appBar: const DefaultAppBar(title: "Site Request"),
|
|
|
|
|
body: Column(
|
|
|
|
|
body: _isLoadingData ?const ALoading().center:Column(
|
|
|
|
|
children: [
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Form(
|
|
|
|
|
@ -110,9 +114,29 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
_buildRequestTypeDropdown(),
|
|
|
|
|
16.height,
|
|
|
|
|
if (_selectedRequestType != null) ...[
|
|
|
|
|
_buildSiteMultiSelect(),
|
|
|
|
|
16.height,
|
|
|
|
|
_buildDepartmentMultiSelect(),
|
|
|
|
|
if (_isChangeSiteRequest()) ...[
|
|
|
|
|
_buildOldSiteDropdown(),
|
|
|
|
|
16.height,
|
|
|
|
|
// Show replacement containers for each old site
|
|
|
|
|
if (_selectedOldSites.isNotEmpty) ...[
|
|
|
|
|
Text(
|
|
|
|
|
"Site Replacements",
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
|
color: AppColor.textStyleColor(context),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
8.height,
|
|
|
|
|
..._buildSiteReplacementContainers(),
|
|
|
|
|
],
|
|
|
|
|
] else if (_isRemoveSiteRequest()) ...[
|
|
|
|
|
_buildRemoveSiteDropdown(),
|
|
|
|
|
] else ...[
|
|
|
|
|
_buildSiteMultiSelect(),
|
|
|
|
|
16.height,
|
|
|
|
|
_buildDepartmentMultiSelect(),
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
@ -149,12 +173,29 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
staticData: _provider.requestTypes,
|
|
|
|
|
showAsFullScreenDialog: false,
|
|
|
|
|
showAsBottomSheet: true,
|
|
|
|
|
onSelect: (value) {
|
|
|
|
|
onSelect: (value) async {
|
|
|
|
|
setState(() {
|
|
|
|
|
_selectedRequestType = value;
|
|
|
|
|
_selectedSites.clear();
|
|
|
|
|
_selectedOldSites.clear();
|
|
|
|
|
_selectedDepartments.clear();
|
|
|
|
|
_siteReplacements.clear();
|
|
|
|
|
_loadedDepartmentSiteIds.clear(); // Reset loaded department site IDs
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Fetch user's current sites if Change Site or Remove Site is selected
|
|
|
|
|
if ((_isChangeSiteRequest() || _isRemoveSiteRequest()) && value != null) {
|
|
|
|
|
final userId = _provider.getCurrentUserEmployeeId(_userProvider);
|
|
|
|
|
await _provider.fetchUserCurrentSites(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fetch all sites if Change Site is selected (needed for new site dropdown)
|
|
|
|
|
if (_isChangeSiteRequest() && value != null) {
|
|
|
|
|
final siteProvider = Provider.of<SiteProvider>(context, listen: false);
|
|
|
|
|
if (siteProvider.items.isEmpty) {
|
|
|
|
|
await siteProvider.getData();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
validator: (value) {
|
|
|
|
|
if (value == null) return "Please select request type";
|
|
|
|
|
@ -198,34 +239,78 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
).toShadowContainer(context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildInfoRow(String label, String value, {bool isLast = false}) {
|
|
|
|
|
return Padding(
|
|
|
|
|
padding: EdgeInsets.only(bottom: isLast ? 0 : 12.toScreenHeight),
|
|
|
|
|
child: Row(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: 130.toScreenWidth,
|
|
|
|
|
child: Text(
|
|
|
|
|
"$label:",
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
color: AppColor.labelTextStyleColor(context),
|
|
|
|
|
fontWeight: FontWeight.w500,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Text(
|
|
|
|
|
value.isEmpty ? "-" : value,
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
color: AppColor.textStyleColor(context),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
Widget _buildOldSiteDropdown() {
|
|
|
|
|
return MultipleItemDropDownMenu<SiteRequestSiteModel, NullableLoadingProvider>(
|
|
|
|
|
context: context,
|
|
|
|
|
title: "Old Site (Current Site)",
|
|
|
|
|
initialValue: _selectedOldSites.map((s) => SiteRequestSiteModel(
|
|
|
|
|
id: s.identifier ?? '',
|
|
|
|
|
name: s.name ?? '',
|
|
|
|
|
)).toList(),
|
|
|
|
|
staticData: _provider.userCurrentSites,
|
|
|
|
|
showAsBottomSheet: true,
|
|
|
|
|
backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white,
|
|
|
|
|
showShadow: true,
|
|
|
|
|
height: 56.toScreenHeight,
|
|
|
|
|
showCancel: true,
|
|
|
|
|
onSelect: (value) {
|
|
|
|
|
if (value != null) {
|
|
|
|
|
setState(() {
|
|
|
|
|
_selectedOldSites = value.map((s) {
|
|
|
|
|
final site = Site(
|
|
|
|
|
id: int.tryParse(s.identifier ?? '0'),
|
|
|
|
|
custName: s.name,
|
|
|
|
|
);
|
|
|
|
|
return site;
|
|
|
|
|
}).toList();
|
|
|
|
|
|
|
|
|
|
// Remove replacements for sites that are no longer selected
|
|
|
|
|
final newSiteIds = _selectedOldSites.map((s) => s.identifier ?? '').toSet();
|
|
|
|
|
_siteReplacements.removeWhere((key, value) => !newSiteIds.contains(key));
|
|
|
|
|
|
|
|
|
|
// Initialize replacements for newly added sites
|
|
|
|
|
for (var site in _selectedOldSites) {
|
|
|
|
|
final siteId = site.identifier ?? '';
|
|
|
|
|
if (!_siteReplacements.containsKey(siteId)) {
|
|
|
|
|
_siteReplacements[siteId] = SiteReplacement(
|
|
|
|
|
newSite: null,
|
|
|
|
|
departments: [],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildRemoveSiteDropdown() {
|
|
|
|
|
return MultipleItemDropDownMenu<SiteRequestSiteModel, NullableLoadingProvider>(
|
|
|
|
|
context: context,
|
|
|
|
|
title: "Site to Remove",
|
|
|
|
|
initialValue: _selectedSites.map((s) => SiteRequestSiteModel(
|
|
|
|
|
id: s.identifier ?? '',
|
|
|
|
|
name: s.name ?? '',
|
|
|
|
|
)).toList(),
|
|
|
|
|
staticData: _provider.userCurrentSites,
|
|
|
|
|
showAsBottomSheet: true,
|
|
|
|
|
backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white,
|
|
|
|
|
showShadow: true,
|
|
|
|
|
height: 56.toScreenHeight,
|
|
|
|
|
showCancel: true,
|
|
|
|
|
onSelect: (value) {
|
|
|
|
|
if (value != null) {
|
|
|
|
|
setState(() {
|
|
|
|
|
_selectedSites = value.map((s) {
|
|
|
|
|
final site = Site(
|
|
|
|
|
id: int.tryParse(s.identifier ?? '0'),
|
|
|
|
|
custName: s.name,
|
|
|
|
|
);
|
|
|
|
|
return site;
|
|
|
|
|
}).toList();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -257,10 +342,6 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildDepartmentMultiSelect() {
|
|
|
|
|
// Enable department field only when sites are selected
|
|
|
|
|
final isDepartmentEnabled = _selectedSites.isNotEmpty;
|
|
|
|
|
log('Selected Sites: ${_selectedSites.length}, isDepartmentEnabled: $isDepartmentEnabled');
|
|
|
|
|
|
|
|
|
|
return MultipleItemDropDownMenu<Department, DepartmentBySitesProvider>(
|
|
|
|
|
context: context,
|
|
|
|
|
title: "Departments",
|
|
|
|
|
@ -270,8 +351,8 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
showShadow: true,
|
|
|
|
|
height: 56.toScreenHeight,
|
|
|
|
|
showCancel: true,
|
|
|
|
|
enabled: isDepartmentEnabled, // Enable only when sites are selected
|
|
|
|
|
loading: !isDepartmentEnabled ? false : null, // Don't show loading when disabled
|
|
|
|
|
enabled: _selectedSites.isNotEmpty,
|
|
|
|
|
loading: _selectedSites.isEmpty ? false : null,
|
|
|
|
|
onSelect: (value) {
|
|
|
|
|
if (value != null) {
|
|
|
|
|
setState(() {
|
|
|
|
|
@ -296,70 +377,304 @@ class _SiteRequestFormScreenState extends State<SiteRequestFormScreen> {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<Widget> _buildSiteReplacementContainers() {
|
|
|
|
|
return _selectedOldSites.map((oldSite) {
|
|
|
|
|
final oldSiteId = oldSite.identifier ?? '';
|
|
|
|
|
final replacement = _siteReplacements[oldSiteId];
|
|
|
|
|
|
|
|
|
|
return Consumer<SiteProvider>(
|
|
|
|
|
builder: (context, siteProvider, child) {
|
|
|
|
|
// Filter out already selected new sites and the current old site
|
|
|
|
|
final alreadySelectedNewSites = _siteReplacements.values
|
|
|
|
|
.where((r) => r.newSite != null)
|
|
|
|
|
.map((r) => r.newSite!.identifier)
|
|
|
|
|
.toSet();
|
|
|
|
|
|
|
|
|
|
final filteredSites = siteProvider.items.where((site) {
|
|
|
|
|
// Exclude the old site itself
|
|
|
|
|
if (site.identifier == oldSiteId) return false;
|
|
|
|
|
// Exclude already selected new sites (except current one)
|
|
|
|
|
if (replacement?.newSite?.identifier != site.identifier &&
|
|
|
|
|
alreadySelectedNewSites.contains(site.identifier)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}).toList();
|
|
|
|
|
|
|
|
|
|
return Container(
|
|
|
|
|
padding: EdgeInsets.all(16.toScreenWidth),
|
|
|
|
|
margin: EdgeInsets.only(bottom: 16.toScreenHeight),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: AppColor.background(context),
|
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
|
border: Border.all(
|
|
|
|
|
color: AppColor.neutral40.withValues(alpha: 0.3),
|
|
|
|
|
width: 1,
|
|
|
|
|
),
|
|
|
|
|
boxShadow: [
|
|
|
|
|
BoxShadow(
|
|
|
|
|
color: Colors.black.withValues(alpha: 0.05),
|
|
|
|
|
blurRadius: 8,
|
|
|
|
|
offset: const Offset(0, 2),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
// Old site name display (simple text only)
|
|
|
|
|
Text(
|
|
|
|
|
oldSite.name ?? 'Unknown Site',
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
|
color: AppColor.textStyleColor(context),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
16.height,
|
|
|
|
|
|
|
|
|
|
// New site single selection
|
|
|
|
|
SingleItemDropDownMenu<Site, NullableLoadingProvider>(
|
|
|
|
|
context: context,
|
|
|
|
|
title: "New Site",
|
|
|
|
|
initialValue: replacement?.newSite,
|
|
|
|
|
staticData: filteredSites,
|
|
|
|
|
showAsBottomSheet: true,
|
|
|
|
|
backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white,
|
|
|
|
|
showShadow: true,
|
|
|
|
|
height: 56.toScreenHeight,
|
|
|
|
|
onSelect: (value) {
|
|
|
|
|
setState(() {
|
|
|
|
|
if (value != null) {
|
|
|
|
|
// Remove old site ID from loaded set to allow fetching new departments
|
|
|
|
|
if (replacement?.newSite != null) {
|
|
|
|
|
final oldNewSiteId = int.tryParse(replacement!.newSite!.identifier ?? '0') ?? 0;
|
|
|
|
|
_loadedDepartmentSiteIds.remove(oldNewSiteId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_siteReplacements[oldSiteId] = SiteReplacement(
|
|
|
|
|
newSite: value,
|
|
|
|
|
departments: [], // Clear departments when new site changes
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
16.height,
|
|
|
|
|
|
|
|
|
|
// Department multi-select based on new site
|
|
|
|
|
if (replacement?.newSite != null) ...[
|
|
|
|
|
_buildDepartmentDropdownForSite(oldSiteId, replacement!.newSite!),
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}).toList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildDepartmentDropdownForSite(String oldSiteId, Site newSite) {
|
|
|
|
|
final replacement = _siteReplacements[oldSiteId];
|
|
|
|
|
final siteId = int.tryParse(newSite.identifier ?? '0') ?? 0;
|
|
|
|
|
|
|
|
|
|
return Consumer<DepartmentBySitesProvider>(
|
|
|
|
|
builder: (context, departmentProvider, child) {
|
|
|
|
|
// Only fetch departments if we haven't loaded them for this site yet
|
|
|
|
|
if (siteId > 0 && !_loadedDepartmentSiteIds.contains(siteId)) {
|
|
|
|
|
// Mark this site as loaded to prevent infinite calls
|
|
|
|
|
_loadedDepartmentSiteIds.add(siteId);
|
|
|
|
|
|
|
|
|
|
// Fetch departments in post frame callback
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
|
|
if (mounted) {
|
|
|
|
|
departmentProvider.setSiteIds([siteId]);
|
|
|
|
|
departmentProvider.getData();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return MultipleItemDropDownMenu<Department, NullableLoadingProvider>(
|
|
|
|
|
context: context,
|
|
|
|
|
title: "Departments",
|
|
|
|
|
initialValue: replacement?.departments ?? [],
|
|
|
|
|
staticData: departmentProvider.items,
|
|
|
|
|
showAsBottomSheet: true,
|
|
|
|
|
backgroundColor: context.isDark ? AppColor.neutral60 : Colors.white,
|
|
|
|
|
showShadow: true,
|
|
|
|
|
height: 56.toScreenHeight,
|
|
|
|
|
showCancel: true,
|
|
|
|
|
loading: departmentProvider.loading,
|
|
|
|
|
onSelect: (value) {
|
|
|
|
|
setState(() {
|
|
|
|
|
if (value != null && replacement != null) {
|
|
|
|
|
_siteReplacements[oldSiteId] = SiteReplacement(
|
|
|
|
|
newSite: replacement.newSite,
|
|
|
|
|
departments: value,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _submitForm() async {
|
|
|
|
|
// Client-side validation only (no toast messages)
|
|
|
|
|
if (!_formKey.currentState!.validate()) {
|
|
|
|
|
Fluttertoast.showToast(msg: "Please fill all required fields");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_selectedRequestType == null) {
|
|
|
|
|
Fluttertoast.showToast(msg: "Please select request type");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_selectedSites.isEmpty) {
|
|
|
|
|
Fluttertoast.showToast(msg: "Please select at least one site");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Validation for Change Site request
|
|
|
|
|
if (_isChangeSiteRequest()) {
|
|
|
|
|
if (_selectedOldSites.isEmpty) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
|
_isSubmitting = true;
|
|
|
|
|
});
|
|
|
|
|
// Validate that each old site has a new site selected
|
|
|
|
|
for (var oldSite in _selectedOldSites) {
|
|
|
|
|
final oldSiteId = oldSite.identifier ?? '';
|
|
|
|
|
final replacement = _siteReplacements[oldSiteId];
|
|
|
|
|
if (replacement == null || replacement.newSite == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mounted) {
|
|
|
|
|
showDialog(
|
|
|
|
|
context: context,
|
|
|
|
|
barrierDismissible: false,
|
|
|
|
|
builder: (context) => const AppLazyLoading(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// Build the payload from replacements
|
|
|
|
|
final newSiteIds = <String>[];
|
|
|
|
|
final newSiteNames = <String>[];
|
|
|
|
|
final oldSiteIds = <String>[];
|
|
|
|
|
final oldSiteNames = <String>[];
|
|
|
|
|
final departmentIds = <String>[];
|
|
|
|
|
final departmentNames = <String>[];
|
|
|
|
|
|
|
|
|
|
for (var oldSite in _selectedOldSites) {
|
|
|
|
|
final oldSiteId = oldSite.identifier ?? '';
|
|
|
|
|
final replacement = _siteReplacements[oldSiteId]!;
|
|
|
|
|
|
|
|
|
|
// Add old site info
|
|
|
|
|
oldSiteIds.add(oldSiteId);
|
|
|
|
|
oldSiteNames.add(oldSite.name ?? '');
|
|
|
|
|
|
|
|
|
|
// Add new site info
|
|
|
|
|
newSiteIds.add(replacement.newSite!.identifier ?? '');
|
|
|
|
|
newSiteNames.add(replacement.newSite!.name ?? '');
|
|
|
|
|
|
|
|
|
|
// Add departments for this replacement
|
|
|
|
|
for (var dept in replacement.departments) {
|
|
|
|
|
departmentIds.add(dept.identifier ?? '');
|
|
|
|
|
departmentNames.add(dept.name ?? '');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final request = SiteRequestModel(
|
|
|
|
|
requestType: _selectedRequestType!.identifier?.toString() ?? '',
|
|
|
|
|
// Use value instead of id
|
|
|
|
|
employeeId: _provider.getCurrentUserEmployeeId(_userProvider),
|
|
|
|
|
fullName: _provider.getCurrentUserFullName(_userProvider),
|
|
|
|
|
emailAddress: _provider.getCurrentUserEmail(_userProvider),
|
|
|
|
|
mobileNumber: _provider.getCurrentUserMobile(_userProvider),
|
|
|
|
|
extensionNumber: _provider.getCurrentUserExtension(_userProvider),
|
|
|
|
|
siteIds: _selectedSites.map((s) => s.identifier ?? '').toList(),
|
|
|
|
|
siteNames: _selectedSites.map((s) => s.name ?? '').toList(),
|
|
|
|
|
departmentIds: _selectedDepartments.isNotEmpty ? _selectedDepartments.map((d) => d.identifier ?? '').toList() : null,
|
|
|
|
|
departmentNames: _selectedDepartments.isNotEmpty ? _selectedDepartments.map((d) => d.name ?? '').toList() : null,
|
|
|
|
|
role: _provider.getCurrentUserRole(_userProvider),
|
|
|
|
|
status: 'Pending',
|
|
|
|
|
requestDate: DateTime.now(),
|
|
|
|
|
);
|
|
|
|
|
setState(() {
|
|
|
|
|
_isSubmitting = true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
final success = await _provider.submitSiteRequest(request, _userProvider);
|
|
|
|
|
if (mounted) {
|
|
|
|
|
showDialog(
|
|
|
|
|
context: context,
|
|
|
|
|
barrierDismissible: false,
|
|
|
|
|
builder: (context) => const AppLazyLoading(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mounted) {
|
|
|
|
|
Navigator.pop(context); // Close loading dialog
|
|
|
|
|
}
|
|
|
|
|
final request = SiteRequestModel(
|
|
|
|
|
requestType: _selectedRequestType!.identifier?.toString() ?? '',
|
|
|
|
|
employeeId: _provider.getCurrentUserEmployeeId(_userProvider),
|
|
|
|
|
fullName: _provider.getCurrentUserFullName(_userProvider),
|
|
|
|
|
emailAddress: _provider.getCurrentUserEmail(_userProvider),
|
|
|
|
|
mobileNumber: _provider.getCurrentUserMobile(_userProvider),
|
|
|
|
|
extensionNumber: _provider.getCurrentUserExtension(_userProvider),
|
|
|
|
|
siteIds: newSiteIds,
|
|
|
|
|
siteNames: newSiteNames,
|
|
|
|
|
oldSiteIds: oldSiteIds,
|
|
|
|
|
oldSiteNames: oldSiteNames,
|
|
|
|
|
departmentIds: departmentIds.isNotEmpty ? departmentIds : null,
|
|
|
|
|
departmentNames: departmentNames.isNotEmpty ? departmentNames : null,
|
|
|
|
|
role: _provider.getCurrentUserRole(_userProvider),
|
|
|
|
|
status: 'Pending',
|
|
|
|
|
requestDate: DateTime.now(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
|
_isSubmitting = false;
|
|
|
|
|
});
|
|
|
|
|
final success = await _provider.submitSiteRequest(request, _userProvider);
|
|
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
|
Fluttertoast.showToast(msg: "Site request submitted successfully");
|
|
|
|
|
if (mounted) {
|
|
|
|
|
Navigator.pop(context); // Close loading dialog
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
|
_isSubmitting = false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// API will handle success/error toast messages
|
|
|
|
|
if (success && mounted) {
|
|
|
|
|
Navigator.pushReplacementNamed(context, SiteRequestHistoryScreen.routeName);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Fluttertoast.showToast(
|
|
|
|
|
msg: _provider.errorMessage ?? "Failed to submit site request",
|
|
|
|
|
// For Add Site and Remove Site request types
|
|
|
|
|
if (_selectedSites.isEmpty) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
|
_isSubmitting = true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (mounted) {
|
|
|
|
|
showDialog(
|
|
|
|
|
context: context,
|
|
|
|
|
barrierDismissible: false,
|
|
|
|
|
builder: (context) => const AppLazyLoading(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final request = SiteRequestModel(
|
|
|
|
|
requestType: _selectedRequestType!.identifier?.toString() ?? '',
|
|
|
|
|
employeeId: _provider.getCurrentUserEmployeeId(_userProvider),
|
|
|
|
|
fullName: _provider.getCurrentUserFullName(_userProvider),
|
|
|
|
|
emailAddress: _provider.getCurrentUserEmail(_userProvider),
|
|
|
|
|
mobileNumber: _provider.getCurrentUserMobile(_userProvider),
|
|
|
|
|
extensionNumber: _provider.getCurrentUserExtension(_userProvider),
|
|
|
|
|
siteIds: _selectedSites.map((s) => s.identifier ?? '').toList(),
|
|
|
|
|
siteNames: _selectedSites.map((s) => s.name ?? '').toList(),
|
|
|
|
|
departmentIds: _selectedDepartments.isNotEmpty ? _selectedDepartments.map((d) => d.identifier ?? '').toList() : null,
|
|
|
|
|
departmentNames: _selectedDepartments.isNotEmpty ? _selectedDepartments.map((d) => d.name ?? '').toList() : null,
|
|
|
|
|
role: _provider.getCurrentUserRole(_userProvider),
|
|
|
|
|
status: 'Pending',
|
|
|
|
|
requestDate: DateTime.now(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
final success = await _provider.submitSiteRequest(request, _userProvider);
|
|
|
|
|
|
|
|
|
|
if (mounted) {
|
|
|
|
|
Navigator.pop(context); // Close loading dialog
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
|
_isSubmitting = false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// API will handle success/error toast messages
|
|
|
|
|
if (success && mounted) {
|
|
|
|
|
Navigator.pushReplacementNamed(context, SiteRequestHistoryScreen.routeName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class SiteReplacement {
|
|
|
|
|
final Site? newSite;
|
|
|
|
|
final List<Department> departments;
|
|
|
|
|
|
|
|
|
|
SiteReplacement({
|
|
|
|
|
required this.newSite,
|
|
|
|
|
required this.departments,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|