UI_DATE_FILTER_DYNM

This commit is contained in:
venbaittech 2025-10-08 09:47:40 +05:30
parent 4821c5f058
commit f76195ce8c
3 changed files with 316 additions and 58 deletions

View File

@ -17,6 +17,7 @@ import '../../providers/manager_provider.dart';
import '../../themes/indicators/date_field_theme.dart';
import '../../themes/indicators/export_btn.dart';
import '../../themes/indicators/search_field_theme.dart';
import '../../widgets/custom_Stdate_EnDate_Filter.dart';
import '../../widgets/custom_action_popup.dart';
class EnquiryList extends ConsumerStatefulWidget {
@ -69,7 +70,7 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
});
}
void filterDateRange() {
void filterDateRange1() {
print("filterDateRange");
// if (!_formKey.currentState!.validate()) return;
@ -80,6 +81,32 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
getStaffList(userId, roleId);
}
void filterDateRange() {
// Validate the form first
if (!_formKey.currentState!.validate()) {
// stop execution if validation fails
return;
}
final fromDateText = controllers['startDate']?.text ?? '';
final toDateText = controllers['endDate']?.text ?? '';
// Optional: double-check End >= Start
final fromDate = DateFormat('dd-MM-yyyy').parse(fromDateText);
final toDate = DateFormat('dd-MM-yyyy').parse(toDateText);
if (toDate.isBefore(fromDate)) {
// This is already caught by the validator, but extra safety
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("End Date cannot be earlier than Start Date")),
);
return;
}
// Call your API
getStaffList(userId, roleId);
}
void refrshfilterDateRange() {
setState(() {
controllers['startDate']!.clear();
@ -87,6 +114,8 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
controllers['startDate']?.text = '';
controllers['endDate']?.text = '';
// Reset the FormField validation
_formKey.currentState?.reset();
});
getStaffList(userId, roleId);
}
@ -363,42 +392,19 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
Container(
padding: EdgeInsets.all(8.0),
color: Color(0xffD9EBE8),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
buildStartDate(context),
SizedBox(height: 10),
buildEndDate(context),
// SizedBox(height: 10),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: filterDateRange,
child: Icon(
Icons.filter_list_outlined,
size: 18,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: refrshfilterDateRange,
child: Icon(Icons.refresh, size: 18),
),
),
],
),
],
),
child: DateFilterRow(
startController: controllers['startDate']!,
endController: controllers['endDate']!,
formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context),
onFilter: () {
// call your filter logic
filterDateRange();
},
onRefresh: () {
// call your refresh logic
refrshfilterDateRange();
},
),
),
],
@ -411,26 +417,57 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (!ResponsiveLayout.isMobile(context)) ...[
buildStartDate(context),
SizedBox(width: 10),
buildEndDate(context),
SizedBox(width: 10),
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: filterDateRange,
child: Icon(Icons.filter_list_outlined),
),
DateFilterRow(
startController: controllers['startDate']!,
endController: controllers['endDate']!,
formKey: _formKey,
isMobile: ResponsiveLayout.isMobile(context),
onFilter: () {
// call your filter logic
filterDateRange();
},
onRefresh: () {
// call your refresh logic
refrshfilterDateRange();
},
),
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: refrshfilterDateRange,
child: Icon(Icons.refresh),
),
),
// Form(
// key: _formKey,
// child: Row(
// mainAxisAlignment: MainAxisAlignment.start,
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// buildStartDate(context),
// SizedBox(width: 10),
// buildEndDate(context),
// SizedBox(width: 10),
//
// Padding(
// padding: const EdgeInsets.symmetric(
// vertical: 8.0,
// ),
// child: GestureDetector(
// // onTap: filterDateRange,
// onTap: () {
// if (_formKey.currentState!.validate()) {
// filterDateRange(); // only runs if valid
// }
// },
// child: Icon(Icons.filter_alt_outlined),
// ),
// ),
//
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: GestureDetector(
// onTap: refrshfilterDateRange,
// child: Icon(Icons.refresh),
// ),
// ),
// ],
// ),
// ),
Spacer(),
],
ThemedSearchField(
@ -949,8 +986,24 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
: MediaQuery.of(context).size.width * 0.16,
// txtheight: 50,
// backgroundColor: const Color(0xFFECECEC),
// validator: (value) => Validators.requiredField(value, "date"),
validator: (value) {
if (value == null || value.isEmpty) {
return "End Date is required";
}
final fromText = controllers['startDate']?.text ?? '';
if (fromText.isNotEmpty) {
final startDate = DateFormat('dd-MM-yyyy').parse(fromText);
final endDate = DateFormat('dd-MM-yyyy').parse(value);
if (endDate.isBefore(startDate)) {
return "End Date cannot be earlier than Start Date";
}
}
return null; // no error
},
controller: controllers['endDate']!,
lastDate: DateTime.now(),
onDateSelected: (date) {
print("Picked Date: $date");
controllers['endDate']?.text = DateFormat(

View File

@ -14,7 +14,8 @@ class ThemedDateField extends StatefulWidget {
this.errorBorderColor,
this.onDateSelected,
this.controller,
this.validator, // new
this.validator,
this.lastDate, // new
});
final String? hintText;
@ -26,6 +27,7 @@ class ThemedDateField extends StatefulWidget {
final TextEditingController? controller;
final Function(DateTime)? onDateSelected;
final String? Function(String? value)? validator; // new
final DateTime? lastDate;
@override
State<ThemedDateField> createState() => _ThemedDateFieldState();
@ -42,7 +44,8 @@ class _ThemedDateFieldState extends State<ThemedDateField> {
context: context,
initialDate: selectedDate ?? DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2100),
// lastDate: DateTime(2100),
lastDate: widget.lastDate ?? DateTime(2100),
initialEntryMode: DatePickerEntryMode.calendarOnly,
);

View File

@ -0,0 +1,202 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../layouts/responsive_layout.dart';
import '../themes/indicators/date_field_theme.dart';
class DateFilterRow extends StatelessWidget {
final TextEditingController startController;
final TextEditingController endController;
final VoidCallback onFilter;
final VoidCallback onRefresh;
final GlobalKey<FormState> formKey;
final bool isMobile;
const DateFilterRow({
super.key,
required this.startController,
required this.endController,
required this.onFilter,
required this.onRefresh,
required this.formKey,
this.isMobile = false,
});
@override
Widget build(BuildContext context) {
final spacing = 10.0;
// final rowChildren = [
// buildStartDate(context),
// SizedBox(width: spacing),
// buildEndDate(context),
// SizedBox(width: spacing),
// Padding(
// padding: const EdgeInsets.symmetric(vertical: 8.0),
// child: GestureDetector(
// onTap: () {
// if (formKey.currentState!.validate()) onFilter();
// },
// child: Icon(Icons.filter_alt_outlined),
// ),
// ),
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: GestureDetector(onTap: onRefresh, child: Icon(Icons.refresh)),
// ),
// ];
List<Widget> getRowChildren(bool isMobile, double spacing) {
final dateFields = [
buildStartDate(context),
SizedBox(width: spacing),
buildEndDate(context),
SizedBox(width: spacing),
];
final buttons = [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: GestureDetector(
onTap: () {
if (formKey.currentState!.validate()) onFilter();
},
child: Icon(Icons.filter_alt_outlined),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(onTap: onRefresh, child: Icon(Icons.refresh)),
),
];
if (isMobile) {
// For mobile: buttons below fields
return [
...dateFields,
SizedBox(height: 10),
Row(mainAxisAlignment: MainAxisAlignment.end, children: buttons),
];
} else {
// For desktop: buttons inline with fields
return [...dateFields, ...buttons];
}
}
return Form(
key: formKey,
child: isMobile
? Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: getRowChildren(isMobile, spacing),
)
: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: getRowChildren(isMobile, spacing),
),
);
}
Widget buildStartDate(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Start Date', style: _textStyle),
SizedBox(height: 5),
ThemedDateField(
hintText: "Select Date",
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.16,
// txtheight: 50,
// backgroundColor: const Color(0xFFECECEC),
// validator: (value) => Validators.requiredField(value, "date"),
controller: startController,
onDateSelected: (date) {
print("Picked Date: $date");
startController.text = DateFormat('dd-MM-yyyy').format(date);
// controllers['date']?.text = date as String;
},
),
],
);
}
Widget buildEndDate(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('End Date', style: _textStyle),
SizedBox(height: 5),
ThemedDateField(
hintText: "Select Date",
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.16,
// txtheight: 50,
// backgroundColor: const Color(0xFFECECEC),
validator: (value) {
if (value == null || value.isEmpty) {
return "End Date is required";
}
final fromText = startController.text ?? '';
if (fromText.isNotEmpty) {
final startDate = DateFormat('dd-MM-yyyy').parse(fromText);
final endDate = DateFormat('dd-MM-yyyy').parse(value);
if (endDate.isBefore(startDate)) {
return "End Date cannot be earlier than Start Date";
}
}
return null; // no error
},
controller: endController,
lastDate: DateTime.now(),
onDateSelected: (date) {
print("Picked Date: $date");
endController.text = DateFormat('dd-MM-yyyy').format(date);
// controllers['date']?.text = date as String;
},
),
],
);
}
static const _textStyle = TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
);
Widget buildStartDate1() {
return ThemedDateField(
controller: startController,
hintText: 'Select Start Date',
validator: (value) =>
value == null || value.isEmpty ? "Start Date required" : null,
onDateSelected: (date) =>
startController.text = DateFormat('dd-MM-yyyy').format(date),
);
}
Widget buildEndDate1() {
return ThemedDateField(
controller: endController,
hintText: 'Select End Date',
lastDate: DateTime.now(),
validator: (value) {
if (value == null || value.isEmpty) return "End Date required";
if (startController.text.isNotEmpty) {
final start = DateFormat('dd-MM-yyyy').parse(startController.text);
final end = DateFormat('dd-MM-yyyy').parse(value);
if (end.isBefore(start))
return "End Date cannot be earlier than Start Date";
}
return null;
},
onDateSelected: (date) =>
endController.text = DateFormat('dd-MM-yyyy').format(date),
);
}
}