User Profile Management

This commit is contained in:
Venba Team 2025-04-02 15:47:15 +05:30
parent 23e6c1608a
commit 7d684e86b3
17 changed files with 3405 additions and 60 deletions

View File

@ -386,7 +386,6 @@ class _ForexScreenState extends State<ForexScreen> {
print("CAsh - $cashAmount- CaRd- $enteredAmount - $calculateAmnt - selectedQuotedAmount - $qouteAmount");
if (enteredAmount == null || calculateAmnt > qouteAmount!) {
errorMessages["deposit_on_card"] = "Amount cannot exceed $qouteAmount";
} else {

View File

@ -154,8 +154,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
}
void _clearError(String field) {
if (mounted && errorMessages.containsKey(field)) {
setState(() {
@ -165,11 +163,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
}
bool isValidData(Map<String, dynamic> data) {
errorMessages.clear(); // Reset errors
@ -327,8 +320,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
Column(
children: _buildTripType(isDesktop)
)
],
),
if (isDesktop)

View File

@ -410,10 +410,6 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
final String apiUrldata = '$apiUrl/api/getDropdownMaster';
final token = await getToken();
final userId = "1";
// final userId = await getUserId();
print("SUSRTRT- $userId");
if (token == null) {
throw Exception('Token not found. Please log in.');
@ -456,7 +452,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
final token = await getToken();
// final userId = await getUserId();
final userId = await getUserId();
// print("SUSRTRT- $userId");
//
@ -508,7 +504,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
final token = await getToken();
// final userId = await getUserId();
final userId = await getUserId();
// print("SUSRTRT- $userId");
//
@ -1270,7 +1266,7 @@ class _CreateNewPlansState extends State<CreateNewPlan> {
keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12),
enabled: !widget.isViewMode,
decoration: InputDecoration(
decoration: InputDecoration(
labelText: "Description",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never,

View File

@ -465,27 +465,51 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
List<Widget> _buildOptions() {
return [
_buildOption("Flight"),
_buildOption("Flight", itineraryData["Flight"]?.isNotEmpty ?? false),
SizedBox(width: 20),
_buildOption("Taxi"),
_buildOption("Taxi", itineraryData["Taxi"]?.isNotEmpty ?? false),
SizedBox(width: 20),
_buildOption("Train"),
_buildOption("Train", itineraryData["Train"]?.isNotEmpty ?? false),
SizedBox(width: 20),
_buildOption("Bus"),
_buildOption("Bus", itineraryData["Bus"]?.isNotEmpty ?? false),
SizedBox(width: 20),
_buildOption("Accomodation"),
_buildOption("Accomodation", itineraryData["Accomodation"]?.isNotEmpty ?? false),
SizedBox(width: 20),
_buildOption("Forex"),
_buildOption("Forex", itineraryData["Forex"]?.isNotEmpty ?? false),
SizedBox(width: 20),
_buildOption("Insurance"),
_buildOption("Insurance", itineraryData["Insurance"]?.isNotEmpty ?? false),
SizedBox(width: 20),
_buildOption("Visa"),
_buildOption("Visa", itineraryData["Visa"]?.isNotEmpty ?? false),
SizedBox(width: 20),
_buildOption("Miscellaneous"),
_buildOption("Miscellaneous", itineraryData["Miscellaneous"]?.isNotEmpty ?? false),
];
}
Widget _buildOption(String title) {
// List<Widget> _buildOptions() {
// return [
// _buildOption("Flight", itineraryData["Flight"]?.isNotEmpty ?? false),
// _buildOption("Flight"),
// SizedBox(width: 20),
// _buildOption("Taxi"),
// SizedBox(width: 20),
// _buildOption("Train"),
// SizedBox(width: 20),
// _buildOption("Bus"),
// SizedBox(width: 20),
// _buildOption("Accomodation"),
// SizedBox(width: 20),
// _buildOption("Forex"),
// SizedBox(width: 20),
// _buildOption("Insurance"),
// SizedBox(width: 20),
// _buildOption("Visa"),
// SizedBox(width: 20),
// _buildOption("Miscellaneous"),
// ];
// }
Widget _buildOption(String title, bool hasData) {
return GestureDetector(
onTap: () {
setState(() {
@ -495,6 +519,11 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
},
child: Row(
children: [
if(hasData)
Icon(Icons.circle_notifications,color: Colors.green, size: 10,),
SizedBox(width: 5),
Text(title,
style: TextStyle(
fontSize: 13,

View File

@ -23,25 +23,67 @@ class ListPlans extends StatefulWidget{
class _ListPlansState extends State<ListPlans>{
late Future<List<Plan>> futurePlans;
String? userId;
String? token;
@override
void initState(){
super.initState();
futurePlans = fetchPlans();
getToken();
initializeData();
// futurePlans = fetchPlans();
}
Future<void> initializeData ()async{
token = await getToken();
userId = await getUserId();
if(token == null || userId == null){
print("Token or USerId missing");
return;
}
else{
setState(() {
futurePlans = fetchPlans();
});
}
}
Future<String?> getUserId() async {
final prefs = await SharedPreferences.getInstance();
final String? userDataString = prefs.getString('user_data');
if(userDataString != null){
try{
final Map<String,dynamic> userData = jsonDecode(userDataString);
return userData["user_id"]?.toString();
}catch(e){
return null;
}
}
return null;
}
Future<String?> getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('auth_token');
}
// Fetch API Data
Future<List<Plan>> fetchPlans() async {
final String apiUrldata = '$apiUrl/api/plans';
// final String apiUrldata = '$apiUrl/api/plans';
final String apiUrldata = '$apiUrl/api/plans?user_id=$userId';
// final token = await getToken();
final token = await getToken();
if (token == null) {
throw Exception('Token not found. Please log in.');
@ -68,7 +110,7 @@ class _ListPlansState extends State<ListPlans>{
Future <Map<String,dynamic>> getViewPlan(String planId) async{
final String apiUrldata = '$apiUrl/api/plans/find/$planId';
print("API URL: $apiUrldata");
final token = await getToken();
// final token = await getToken();
if (token == null) {
throw Exception('Token not found. Please log in.');
@ -269,9 +311,6 @@ class _ListPlansState extends State<ListPlans>{
// },
// );
return Expanded(
child: SingleChildScrollView(
// scrollDirection: Axis.horizontal, // Outer wrapper for horizontal scrolling
@ -317,7 +356,22 @@ class _ListPlansState extends State<ListPlans>{
DataCell(Text(plan.tripType)),
DataCell(Text(plan.costCenter)),
DataCell(Text(plan.isBillable)),
DataCell(Text(plan.status)),
DataCell(
Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), // Padding for better look
decoration: BoxDecoration(
color: plan.status == "Active" ? Colors.green.shade50 : Colors.grey.shade50, // Background color
borderRadius: BorderRadius.circular(10), // Rounded corners
),
child: Text(
plan.status,
style: TextStyle(
color: plan.status == "Active" ? Colors.green : Colors.grey, // Text color
fontWeight: FontWeight.bold, // Optional: Make text bold
),
),
),
),
DataCell(
Row(
children:[

View File

@ -0,0 +1 @@
// TODO Implement this library.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,490 @@
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(),
),
),
),
),
),
),
);
},
),
]));
}
}

View File

@ -1,37 +1,161 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:responsive_builder/responsive_builder.dart';
import 'package:shared_preferences/shared_preferences.dart';
class CustomDrawer extends StatelessWidget{
final bool isDesktop;
class CustomDrawer extends StatefulWidget{
final bool isDesktop;
const CustomDrawer({super.key, required this.isDesktop});
@override
_CustomDrawerState createState() => _CustomDrawerState();
}
class _CustomDrawerState extends State<CustomDrawer>{
String? token;
Map<String,dynamic>? userData;
Map<String, dynamic>? fetchedUserData;
Map<String, dynamic> userDetails = {};
@override
void initState() {
super.initState();
initializeData();
}
Future<void> initializeData() async{
print("initializeDatainitializeData");
token = await getToken();
fetchedUserData = await getUserData();
if(token == null || fetchedUserData == null)
{
print("Token or USerId missing");
return;
}
setState(() {
userData = fetchedUserData;
});
}
Future<String?> getToken() async{
final prefs = await SharedPreferences.getInstance();
return prefs.getString("auth_token");
}
Future <Map<String,dynamic>?> getUserData() async {
final prefs = await SharedPreferences.getInstance();
final String? userDataString = prefs.getString('user_data');
if(userDataString != null){
try{
userDetails = jsonDecode(userDataString);
return{
"user_id" : userDetails["user_id"].toString(),
"name" : "${userDetails["first_name"]} ${userDetails["last_name"]}",
"email" : userDetails["email"] ?? "",
};
}catch (e) {
print("Error decoding user data: $e");
return null;
}
}
return null;
}
const CustomDrawer({super.key, required this.isDesktop});
@override
Widget build(BuildContext context){
Widget drawerContent = Column(
children: [
SizedBox(
height: 80,
child: const DrawerHeader(
decoration: BoxDecoration(color: Colors.blue),
child: SizedBox(
width: double.infinity,
child: Text('Menu', style: TextStyle(color: Colors.white, fontSize: 20)))
Widget drawerContent = Container(
color: Color(0xFFF3F3FA),
child: Column(
children: [
GestureDetector(
onTap:(){
print("ONTAP Custom");
context.go(
"/CreateUserDetails",
extra: {
"selectedUser": userDetails,
"isEditProfile": true,
"isViewMode": true
},
);
},
child :SizedBox(
height: 80,
child: Container(
color: Color(0xFFF3F3FA),
padding: EdgeInsets.all(16),
width: double.infinity,
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
height: 50,
width: 50,
decoration:BoxDecoration(
color: Colors.blueAccent,
shape: BoxShape.circle
) ,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ Text(
userData?["name"]?.isNotEmpty == true
? userData!["name"]![0].toUpperCase()
: "N/A",
style: TextStyle(color: Colors.white, fontSize: 25),
),],),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
userData?["name"] ?? "N/A",
style: TextStyle(color: Colors.black87, fontSize: 11),
),
Text(
userData?["email"] ?? "N/A",
style: TextStyle(color: Colors.black45, fontSize: 10),
),
],)
],)
),
),
),
_buildDrawerItem(context, Icons.home,'Home', '/home'),
_buildExpandableItem(context,Icons.assessment,'Plans',[
_buildSubDrawerItem(context,'My Plans','/listPlan'),
// _buildSubDrawerItem(context,'PlanB','/PlanB')
]),
_buildDrawerItem(context,Icons.logout,'Logout','/')
],
),
_buildDrawerItem(context, Icons.home,'Home', '/home'),
_buildExpandableItem(context,Icons.assessment,'Plans',[
_buildSubDrawerItem(context,'My Travel Request','/listPlan'),
// _buildSubDrawerItem(context,'PlanB','/PlanB')
]),
_buildExpandableItem(context,Icons.account_circle_outlined,'User ',[
_buildSubDrawerItem(context,'User List','/listUser'),
// _buildSubDrawerItem(context,'PlanB','/PlanB')
]),
_buildDrawerItem(context,Icons.logout,'Logout','/')
],
),
);
if (isDesktop) {
if (widget.isDesktop) {
// Sidebar for Desktop (always visible)**
return Container(
width: 250, // Fixed width for sidebar
@ -74,14 +198,13 @@ class CustomDrawer extends StatelessWidget{
);
}
Widget _buildSubDrawerItem(BuildContext context, String title, String route)
{
return ListTile(
title: Text(title),
onTap: (){
context.go(route);
if (!isDesktop) Navigator.pop(context);
if (!widget.isDesktop) Navigator.pop(context);
},
);
}

View File

@ -4,6 +4,8 @@ import 'package:frontend/Screens/authentication/loginPage1.dart';
import 'package:frontend/Screens/dashboard/home_page.dart';
import 'package:frontend/Screens/plans/create_plans.dart';
import 'package:frontend/Screens/plans/list_plans.dart';
import 'package:frontend/Screens/userManagement/create_user/create_user.dart';
import 'package:frontend/Screens/userManagement/user_List.dart';
import 'package:go_router/go_router.dart';
final GoRouter router = GoRouter(
@ -24,7 +26,13 @@ final GoRouter router = GoRouter(
path: '/createPlan',
builder: (context, state) => CreatePlan(),
),
GoRoute(
path: '/listUser',
builder: (context, state) => UserListScreen(),
),
GoRoute(
path: '/CreateUserDetails',
builder: (context, state) => CreateUserForm(),
),
],
);

View File

@ -0,0 +1,72 @@
import 'dart:convert';
import 'package:frontend/utils/auth_utils.dart';
import 'package:http/http.dart' as http;
import '../../config/apiUrl.dart';
class ApiService {
Future<List<dynamic>> 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");
}
return data['data'];
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else {
throw Exception('Failed to load country list');
}
}
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');
}
}
}

View File

@ -0,0 +1,6 @@
import 'package:shared_preferences/shared_preferences.dart';
Future<String?> getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString("auth_token");
}

View File

@ -35,6 +35,7 @@ class _CustomTextFieldForexWrapperState extends State<CustomTextFieldForexWrappe
padding: widget.padding,
decoration: BoxDecoration(
color: widget.color,
// color: Color(0xFFF7F7FB),
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: widget.isFocused ? Color(0xFF78B4FC) : Color(0xFFD6D5E6),

View File

@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
class CustomTextFieldUserWrapper extends StatefulWidget {
final Widget child;
final bool isFocused;
final bool isDesktop;
final double? width;
final Color? color;
final VoidCallback? onFocusChange; // Callback for focus handling
final EdgeInsetsGeometry padding;
const CustomTextFieldUserWrapper({
super.key,
required this.child,
required this.isFocused,
required this.isDesktop,
this.width,
this.color = Colors.white,
this.onFocusChange,
this.padding = const EdgeInsets.symmetric(horizontal: 12),
});
@override
_CustomTextFieldUserWrapperState createState() => _CustomTextFieldUserWrapperState();
}
class _CustomTextFieldUserWrapperState extends State<CustomTextFieldUserWrapper> {
@override
Widget build(BuildContext context) {
return Container(
width: widget.width ?? // Use custom width if provided, else default
(widget.isDesktop
? MediaQuery.of(context).size.width * 0.25
: MediaQuery.of(context).size.width * 0.8),
padding: widget.padding,
decoration: BoxDecoration(
// color: widget.color,
color: Color(0xFFF7F7FB),
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: widget.isFocused ? Color(0xFF78B4FC) : Color(0xFFD6D5E6),
width: widget.isFocused ? 2.0 : 0.5,
),
boxShadow: widget.isFocused
? [
BoxShadow(
color: Color.fromRGBO(120, 180, 252, 0.3),
blurRadius: 10,
spreadRadius: 2,
offset: Offset(0, 4),
),
]
: [],
),
child: widget.child,
);
}
}

View File

@ -5,8 +5,10 @@
import FlutterMacOS
import Foundation
import file_picker
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

View File

@ -17,6 +17,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.0"
bcrypt:
dependency: "direct main"
description:
name: bcrypt
sha256: "9dc3f234d5935a76917a6056613e1a6d9b53f7fa56f98e24cd49b8969307764b"
url: "https://pub.dev"
source: hosted
version: "1.1.3"
boolean_selector:
dependency: transitive
description:
@ -49,6 +57,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.19.0"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.dev"
source: hosted
version: "0.3.4+2"
crypto:
dependency: transitive
description:
@ -105,6 +121,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.1"
file_picker:
dependency: "direct main"
description:
name: file_picker
sha256: "36a1652d99cb6bf8ccc8b9f43aded1fd60b234d23ce78af422c07f950a436ef7"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
flutter:
dependency: "direct main"
description: flutter
@ -118,6 +142,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3"
url: "https://pub.dev"
source: hosted
version: "2.0.27"
flutter_test:
dependency: "direct dev"
description: flutter
@ -453,6 +485,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
win32:
dependency: transitive
description:
name: win32
sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e
url: "https://pub.dev"
source: hosted
version: "5.10.1"
xdg_directories:
dependency: transitive
description:

View File

@ -41,6 +41,8 @@ dependencies:
easy_stepper: ^0.8.5+1
intl: ^0.20.2
dropdown_search: ^5.0.6
file_picker: ^10.0.0
bcrypt: ^1.1.3
dev_dependencies: