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/date_field_theme.dart';
|
||||||
import '../../themes/indicators/export_btn.dart';
|
import '../../themes/indicators/export_btn.dart';
|
||||||
import '../../themes/indicators/search_field_theme.dart';
|
import '../../themes/indicators/search_field_theme.dart';
|
||||||
|
import '../../widgets/custom_Stdate_EnDate_Filter.dart';
|
||||||
import '../../widgets/custom_action_popup.dart';
|
import '../../widgets/custom_action_popup.dart';
|
||||||
|
|
||||||
class EnquiryList extends ConsumerStatefulWidget {
|
class EnquiryList extends ConsumerStatefulWidget {
|
||||||
@ -69,7 +70,7 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void filterDateRange() {
|
void filterDateRange1() {
|
||||||
print("filterDateRange");
|
print("filterDateRange");
|
||||||
// if (!_formKey.currentState!.validate()) return;
|
// if (!_formKey.currentState!.validate()) return;
|
||||||
|
|
||||||
@ -80,6 +81,32 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
getStaffList(userId, roleId);
|
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() {
|
void refrshfilterDateRange() {
|
||||||
setState(() {
|
setState(() {
|
||||||
controllers['startDate']!.clear();
|
controllers['startDate']!.clear();
|
||||||
@ -87,6 +114,8 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
|
|
||||||
controllers['startDate']?.text = '';
|
controllers['startDate']?.text = '';
|
||||||
controllers['endDate']?.text = '';
|
controllers['endDate']?.text = '';
|
||||||
|
// Reset the FormField validation
|
||||||
|
_formKey.currentState?.reset();
|
||||||
});
|
});
|
||||||
getStaffList(userId, roleId);
|
getStaffList(userId, roleId);
|
||||||
}
|
}
|
||||||
@ -363,42 +392,19 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
color: Color(0xffD9EBE8),
|
color: Color(0xffD9EBE8),
|
||||||
child: Form(
|
child: DateFilterRow(
|
||||||
key: _formKey,
|
startController: controllers['startDate']!,
|
||||||
child: Column(
|
endController: controllers['endDate']!,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
formKey: _formKey,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
isMobile: ResponsiveLayout.isMobile(context),
|
||||||
children: [
|
onFilter: () {
|
||||||
buildStartDate(context),
|
// call your filter logic
|
||||||
SizedBox(height: 10),
|
filterDateRange();
|
||||||
buildEndDate(context),
|
},
|
||||||
// SizedBox(height: 10),
|
onRefresh: () {
|
||||||
Row(
|
// call your refresh logic
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
refrshfilterDateRange();
|
||||||
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),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -411,26 +417,57 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (!ResponsiveLayout.isMobile(context)) ...[
|
if (!ResponsiveLayout.isMobile(context)) ...[
|
||||||
buildStartDate(context),
|
DateFilterRow(
|
||||||
SizedBox(width: 10),
|
startController: controllers['startDate']!,
|
||||||
buildEndDate(context),
|
endController: controllers['endDate']!,
|
||||||
SizedBox(width: 10),
|
formKey: _formKey,
|
||||||
|
isMobile: ResponsiveLayout.isMobile(context),
|
||||||
Padding(
|
onFilter: () {
|
||||||
padding: const EdgeInsets.all(8.0),
|
// call your filter logic
|
||||||
child: GestureDetector(
|
filterDateRange();
|
||||||
onTap: filterDateRange,
|
},
|
||||||
child: Icon(Icons.filter_list_outlined),
|
onRefresh: () {
|
||||||
),
|
// call your refresh logic
|
||||||
|
refrshfilterDateRange();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
Padding(
|
// Form(
|
||||||
padding: const EdgeInsets.all(8.0),
|
// key: _formKey,
|
||||||
child: GestureDetector(
|
// child: Row(
|
||||||
onTap: refrshfilterDateRange,
|
// mainAxisAlignment: MainAxisAlignment.start,
|
||||||
child: Icon(Icons.refresh),
|
// 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(),
|
Spacer(),
|
||||||
],
|
],
|
||||||
ThemedSearchField(
|
ThemedSearchField(
|
||||||
@ -949,8 +986,24 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
|
|||||||
: MediaQuery.of(context).size.width * 0.16,
|
: MediaQuery.of(context).size.width * 0.16,
|
||||||
// txtheight: 50,
|
// txtheight: 50,
|
||||||
// backgroundColor: const Color(0xFFECECEC),
|
// 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']!,
|
controller: controllers['endDate']!,
|
||||||
|
lastDate: DateTime.now(),
|
||||||
onDateSelected: (date) {
|
onDateSelected: (date) {
|
||||||
print("Picked Date: $date");
|
print("Picked Date: $date");
|
||||||
controllers['endDate']?.text = DateFormat(
|
controllers['endDate']?.text = DateFormat(
|
||||||
|
|||||||
@ -14,7 +14,8 @@ class ThemedDateField extends StatefulWidget {
|
|||||||
this.errorBorderColor,
|
this.errorBorderColor,
|
||||||
this.onDateSelected,
|
this.onDateSelected,
|
||||||
this.controller,
|
this.controller,
|
||||||
this.validator, // ✅ new
|
this.validator,
|
||||||
|
this.lastDate, // ✅ new
|
||||||
});
|
});
|
||||||
|
|
||||||
final String? hintText;
|
final String? hintText;
|
||||||
@ -26,6 +27,7 @@ class ThemedDateField extends StatefulWidget {
|
|||||||
final TextEditingController? controller;
|
final TextEditingController? controller;
|
||||||
final Function(DateTime)? onDateSelected;
|
final Function(DateTime)? onDateSelected;
|
||||||
final String? Function(String? value)? validator; // ✅ new
|
final String? Function(String? value)? validator; // ✅ new
|
||||||
|
final DateTime? lastDate;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ThemedDateField> createState() => _ThemedDateFieldState();
|
State<ThemedDateField> createState() => _ThemedDateFieldState();
|
||||||
@ -42,7 +44,8 @@ class _ThemedDateFieldState extends State<ThemedDateField> {
|
|||||||
context: context,
|
context: context,
|
||||||
initialDate: selectedDate ?? DateTime.now(),
|
initialDate: selectedDate ?? DateTime.now(),
|
||||||
firstDate: DateTime(2000),
|
firstDate: DateTime(2000),
|
||||||
lastDate: DateTime(2100),
|
// lastDate: DateTime(2100),
|
||||||
|
lastDate: widget.lastDate ?? DateTime(2100),
|
||||||
initialEntryMode: DatePickerEntryMode.calendarOnly,
|
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