504 lines
17 KiB
Dart
504 lines
17 KiB
Dart
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:google_fonts/google_fonts.dart';
|
||
import 'package:nhance_partner/presentation/providers/userRoleProvider.dart';
|
||
import 'package:nhance_partner/presentation/screens/Masters/PaymentMode/payment.dart';
|
||
|
||
import '../../../../core/routing/routes.dart';
|
||
import '../../../../core/services/api_service.dart';
|
||
import '../../../../data/utils/Pagination.dart';
|
||
import '../../../layouts/main_layout.dart';
|
||
import '../../../layouts/responsive_layout.dart';
|
||
import '../../../providers/manager_provider.dart';
|
||
import '../../../themes/indicators/export_btn.dart';
|
||
import '../../../themes/indicators/filter_btn.dart';
|
||
import '../../../themes/indicators/search_field_theme.dart';
|
||
import '../../../themes/indicators/text_field_theme.dart';
|
||
import '../../../widgets/custom_action_popup.dart';
|
||
|
||
class PaymentLsit extends ConsumerStatefulWidget {
|
||
const PaymentLsit({super.key});
|
||
@override
|
||
ConsumerState<PaymentLsit> createState() => PaymentLsitState();
|
||
}
|
||
|
||
class PaymentLsitState extends ConsumerState<PaymentLsit> {
|
||
int currentPage = 1;
|
||
int itemsPerPage = 10;
|
||
late ApiService apiService;
|
||
dynamic managerId;
|
||
dynamic role;
|
||
dynamic prefid;
|
||
dynamic userId;
|
||
// List<Map<String, dynamic>> dataVal = [];
|
||
List<Map<String, dynamic>> getPaymentData = [];
|
||
List<Map<String, dynamic>> originalData = [];
|
||
List<Map<String, dynamic>> filteredData = [];
|
||
bool isLoading = false;
|
||
|
||
Map<String, dynamic>? selectedPayment;
|
||
dynamic selectedId;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
|
||
apiService = ApiService();
|
||
|
||
Future.microtask(() {
|
||
final data1 = ref.read(managerIdProvider);
|
||
// final data2 = ref.read(handlerIdProvider);
|
||
print("Edata1 => mId: $data1 -2 :");
|
||
prefid = data1;
|
||
role = ref.read(userRoleProvider);
|
||
userId = ref.watch(userIdProvider);
|
||
print("E43 => mId: $prefid");
|
||
if (prefid != null && role != null) {
|
||
getPayment();
|
||
}
|
||
});
|
||
// getPaymentList();
|
||
}
|
||
|
||
List<dynamic> get _paginatedData {
|
||
// Sort descending by id first
|
||
final sortedData = [...filteredData]
|
||
..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
|
||
|
||
if (sortedData.isEmpty) return [];
|
||
|
||
// Ensure currentPage is valid
|
||
final maxPage = (sortedData.length / itemsPerPage).ceil();
|
||
final safePage = currentPage.clamp(1, maxPage);
|
||
|
||
final startIndex = (safePage - 1) * itemsPerPage;
|
||
final endIndex = (startIndex + itemsPerPage).clamp(0, sortedData.length);
|
||
|
||
return sortedData.sublist(startIndex, endIndex);
|
||
}
|
||
|
||
void handleEdit(Map<String, dynamic> item) {
|
||
setState(() {
|
||
selectedId = item['id'];
|
||
selectedPayment = item;
|
||
});
|
||
}
|
||
|
||
void filterData(String query) {
|
||
setState(() {
|
||
final q = query.toLowerCase();
|
||
|
||
if (q.isEmpty) {
|
||
filteredData = getPaymentData;
|
||
return;
|
||
}
|
||
|
||
filteredData = getPaymentData.where((item) {
|
||
final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
|
||
|
||
return (item['value'] ?? '').toString().toLowerCase().contains(q) ||
|
||
isActiveStatus.contains(q);
|
||
}).toList();
|
||
});
|
||
}
|
||
|
||
final TextEditingController _searchStaffController = TextEditingController();
|
||
|
||
Future<void> getPayment() async {
|
||
print('getPayment called');
|
||
setState(() {
|
||
isLoading = true;
|
||
});
|
||
|
||
try {
|
||
final response = await apiService.fetchMasterDropDown('PaymentMode');
|
||
|
||
if (response['status'] == 200) {
|
||
print('getPayment - ${response['data']}');
|
||
setState(() {
|
||
getPaymentData = List<Map<String, dynamic>>.from(response['data']);
|
||
print('API Data - $getPaymentData');
|
||
|
||
filteredData = List.from(getPaymentData);
|
||
print('originalData - $filteredData');
|
||
});
|
||
} else {
|
||
getPaymentData = [];
|
||
filteredData = [];
|
||
}
|
||
} catch (e) {
|
||
print('Exception occurred: $e');
|
||
} finally {
|
||
setState(() {
|
||
isLoading = false;
|
||
});
|
||
}
|
||
}
|
||
|
||
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
|
||
return [
|
||
GestureDetector(
|
||
onTap: () {
|
||
Navigator.pop(context);
|
||
print('EDITStaff - ${data['id']}');
|
||
dynamic id = data['id'];
|
||
context.go('/staff/$id');
|
||
},
|
||
child: Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18),
|
||
SizedBox(width: 10),
|
||
Text('Edit'),
|
||
],
|
||
),
|
||
),
|
||
];
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
managerId = ref.watch(managerIdProvider);
|
||
|
||
return MainLayout(
|
||
title: "Staff",
|
||
body: SelectionArea(
|
||
child: Container(
|
||
// padding: EdgeInsets.all(8.0),
|
||
// margin: EdgeInsets.all(10.0),
|
||
|
||
// color: Colors.yellow.shade50,
|
||
width: MediaQuery.of(context).size.width,
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
mainAxisAlignment: MainAxisAlignment.start,
|
||
children: [
|
||
// Container(
|
||
// // height: 30,
|
||
// // color: Colors.red.shade50,
|
||
// width: MediaQuery.of(context).size.width,
|
||
// child: GestureDetector(
|
||
// onTap: () {
|
||
// context.go(AppRoutes.dashboard);
|
||
// },
|
||
// child: Row(
|
||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||
// mainAxisAlignment: MainAxisAlignment.start,
|
||
// children: [
|
||
// Text(
|
||
// 'Payment List',
|
||
// style: GoogleFonts.poppins(
|
||
// fontSize: 14,
|
||
// fontWeight: FontWeight.w500,
|
||
// ),
|
||
// ),
|
||
// ],
|
||
// ),
|
||
// ),
|
||
// ),
|
||
Text(
|
||
'Payment',
|
||
style: GoogleFonts.poppins(
|
||
fontSize: 14,
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
),
|
||
SizedBox(height: 5),
|
||
Expanded(
|
||
child: Container(
|
||
// color: Colors.green,
|
||
// color: Colors.green.shade50,
|
||
width: MediaQuery.of(context).size.width,
|
||
// margin: EdgeInsets.all(10.0),
|
||
decoration: BoxDecoration(
|
||
// color: Colors.white,
|
||
borderRadius: BorderRadius.circular(15.0),
|
||
),
|
||
|
||
padding: EdgeInsets.all(8.0),
|
||
child: Column(
|
||
children: [
|
||
Container(
|
||
// height: 40,
|
||
// color: Colors.pink,
|
||
child: Row(
|
||
crossAxisAlignment: CrossAxisAlignment.end,
|
||
mainAxisAlignment: MainAxisAlignment.start,
|
||
children: [
|
||
Payment(
|
||
key: ValueKey(selectedId),
|
||
data: selectedPayment,
|
||
id: selectedId,
|
||
onSubmit: () {
|
||
getPayment();
|
||
setState(() {
|
||
selectedPayment = null;
|
||
selectedId = null;
|
||
}); // reset after save
|
||
},
|
||
),
|
||
Spacer(),
|
||
ThemedSearchField(
|
||
hintText: 'Search',
|
||
// backgroundColor: Color(0xFFF6F8F8),
|
||
backgroundColor: Color(0xFFFFFFFF),
|
||
txtHeight: 30,
|
||
onChanged: filterData,
|
||
controller: _searchStaffController,
|
||
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
||
),
|
||
|
||
SizedBox(width: 10),
|
||
ExportBtn(
|
||
sheetName: "Payment",
|
||
fileName: "Payment_list",
|
||
txt: !ResponsiveLayout.isMobile(context)
|
||
? true
|
||
: false,
|
||
data: filteredData,
|
||
displayHeaders: ['S.No.', 'Payment', 'Status'],
|
||
keys: ["sno", "value", "is_active"],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
SizedBox(height: 10),
|
||
Container(
|
||
decoration: BoxDecoration(
|
||
color: Color(0xFFF1F5F9),
|
||
// color: Color(0xFFEDF6F5),
|
||
borderRadius: BorderRadius.circular(6),
|
||
),
|
||
padding: const EdgeInsets.symmetric(
|
||
vertical: 10,
|
||
horizontal: 16,
|
||
),
|
||
child: Row(
|
||
children: [
|
||
// Expanded(
|
||
// flex: 1,
|
||
// child: Text('S.No.', style: _headerStyle),
|
||
// ),
|
||
SizedBox(
|
||
width: 50,
|
||
child: Text('S.No.', style: _headerStyle),
|
||
),
|
||
Expanded(
|
||
flex: 1,
|
||
child: Text('Payment', style: _headerStyle),
|
||
),
|
||
|
||
Expanded(
|
||
flex: 1,
|
||
child: Text('Status', style: _headerStyle),
|
||
),
|
||
Expanded(
|
||
flex: 1,
|
||
child: Text('Action', style: _headerStyle),
|
||
),
|
||
Expanded(
|
||
flex: 1,
|
||
child: Text('', style: _headerStyle),
|
||
),
|
||
Expanded(
|
||
flex: 1,
|
||
child: Text('', style: _headerStyle),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Expanded(
|
||
child: Container(
|
||
color: Colors.white,
|
||
child: _buildDataTable(context),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
|
||
Container(
|
||
// height: 20,
|
||
width: MediaQuery.of(context).size.width,
|
||
// color: Colors.green.shade50,
|
||
child: PaginationControls(
|
||
currentPage: currentPage,
|
||
itemsPerPage: itemsPerPage,
|
||
// totalItems: dataVal.length,
|
||
totalItems: filteredData.length,
|
||
// activeColor: layoutColor, // your theme color
|
||
onPageChanged: (page) {
|
||
setState(() {
|
||
currentPage = page;
|
||
});
|
||
},
|
||
onItemsPerPageChanged: (items) {
|
||
setState(() {
|
||
itemsPerPage = items;
|
||
currentPage = 1;
|
||
});
|
||
},
|
||
),
|
||
),
|
||
],
|
||
),
|
||
) ),
|
||
);
|
||
}
|
||
|
||
Widget _buildDataTable(BuildContext context) {
|
||
if (filteredData.isEmpty) {
|
||
return const SizedBox(
|
||
height: 50,
|
||
child: Center(child: Text('No available data')),
|
||
);
|
||
}
|
||
|
||
final sortedData = [..._paginatedData];
|
||
|
||
return ListView.builder(
|
||
// itemCount: filteredData.length + 1, // +1 for header, +1 for pagination
|
||
itemCount: sortedData.length + 1, // +1 for header, +1 for pagination
|
||
itemBuilder: (context, index) {
|
||
if (index == 0) return _buildHeader();
|
||
// if (index == dataVal.length + 1)
|
||
// return _buildPagination(context);
|
||
final startIndex = ((currentPage - 1) * itemsPerPage);
|
||
// final item = filteredData[index - 1];
|
||
final item = sortedData[index - 1];
|
||
final sno = startIndex + index;
|
||
return _buildDataRow(item, sno);
|
||
},
|
||
);
|
||
}
|
||
|
||
Widget _buildHeader() {
|
||
return SizedBox.shrink();
|
||
}
|
||
|
||
Widget _buildDataRow(Map<String, dynamic> item, sno) {
|
||
return Container(
|
||
padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 16),
|
||
// margin: const EdgeInsets.only(top: 10),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
// color: Color(0xFFE0F7F9),
|
||
border: const Border(
|
||
bottom: BorderSide(color: Colors.blueGrey, width: 0.15),
|
||
),
|
||
// borderRadius: BorderRadius.circular(8),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
SizedBox(width: 50, child: Text('$sno' ?? '-', style: _dataBold)),
|
||
// Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)),
|
||
Expanded(
|
||
flex: 1,
|
||
child: Text(item['value'] ?? '-', style: _dataBold),
|
||
),
|
||
Expanded(
|
||
flex: 1,
|
||
child: Row(
|
||
children: [
|
||
Container(
|
||
// color: Colors.yellow.shade50,
|
||
child: Transform.scale(
|
||
scale: 0.4, // reduce size (0.7–0.9 works well)
|
||
child: Switch(
|
||
value: item['is_active'] == "1",
|
||
onChanged: (val) {
|
||
setState(() {
|
||
item['is_active'] = val ? "1" : "0";
|
||
});
|
||
final response = apiService.updateStatusMasters(
|
||
item['id'],
|
||
val ? "0" : "1",
|
||
'PaymentMode',
|
||
userId,
|
||
);
|
||
print("Response - $response");
|
||
},
|
||
activeColor: Color(0xFF2E7D6E), // thumb when active
|
||
// activeColor: Color(0xFF425B5B), // thumb when active
|
||
activeTrackColor: Color(0xFFDCFCE7), // track when active
|
||
// activeTrackColor: Color(0xFFB2D8D3), // track when active
|
||
inactiveThumbColor:
|
||
Colors.grey.shade400, // thumb when inactive
|
||
inactiveTrackColor:
|
||
Colors.grey.shade300, // track when inactive
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
|
||
Expanded(
|
||
flex: 1,
|
||
child: item['is_active'] == "1"
|
||
? Row(
|
||
children: [
|
||
Tooltip(
|
||
message: 'Edit',
|
||
child: IconButton(
|
||
icon: Image.asset(
|
||
"assets/miscellaneous/Edit.png",
|
||
height: 12,
|
||
width: 15,
|
||
),
|
||
onPressed: () {
|
||
print('EDITBrokwer - ${item['id']}');
|
||
print('EDITBrokwer - ${item}');
|
||
dynamic id = item['id'];
|
||
|
||
handleEdit(item);
|
||
|
||
print(item);
|
||
},
|
||
splashRadius: 28,
|
||
hoverColor: Colors.black12,
|
||
padding: const EdgeInsets.all(8),
|
||
constraints: const BoxConstraints(),
|
||
),
|
||
),
|
||
],
|
||
)
|
||
: Row(
|
||
children: [
|
||
Image.asset(
|
||
"assets/miscellaneous/Edit_muted.png",
|
||
height: 15,
|
||
width: 15,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Expanded(flex: 1, child: Text('', style: _dataBold)),
|
||
Expanded(flex: 1, child: Text('', style: _dataBold)),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
static final _dataBold = GoogleFonts.inter(
|
||
fontSize: 11.5,
|
||
fontWeight: FontWeight.w400,
|
||
color: Color(0xFF000000),
|
||
);
|
||
|
||
static final _dataSub = GoogleFonts.inter(
|
||
fontSize: 10,
|
||
fontWeight: FontWeight.w300,
|
||
color: Color(0xFF585757),
|
||
);
|
||
|
||
static final _headerStyle = GoogleFonts.poppins(
|
||
fontSize: 11.2,
|
||
fontWeight: FontWeight.w500,
|
||
color: Color(0xFF1E293B),
|
||
);
|
||
}
|