489 lines
20 KiB
Dart
489 lines
20 KiB
Dart
import 'dart:convert';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:responsive_builder/responsive_builder.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import '../../config/apiUrl.dart';
|
|
import '../../routes/custom_appBar.dart';
|
|
import '../../routes/custom_drawer.dart';
|
|
|
|
class UserListScreen extends StatefulWidget {
|
|
@override
|
|
_UserListScreenState createState() => _UserListScreenState();
|
|
}
|
|
|
|
class _UserListScreenState extends State<UserListScreen> {
|
|
late Future<List<dynamic>> futureUsers;
|
|
List<dynamic>? apiCountryData;
|
|
String? selectedUserId;
|
|
|
|
Future<String?> getToken() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
return prefs.getString('auth_token');
|
|
|
|
}
|
|
|
|
Future<List<dynamic>> fetchUsers() async {
|
|
final String apiUrlData = '$apiUrl/api/users';
|
|
final String? token = await getToken();
|
|
|
|
print("Fetch Users");
|
|
print("TOEKRWE: $token");
|
|
|
|
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) {
|
|
final data = json.decode(response.body);
|
|
return data['data']; // Returning raw JSON list
|
|
} else {
|
|
throw Exception('Failed to load users');
|
|
}
|
|
}
|
|
|
|
Future<void> fetchCountryList() async {
|
|
final String apiUrldata = '$apiUrl/api/getcountryMaster';
|
|
|
|
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("Country - $data");
|
|
|
|
if (!data.containsKey('data') || data['data'] is!List) {
|
|
throw Exception("Invalid response format: 'data' field is missing or not a List");
|
|
}
|
|
|
|
List <dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
|
|
|
if (data['data'] is List) {
|
|
List<dynamic> plansJson = data['data'];
|
|
print("plansJson.length - ${plansJson.length}");
|
|
} else {
|
|
print("The 'data' key does not contain a list.");
|
|
}
|
|
|
|
setState(() {
|
|
apiCountryData = plansJson; // Store API response in state
|
|
});
|
|
print('plansJSONContry - $plansJson');
|
|
|
|
} catch (e) {
|
|
throw Exception('Error parsing response: $e');
|
|
}
|
|
} else {
|
|
throw Exception('Failed to load plans');
|
|
}
|
|
}
|
|
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
futureUsers = fetchUsers();
|
|
fetchCountryList();
|
|
}
|
|
|
|
void handleDelete(userId){
|
|
print("handDel - $userId");
|
|
}
|
|
|
|
|
|
void handleToggleUserStatus(String userId, String currentStatus) async {
|
|
print("Toggling user status - $userId (Current: $currentStatus)");
|
|
|
|
final String apiUrlData = '$apiUrl/api/users/update/$userId'; // API for updating user
|
|
final String? token = await getToken();
|
|
|
|
if (token == null) {
|
|
print("Error: Token not found");
|
|
return;
|
|
}
|
|
|
|
// Toggle status: If active ("1"), set to inactive ("0"); otherwise, activate ("1")
|
|
String newStatus = (currentStatus == "1") ? "0" : "1";
|
|
|
|
try {
|
|
final response = await http.put(
|
|
Uri.parse(apiUrlData),
|
|
headers: {
|
|
'Authorization': 'Bearer $token',
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: jsonEncode({
|
|
"is_active": newStatus // Set new status dynamically
|
|
}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
print("User status updated successfully to $newStatus!");
|
|
refreshUserList(); // Refresh users list after update
|
|
} else {
|
|
print("Failed to update user status. Status: ${response.statusCode}");
|
|
print("Error: ${response.body}");
|
|
}
|
|
} catch (e) {
|
|
print("Error updating user status: $e");
|
|
}
|
|
}
|
|
|
|
// Refresh user list after update
|
|
void refreshUserList() {
|
|
setState(() {
|
|
futureUsers = fetchUsers(); // Re-fetch users after status update
|
|
});
|
|
}
|
|
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
|
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
|
|
|
|
|
return Scaffold(
|
|
appBar: isDesktop ? null : const CustomAppBar(title:'User Management'),
|
|
drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
|
body:
|
|
Container(
|
|
color: Colors.white,
|
|
child: Row(
|
|
children: [
|
|
if(isDesktop)
|
|
CustomDrawer(isDesktop: true),
|
|
// const Expanded(child: Center(child: Text("User Page Content"))),
|
|
Expanded(child: buildUserTable(isDesktop)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
|
|
});
|
|
}
|
|
|
|
Widget buildUserTable(bool isDesktop) {
|
|
|
|
|
|
|
|
return Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
const Text('User List',
|
|
style:
|
|
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
|
IconButton(
|
|
icon: const Icon(Icons.keyboard_arrow_down),
|
|
onPressed: () {
|
|
|
|
},
|
|
),
|
|
],
|
|
),
|
|
ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
foregroundColor: Colors.white,
|
|
backgroundColor: Colors.blueAccent),
|
|
onPressed: () async {
|
|
|
|
List<dynamic> users = await futureUsers;
|
|
|
|
// Print the resolved value
|
|
print("CREATELIAS - $users");
|
|
|
|
context.go("/CreateUserDetails",
|
|
extra: {
|
|
// 'apiCountryData': apiCountryData,
|
|
'apiUserData' :users,
|
|
}
|
|
);
|
|
if (!isDesktop) Navigator.pop(context);
|
|
},
|
|
child: Row(
|
|
children: [
|
|
Icon(Icons.add_circle,color: Colors.white,),
|
|
SizedBox(width: 5,),
|
|
Text('New User'),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 10),
|
|
|
|
FutureBuilder<List<dynamic>>(
|
|
future: futureUsers,
|
|
builder: (context, snapshot) {
|
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
return Center(child: CircularProgressIndicator());
|
|
} else if (snapshot.hasError) {
|
|
return Center(child: Text("Error: ${snapshot.error}"));
|
|
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
|
return Center(child: Text("No users found"));
|
|
}
|
|
|
|
List<dynamic> users = snapshot.data!;
|
|
Color borderColor = Color(0xFF9E9DBD);
|
|
|
|
return Expanded(
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.vertical,
|
|
child: SizedBox(
|
|
width: MediaQuery.of(context).size.width * 1.5,
|
|
child: SingleChildScrollView(
|
|
|
|
scrollDirection: Axis.horizontal, // Inner wrapper for vertical scrolling
|
|
|
|
child: ConstrainedBox(
|
|
constraints: BoxConstraints(minWidth: MediaQuery.of(context).size.width),
|
|
// constraints: BoxConstraints(minWidth: 1300),
|
|
// width: MediaQuery.of(context).size.width ,
|
|
|
|
child: Container(
|
|
// color: Colors.amber,
|
|
child: DataTable(
|
|
columnSpacing: 20.0, // Adjust spacing between columns
|
|
dividerThickness: 0.5,
|
|
dataRowMinHeight: 60.0, // Minimum row height
|
|
dataRowMaxHeight: 100.0,
|
|
border: TableBorder(
|
|
horizontalInside: BorderSide(width: 0.5, color: Colors.grey.shade200),
|
|
),
|
|
columns: const [
|
|
|
|
DataColumn(label: Text('User Details',style: TextStyle(color: Color(0xFF9E9DBD),fontSize: 15, fontWeight: FontWeight.bold),)),
|
|
DataColumn(label: Text('Role',style: TextStyle(color: Color(0xFF9E9DBD),fontSize: 15, fontWeight: FontWeight.bold),)),
|
|
DataColumn(label: Text('Level',style: TextStyle(color: Color(0xFF9E9DBD),fontSize: 15, fontWeight: FontWeight.bold),)),
|
|
DataColumn(label: Text('Status',style: TextStyle(color: Color(0xFF9E9DBD),fontSize: 15, fontWeight: FontWeight.bold),)),
|
|
DataColumn(label: Text('Actions',style: TextStyle(color: Color(0xFF9E9DBD),fontSize: 15, fontWeight: FontWeight.bold),)),
|
|
|
|
],
|
|
|
|
rows: users.map((user) {
|
|
String userId = user['user_id'].toString(); // Get user ID
|
|
bool isSelected = selectedUserId == userId;
|
|
|
|
return DataRow(cells: [
|
|
// DataCell(Text(user['user_id'].toString())),
|
|
DataCell(
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
|
|
Align(alignment: Alignment.center,
|
|
child: GestureDetector(
|
|
onTap: () {
|
|
setState(() {
|
|
selectedUserId = userId; // Store clicked user ID
|
|
});
|
|
},
|
|
child: Container(
|
|
width: 15, // Adjust size
|
|
height: 15,
|
|
decoration: BoxDecoration(
|
|
// Background color
|
|
shape: BoxShape.rectangle,
|
|
border: Border.all(
|
|
color: isSelected ? Colors.blueAccent : Color(0xFF9E9DBD),
|
|
// color: Color(0xFF9E9DBD),
|
|
// color: Color.fromRGBO(128, 128, 128, 0.6),
|
|
width: isSelected ?2:1), // Grey outline
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
|
|
|
|
SizedBox(width: 50,),
|
|
Align(
|
|
alignment: Alignment.center,
|
|
child: Container(
|
|
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
border: Border.all(color: Color(0xFF9E9DBD), width: 1), // Grey outline
|
|
),
|
|
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(2.0),
|
|
child: Container(
|
|
|
|
width: 40, // Adjust size
|
|
height: 40,
|
|
decoration: BoxDecoration(
|
|
color: Colors.amber, // Inner circle background
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
(user['first_name'] != null && user['first_name']!.isNotEmpty)
|
|
? user['first_name']![0].toUpperCase()
|
|
: "?",
|
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ),
|
|
),],
|
|
|
|
|
|
),
|
|
),
|
|
)),
|
|
),
|
|
SizedBox(width: 20,),
|
|
|
|
Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(children: [
|
|
Text("${user['first_name'] ?? ''} ${user['last_name'] ?? ''}",
|
|
style: TextStyle( color: Colors.blueAccent,fontSize: 16),),
|
|
],),
|
|
|
|
SizedBox(height: 5),
|
|
|
|
Row(children: [
|
|
Icon(Icons.mail_outline, size: 15,color: Color(0xFF9E9EBE)),
|
|
SizedBox(width: 10,),
|
|
Text(user['email'] ?? '')
|
|
],),
|
|
|
|
SizedBox(height: 5),
|
|
Row(children: [
|
|
Icon(Icons.account_tree_outlined, size: 15,color:Color(0xFF9E9EBE)),
|
|
SizedBox(width: 10,),
|
|
Text(user['user_type'] ?? '') ],),
|
|
],),
|
|
],
|
|
)
|
|
),
|
|
|
|
DataCell(Text(user['role_id'] ?? 'N/A',style: TextStyle(color: user['is_active'] == "1" ? Colors.black :Colors.grey, fontWeight: FontWeight.bold),)),
|
|
DataCell(Text(user['level_id'] ?? 'N/A',style: TextStyle(color: user['is_active'] == "1" ? Colors.black :Colors.grey, fontWeight: FontWeight.bold),)),
|
|
DataCell(
|
|
GestureDetector( onTap :(){
|
|
handleToggleUserStatus(user['user_id'], user['is_active']);
|
|
},
|
|
child: Text(
|
|
user['is_active'] == "1" ? "Active" : "Inactive",
|
|
style: TextStyle(color: user['is_active'] == "1" ? Colors.lightGreen :Colors.grey ,
|
|
|
|
fontWeight: FontWeight.bold),)
|
|
|
|
)
|
|
|
|
),
|
|
|
|
|
|
DataCell(
|
|
Row(
|
|
children: [
|
|
MouseRegion(
|
|
cursor: user['is_active'] == "0" ? SystemMouseCursors.forbidden : SystemMouseCursors.click,
|
|
child: IconButton(
|
|
icon: Icon(Icons.remove_red_eye, color: user['is_active'] == "0" ? Colors.grey : Colors.blueAccent),
|
|
onPressed: user['is_active'] == "0"
|
|
? null
|
|
: () {
|
|
context.go(
|
|
"/CreateUserDetails",
|
|
extra: {
|
|
"selectedUser": user,
|
|
"isViewMode": true
|
|
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
MouseRegion(
|
|
cursor: user['is_active'] == "0" ? SystemMouseCursors.forbidden : SystemMouseCursors.click,
|
|
child: IconButton(
|
|
icon: Icon(Icons.edit, color: user['is_active'] == "0" ? Colors.grey : Colors.green),
|
|
onPressed: user['is_active'] == "0"
|
|
? null
|
|
: () {
|
|
print("USER: $user");
|
|
context.go(
|
|
"/CreateUserDetails",
|
|
extra: {
|
|
"selectedUser": user,
|
|
"isViewMode": false
|
|
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
MouseRegion(
|
|
cursor: user['is_active'] == "0" ? SystemMouseCursors.forbidden : SystemMouseCursors.click,
|
|
child: IconButton(
|
|
icon: Icon(Icons.delete, color: user['is_active'] == "0" ? Colors.grey : Colors.redAccent),
|
|
onPressed: user['is_active'] == "0"
|
|
? null
|
|
: () {
|
|
print("USER ID: ${user['user_id']}");
|
|
var userId = user['user_id'];
|
|
handleDelete(userId);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
]);
|
|
}).toList(),
|
|
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
},
|
|
),
|
|
|
|
|
|
|
|
|
|
]));
|
|
}
|
|
}
|