UI_DATE_FILTER_DYNM
This commit is contained in:
parent
4821c5f058
commit
f76195ce8c
@ -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(
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
|
||||
202
lib/presentation/widgets/custom_Stdate_EnDate_Filter.dart
Normal file
202
lib/presentation/widgets/custom_Stdate_EnDate_Filter.dart
Normal 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),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user