group changes
This commit is contained in:
parent
b630ac35b7
commit
2891e93d8d
645
lib/Screens/group/groupDetails.dart
Normal file
645
lib/Screens/group/groupDetails.dart
Normal file
@ -0,0 +1,645 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:dropdown_search/dropdown_search.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import '../../config/apiUrl.dart';
|
||||||
|
import '../../services/apiService.dart';
|
||||||
|
import '../../utils/auth_utils.dart';
|
||||||
|
import '../../widgets/custom_text_forex.dart';
|
||||||
|
import 'groupList.dart';
|
||||||
|
|
||||||
|
class GroupData extends StatefulWidget {
|
||||||
|
final Future<void> Function() fetchGetGroup;
|
||||||
|
final bool isDesktop;
|
||||||
|
final Color? layoutColor;
|
||||||
|
|
||||||
|
final int? groupId; // <-- Add this
|
||||||
|
final Map<String, dynamic>? groupData;
|
||||||
|
|
||||||
|
const GroupData(
|
||||||
|
{super.key,
|
||||||
|
required this.isDesktop,
|
||||||
|
this.layoutColor,
|
||||||
|
required this.fetchGetGroup,
|
||||||
|
this.groupId,
|
||||||
|
this.groupData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
GroupDataState createState() => GroupDataState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupDataState extends State<GroupData> {
|
||||||
|
final ApiService apiService = ApiService();
|
||||||
|
|
||||||
|
Map<String, String> DomesticMap = {};
|
||||||
|
Map<String, String> InternationalMap = {};
|
||||||
|
|
||||||
|
late List<dynamic>? apiForDomestic;
|
||||||
|
late List<dynamic>? apiForInternational;
|
||||||
|
|
||||||
|
Map<String, dynamic>? apiData;
|
||||||
|
final Map<String, TextEditingController> controllers = {};
|
||||||
|
Map<String, String> errorMessages = {};
|
||||||
|
|
||||||
|
|
||||||
|
List<dynamic> domesticList = [];
|
||||||
|
List<dynamic> internationalList = [];
|
||||||
|
|
||||||
|
String? selectedName;
|
||||||
|
String? selectedDescription;
|
||||||
|
|
||||||
|
String? selectedInternationalPolicyID;
|
||||||
|
String? selectedInternationalPolicyName;
|
||||||
|
|
||||||
|
String? selectedDomesticPolicyID;
|
||||||
|
String? selectedDomesticPolicyName;
|
||||||
|
|
||||||
|
String? userId;
|
||||||
|
int? groupDataId;
|
||||||
|
|
||||||
|
late String isActive = "1";
|
||||||
|
|
||||||
|
List<String> dataHeader = [
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"domestic_policy_id",
|
||||||
|
"domestic_policy_name",
|
||||||
|
"international_policy_id",
|
||||||
|
"international_policy_name",
|
||||||
|
];
|
||||||
|
|
||||||
|
Map<String, dynamic> group_Detials() {
|
||||||
|
final data = {
|
||||||
|
"name":controllers["name"]?.text,
|
||||||
|
"description":controllers["description"]?.text,
|
||||||
|
"domestic_policy_id":selectedDomesticPolicyID,
|
||||||
|
"international_policy_id":selectedInternationalPolicyID,
|
||||||
|
"domestic_policy_name":selectedDomesticPolicyName,
|
||||||
|
"international_policy_name":selectedInternationalPolicyName,
|
||||||
|
"is_active": isActive,
|
||||||
|
};
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
loadAllServices();
|
||||||
|
});
|
||||||
|
|
||||||
|
apiForDomestic = null;
|
||||||
|
apiForInternational = null;
|
||||||
|
|
||||||
|
apiData = null;
|
||||||
|
for (var field in dataHeader) {
|
||||||
|
controllers[field] = TextEditingController();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.groupId != null) {
|
||||||
|
print('Editing group ID: ${widget.groupId}');
|
||||||
|
updateGroupDetails();
|
||||||
|
}
|
||||||
|
_clearError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearError() {
|
||||||
|
setState(() {
|
||||||
|
errorMessages.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
for (var controller in controllers.values) {
|
||||||
|
controller.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateGroupDetails() {
|
||||||
|
print("Update - ${widget.groupData}");
|
||||||
|
|
||||||
|
final data = widget.groupData;
|
||||||
|
|
||||||
|
if (data == null) return;
|
||||||
|
setState(() {
|
||||||
|
selectedDomesticPolicyID = data['domestic_policy_id']; // For dropdown
|
||||||
|
selectedDomesticPolicyName = "";
|
||||||
|
selectedInternationalPolicyID = data['international_policy_id'];
|
||||||
|
selectedInternationalPolicyName = ""; // Optional if used elsewhere
|
||||||
|
controllers['name']?.text = data['name'] ?? '';
|
||||||
|
controllers['description']?.text = data['description'] ?? '';
|
||||||
|
isActive = data["is_active"];
|
||||||
|
final groupId = int.tryParse(data['group_id'].toString());
|
||||||
|
groupDataId = groupId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadAllServices() async {
|
||||||
|
try {
|
||||||
|
final result = await apiService.fetchAllPolicy();
|
||||||
|
|
||||||
|
userId = await getUserId();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
apiForDomestic =
|
||||||
|
result.where((policy) => policy["domestic"] == "1").toList();
|
||||||
|
apiForInternational =
|
||||||
|
result.where((policy) => policy["international"] == "1").toList();
|
||||||
|
});
|
||||||
|
print("Domestic policies: $apiForDomestic");
|
||||||
|
print("International policies: $apiForInternational");
|
||||||
|
} catch (e) {
|
||||||
|
print('Error fetching role list: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleStatus() {
|
||||||
|
setState(() {
|
||||||
|
isActive = isActive == "1" ? "0" : "1";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool validateData() {
|
||||||
|
errorMessages.clear();
|
||||||
|
|
||||||
|
final data = {
|
||||||
|
"name":controllers["name"]?.text,
|
||||||
|
"description":controllers["description"]?.text,
|
||||||
|
"domestic_policy_id":selectedDomesticPolicyID,
|
||||||
|
"international_policy_id":selectedInternationalPolicyID,
|
||||||
|
"domestic_policy_name":selectedDomesticPolicyName,
|
||||||
|
"international_policy_name":selectedInternationalPolicyName,
|
||||||
|
};
|
||||||
|
|
||||||
|
final requiredFields = [
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Check validation for each field
|
||||||
|
for (String field in requiredFields) {
|
||||||
|
if (data[field] == null || data[field].toString().trim().isEmpty) {
|
||||||
|
errorMessages[field] = "Required";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorMessages.isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> handleSubmit() async {
|
||||||
|
userId = await getUserId();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
// This triggers UI rebuild with error messages
|
||||||
|
if (validateData()) {
|
||||||
|
postGroupData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final groupData1 = group_Detials();
|
||||||
|
print("GroupDAta - $groupData1");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> postGroupData({int isActive = 1}) async {
|
||||||
|
final orgId = await getOrgId();
|
||||||
|
final groupData = group_Detials();
|
||||||
|
final String apiUrlData;
|
||||||
|
|
||||||
|
// static here
|
||||||
|
groupData["org_id"] = orgId;
|
||||||
|
|
||||||
|
// dynamic here
|
||||||
|
if (groupDataId != null) {
|
||||||
|
apiUrlData = '$apiUrl/api/groups/update/$groupDataId';
|
||||||
|
groupData["group_id"] = groupDataId.toString();
|
||||||
|
groupData["updated_by"] = userId;
|
||||||
|
} else {
|
||||||
|
apiUrlData = '$apiUrl/api/groups/create';
|
||||||
|
groupData["created_by"] = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
final token = await getToken(); // Fetch token
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final uri = Uri.parse(apiUrlData);
|
||||||
|
final headers = {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
};
|
||||||
|
final body = jsonEncode(groupData);
|
||||||
|
|
||||||
|
final response = groupDataId != null
|
||||||
|
? await http.put(uri, headers: headers, body: body)
|
||||||
|
: await http.post(uri, headers: headers, body: body);
|
||||||
|
|
||||||
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
|
print("Group Details Created successfully!");
|
||||||
|
print("Response: ${response.body}");
|
||||||
|
// _clearError();
|
||||||
|
_clearError();
|
||||||
|
await widget.fetchGetGroup();
|
||||||
|
|
||||||
|
// dispose();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
} else if (response.statusCode == 404) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
final message = jsonDecode(response.body)['message'] ?? 'Unknown error';
|
||||||
|
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(message),
|
||||||
|
backgroundColor: Colors.redAccent,
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
print("Failed to submit plan. Status: ${response.statusCode}");
|
||||||
|
print("Error: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(" Error submitting plan: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
late Map<String, String> DomesticMap;
|
||||||
|
late List<String> DomesticID;
|
||||||
|
late Map<String, String> InternationalMap;
|
||||||
|
late List<String> InternationalID;
|
||||||
|
|
||||||
|
domesticList = apiForDomestic ?? [];
|
||||||
|
internationalList = apiForInternational ?? [];
|
||||||
|
|
||||||
|
// print("domesticListFromAPI--$domesticList");
|
||||||
|
|
||||||
|
// Map id to names
|
||||||
|
DomesticMap = {
|
||||||
|
for (var object in domesticList)
|
||||||
|
object['policy_id'] as String: object['name'] as String
|
||||||
|
};
|
||||||
|
|
||||||
|
// print("domestic -- map--$DomesticMap");
|
||||||
|
|
||||||
|
// Extract only id for processing
|
||||||
|
DomesticID = DomesticMap.keys.toList();
|
||||||
|
|
||||||
|
// print("domestic -- id--$DomesticID");
|
||||||
|
|
||||||
|
// print("domestic -- selected --$selectedDomesticPolicyID");
|
||||||
|
|
||||||
|
InternationalMap = {
|
||||||
|
for (var item in internationalList)
|
||||||
|
item['policy_id'] as String: item['name'] as String
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extract only id for processing
|
||||||
|
InternationalID = InternationalMap.keys.toList();
|
||||||
|
|
||||||
|
selectedInternationalPolicyID ??= null;
|
||||||
|
|
||||||
|
return AlertDialog(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
// contentPadding: const EdgeInsets.fromLTRB(44, 40, 44, 40),
|
||||||
|
contentPadding: const EdgeInsets.fromLTRB(34, 30, 34, 30),
|
||||||
|
// contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 10),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// Row 1: Title + Edit + Delete buttons
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
(groupDataId != null) ? 'Edit Group' : 'Create Group',
|
||||||
|
style: GoogleFonts.poppins(fontSize: 15, color: Colors.black),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Divider(
|
||||||
|
thickness: 0.2,
|
||||||
|
color: Colors.blueGrey.shade100,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Name",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
CustomTextFieldForexWrapper(
|
||||||
|
isFocused: false,
|
||||||
|
isDesktop: widget.isDesktop,
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: TextField(
|
||||||
|
controller: controllers["name"],
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: "Name",
|
||||||
|
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
|
||||||
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
if (errorMessages["name"] != null) ...[
|
||||||
|
SizedBox(height: 5), // Space before error message
|
||||||
|
Text(
|
||||||
|
errorMessages["name"]!,
|
||||||
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Select Policy For International",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
CustomTextFieldForexWrapper(
|
||||||
|
isFocused: false,
|
||||||
|
isDesktop: widget.isDesktop,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: DropdownSearch<String>(
|
||||||
|
selectedItem: InternationalMap[selectedInternationalPolicyID],
|
||||||
|
popupProps: PopupProps.menu(
|
||||||
|
showSearchBox: true, // Enables search functionality
|
||||||
|
menuProps: const MenuProps(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
|
itemBuilder: (context, item, isSelected) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8.0, vertical: 6.0),
|
||||||
|
child: Text(
|
||||||
|
item,
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Select Policy For International",
|
||||||
|
hintStyle: GoogleFonts.poppins(fontSize: 11),
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
items: InternationalMap.values.toList(),
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
// Center-align selected item
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select Policy For International",
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
// Find the country_code based on selected country_name
|
||||||
|
selectedInternationalPolicyID = InternationalMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
selectedInternationalPolicyName = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Select Policy For Domestic",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
CustomTextFieldForexWrapper(
|
||||||
|
isFocused: false,
|
||||||
|
isDesktop: widget.isDesktop,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: DropdownSearch<String>(
|
||||||
|
selectedItem: DomesticMap[selectedDomesticPolicyID],
|
||||||
|
popupProps: PopupProps.menu(
|
||||||
|
showSearchBox: true, // Enables search functionality
|
||||||
|
menuProps: const MenuProps(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
constraints: BoxConstraints(maxHeight: 250),
|
||||||
|
itemBuilder: (context, object, isSelected) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8.0, vertical: 6.0),
|
||||||
|
child: Text(
|
||||||
|
object,
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Select Policy For Domestic...",
|
||||||
|
hintStyle: GoogleFonts.poppins(fontSize: 11),
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
items: DomesticMap.values.toList(),
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
// Center-align selected item
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select Policy For Domestic",
|
||||||
|
style: GoogleFonts.poppins(fontSize: 11),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
// Find the country_code based on selected country_name
|
||||||
|
selectedDomesticPolicyID = DomesticMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
selectedDomesticPolicyName = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Description",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
CustomTextFieldForexWrapper(
|
||||||
|
isFocused: false,
|
||||||
|
isDesktop: widget.isDesktop,
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 100,
|
||||||
|
child: TextField(
|
||||||
|
controller: controllers["description"],
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
maxLines: null,
|
||||||
|
expands: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: "Description",
|
||||||
|
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
|
||||||
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (errorMessages["description"] != null) ...[
|
||||||
|
SizedBox(height: 5), // Space before error message
|
||||||
|
Text(
|
||||||
|
errorMessages["description"]!,
|
||||||
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
if (groupDataId != null)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Change Status ",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74)),
|
||||||
|
),
|
||||||
|
Tooltip(
|
||||||
|
message:
|
||||||
|
isActive == "1" ? "Tap to deactivate" : "Tap to activate",
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: toggleStatus,
|
||||||
|
child: Text(
|
||||||
|
isActive == "1" ? "Active" : "Inactive",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontFamily: "Inter",
|
||||||
|
color: isActive == "1" ? Colors.green : Colors.red,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (groupDataId != null)
|
||||||
|
SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
// SizedBox(
|
||||||
|
// child: ElevatedButton(
|
||||||
|
// onPressed: () {
|
||||||
|
// // You can get text from commentController.text
|
||||||
|
// Navigator.of(context).pop(); // Close the modal
|
||||||
|
// },
|
||||||
|
// style: ElevatedButton.styleFrom(
|
||||||
|
// backgroundColor: widget.layoutColor,
|
||||||
|
// shape: RoundedRectangleBorder(
|
||||||
|
// borderRadius: BorderRadius.circular(8),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// child: Text('Cancel',
|
||||||
|
// style: GoogleFonts.poppins(
|
||||||
|
// fontSize: 13, color: Colors.white)),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// width: 10,
|
||||||
|
// ),
|
||||||
|
SizedBox(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
handleSubmit();
|
||||||
|
// You can get text from commentController.text
|
||||||
|
// Navigator.of(context).pop(); // Close the modal
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: widget.layoutColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text('Save',
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 11, color: Colors.white)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
// : SizedBox.shrink(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ import '../../routes/custom_appBar.dart';
|
|||||||
import '../../routes/custom_drawer.dart';
|
import '../../routes/custom_drawer.dart';
|
||||||
import '../../services/apiService.dart';
|
import '../../services/apiService.dart';
|
||||||
import '../../utils/auth_utils.dart';
|
import '../../utils/auth_utils.dart';
|
||||||
|
import 'groupDetails.dart';
|
||||||
|
|
||||||
class GroupList extends StatefulWidget {
|
class GroupList extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
@ -117,6 +118,10 @@ class _GroupListState extends State<GroupList> {
|
|||||||
handleActiveStatus(groupdata, groupId.toString(), status.toString());
|
handleActiveStatus(groupdata, groupId.toString(), status.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> refreshData() async {
|
||||||
|
loadAllGroups();
|
||||||
|
}
|
||||||
|
|
||||||
// Future<void> deleteGroupFromApi(int groupId) async {
|
// Future<void> deleteGroupFromApi(int groupId) async {
|
||||||
// try {
|
// try {
|
||||||
// await apiService.deleteGroup(groupId); // your delete API call
|
// await apiService.deleteGroup(groupId); // your delete API call
|
||||||
@ -236,7 +241,18 @@ class _GroupListState extends State<GroupList> {
|
|||||||
),
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// List<dynamic> users = await futureUsers;
|
// List<dynamic> users = await futureUsers;
|
||||||
context.go('/CreateGroup');
|
// context.go('/CreateGroup');
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => GroupData(
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
groupId: null,
|
||||||
|
layoutColor: layoutColor!,
|
||||||
|
fetchGetGroup: refreshData
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@ -355,9 +371,35 @@ class _GroupListState extends State<GroupList> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
context.go("/CreateGroup", extra: group);
|
|
||||||
|
if (group['group_id'] != null) {
|
||||||
|
final newGroupID = int.tryParse(group['group_id'].toString());
|
||||||
|
if (newGroupID != null) {
|
||||||
|
final data = await apiService.getGroupDetailsFind(newGroupID); // ✅ Always an int
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => GroupData(
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
groupId: newGroupID, // Pass the ID
|
||||||
|
groupData: data,
|
||||||
|
layoutColor: layoutColor!,
|
||||||
|
fetchGetGroup: refreshData
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
print("something went wrong check properly");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// onTap: () {
|
||||||
|
// context.go("/CreateGroup", extra: group);
|
||||||
|
// },
|
||||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||||
width: 20, height: 15),
|
width: 20, height: 15),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -96,7 +96,7 @@ class OrganizationSettingState extends State<OrganizationSetting> {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'value': '/hotels',
|
'value': '/hotels',
|
||||||
'icon': Icons.cabin_sharp,
|
'icon': Icons.add_business,
|
||||||
'label': 'Hotels',
|
'label': 'Hotels',
|
||||||
'description': 'Create and Edit Hotels'
|
'description': 'Create and Edit Hotels'
|
||||||
},
|
},
|
||||||
@ -126,6 +126,7 @@ class OrganizationSettingState extends State<OrganizationSetting> {
|
|||||||
case '/templateList':
|
case '/templateList':
|
||||||
case '/costcenter':
|
case '/costcenter':
|
||||||
case '/hotels':
|
case '/hotels':
|
||||||
|
case '/groupDetails' :
|
||||||
context.go(route);
|
context.go(route);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -1048,4 +1048,87 @@ class ApiService {
|
|||||||
throw Exception('Failed to load CostCenter details');
|
throw Exception('Failed to load CostCenter details');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Future<Map<String, dynamic>> getHotelsDetailsFind(int id) async {
|
||||||
|
final String apiUrldata = '$apiUrl/api/findHotels?hotel_id=$id';
|
||||||
|
|
||||||
|
final token = await getToken();
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
try {
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
// print('findout the result');
|
||||||
|
// print(data.runtimeType);
|
||||||
|
// print(data);
|
||||||
|
|
||||||
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a List");
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Map<String, dynamic>> listData =
|
||||||
|
List<Map<String, dynamic>>.from(data['data']);
|
||||||
|
|
||||||
|
if (listData.isEmpty) {
|
||||||
|
throw Exception("No Hotel data found with ID $id");
|
||||||
|
}
|
||||||
|
|
||||||
|
return listData[0];
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Error parsing response: $e');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load Hotel details');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Future<Map<String, dynamic>> getGroupDetailsFind(int id) async {
|
||||||
|
final String apiUrldata = '$apiUrl/api/groups/find/$id';
|
||||||
|
|
||||||
|
final token = await getToken();
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
try {
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
print(data);
|
||||||
|
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||||
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a Map");
|
||||||
|
}
|
||||||
|
print('Single USer 1');
|
||||||
|
|
||||||
|
Map<String, dynamic> plansJson =
|
||||||
|
data['data']; // 'data' is a Map, not a List
|
||||||
|
|
||||||
|
print('Single USer 2');
|
||||||
|
return plansJson;
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Error parsing response: $e');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load plans');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user