feat: Update User Document Filter to use radio buttons for document status selection

This commit is contained in:
Vaibhav Surve 2025-09-19 17:49:27 +05:30
parent 8c99ba287f
commit ae7ce851ee
2 changed files with 101 additions and 65 deletions

View File

@ -244,12 +244,12 @@ class UserDocumentFilterBottomSheet extends StatelessWidget {
selectedValues: docController.selectedTag,
),
// --- Verified Toggle ---
// --- Document Status ---
_buildField(
"Only Verified",
"Select Document Status",
Obx(() {
return Container(
padding: MySpacing.xy(12, 6),
padding: MySpacing.all(12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
@ -258,19 +258,51 @@ class UserDocumentFilterBottomSheet extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText(
"Verified Documents Only",
style: MyTextStyle.bodyMedium(),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Radio<bool?>(
value: null,
groupValue: docController.isVerified.value,
onChanged: (val) =>
docController.isVerified.value = val,
activeColor:
Colors.indigo,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
),
MyText("All"),
],
),
Switch(
value: docController.isVerified.value ?? false,
onChanged: (val) {
docController.isVerified.value =
val ? true : null;
},
activeColor: Colors.indigo,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Radio<bool?>(
value: true,
groupValue: docController.isVerified.value,
onChanged: (val) =>
docController.isVerified.value = val,
activeColor: Colors.indigo,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
),
MyText("Verified"),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Radio<bool?>(
value: false,
groupValue: docController.isVerified.value,
onChanged: (val) =>
docController.isVerified.value = val,
activeColor: Colors.indigo,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
),
MyText("Rejected"),
],
),
],
),

View File

@ -219,14 +219,14 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
);
}
/// Dashboard Statistics Section with Compact Cards
/// Dashboard Statistics Section
Widget _buildDashboardStats(BuildContext context) {
return Obx(() {
if (menuController.isLoading.value) {
return _buildLoadingSkeleton(context);
}
if (menuController.hasError.value && menuController.menuItems.isEmpty) {
// Only show error if there are no menus at all
return Padding(
padding: const EdgeInsets.all(16),
child: Center(
@ -262,32 +262,40 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!isProjectSelected) _buildNoProjectMessage(),
Wrap(
spacing: 6,
runSpacing: 6,
children: stats
.where((stat) {
// Always allow Documents
if (stat.title == "Documents") return true;
LayoutBuilder(
builder: (context, constraints) {
// smaller width cards fit more in a row
int crossAxisCount = (constraints.maxWidth ~/ 80).clamp(2, 8);
double cardWidth =
(constraints.maxWidth - (crossAxisCount - 1) * 6) /
crossAxisCount;
// For all other menus, respect sidebar permissions
return menuController.isMenuAllowed(stat.title);
})
.map((stat) => _buildStatCard(stat, isProjectSelected))
.toList(),
return Wrap(
spacing: 6,
runSpacing: 6,
alignment: WrapAlignment.start,
children: stats
.where((stat) {
if (stat.title == "Documents") return true;
return menuController.isMenuAllowed(stat.title);
})
.map((stat) =>
_buildStatCard(stat, isProjectSelected, cardWidth))
.toList()
.cast<Widget>(),
);
},
),
],
);
});
}
/// Stat Card (Compact with wrapping text)
/// Stat Card (Compact with wrapping text)
Widget _buildStatCard(_StatItem statItem, bool isProjectSelected) {
const double cardWidth = 80;
const double cardHeight = 70;
/// Stat Card (Compact + Small)
Widget _buildStatCard(
_StatItem statItem, bool isProjectSelected, double width) {
const double cardHeight = 60;
// Attendance should always be enabled
final bool isEnabled = statItem.title == "Attendance" || isProjectSelected;
return Opacity(
@ -296,30 +304,28 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
ignoring: !isEnabled,
child: InkWell(
onTap: () => _handleStatCardTap(statItem, isEnabled),
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(6),
child: MyCard.bordered(
width: cardWidth,
width: width,
height: cardHeight,
paddingAll: 4,
borderRadiusAll: 8,
borderRadiusAll: 6,
border: Border.all(color: Colors.grey.withOpacity(0.15)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildStatCardIconCompact(statItem),
_buildStatCardIconCompact(statItem, size: 12),
MySpacing.height(4),
Expanded(
child: Center(
child: Text(
statItem.title,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 10,
overflow: TextOverflow.visible,
),
maxLines: 2,
softWrap: true,
Flexible(
child: Text(
statItem.title,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 8,
overflow: TextOverflow.visible,
),
maxLines: 2,
softWrap: true,
),
),
],
@ -330,6 +336,19 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
);
}
/// Compact Icon (smaller)
Widget _buildStatCardIconCompact(_StatItem statItem, {double size = 12}) {
return MyContainer.rounded(
paddingAll: 4,
color: statItem.color.withOpacity(0.1),
child: Icon(
statItem.icon,
size: size,
color: statItem.color,
),
);
}
/// Handle Tap
void _handleStatCardTap(_StatItem statItem, bool isEnabled) {
if (!isEnabled) {
@ -346,21 +365,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
Get.toNamed(statItem.route);
}
}
/// Compact Icon
Widget _buildStatCardIconCompact(_StatItem statItem) {
return MyContainer.rounded(
paddingAll: 6,
color: statItem.color.withOpacity(0.1),
child: Icon(
statItem.icon,
size: 14,
color: statItem.color,
),
);
}
/// Handle Tap
}
class _StatItem {