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, selectedValues: docController.selectedTag,
), ),
// --- Verified Toggle --- // --- Document Status ---
_buildField( _buildField(
"Only Verified", "Select Document Status",
Obx(() { Obx(() {
return Container( return Container(
padding: MySpacing.xy(12, 6), padding: MySpacing.all(12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.shade100, color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
@ -258,19 +258,51 @@ class UserDocumentFilterBottomSheet extends StatelessWidget {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
MyText( Row(
"Verified Documents Only", mainAxisSize: MainAxisSize.min,
style: MyTextStyle.bodyMedium(), children: [
Radio<bool?>(
value: null,
groupValue: docController.isVerified.value,
onChanged: (val) =>
docController.isVerified.value = val,
activeColor:
Colors.indigo,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
),
MyText("All"),
],
), ),
Switch( Row(
value: docController.isVerified.value ?? false, mainAxisSize: MainAxisSize.min,
onChanged: (val) { children: [
docController.isVerified.value = Radio<bool?>(
val ? true : null; value: true,
}, groupValue: docController.isVerified.value,
activeColor: Colors.indigo, onChanged: (val) =>
materialTapTargetSize: docController.isVerified.value = val,
MaterialTapTargetSize.shrinkWrap, 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) { Widget _buildDashboardStats(BuildContext context) {
return Obx(() { return Obx(() {
if (menuController.isLoading.value) { if (menuController.isLoading.value) {
return _buildLoadingSkeleton(context); return _buildLoadingSkeleton(context);
} }
if (menuController.hasError.value && menuController.menuItems.isEmpty) { if (menuController.hasError.value && menuController.menuItems.isEmpty) {
// Only show error if there are no menus at all
return Padding( return Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Center( child: Center(
@ -262,32 +262,40 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (!isProjectSelected) _buildNoProjectMessage(), if (!isProjectSelected) _buildNoProjectMessage(),
Wrap( LayoutBuilder(
spacing: 6, builder: (context, constraints) {
runSpacing: 6, // smaller width cards fit more in a row
children: stats int crossAxisCount = (constraints.maxWidth ~/ 80).clamp(2, 8);
.where((stat) { double cardWidth =
// Always allow Documents (constraints.maxWidth - (crossAxisCount - 1) * 6) /
if (stat.title == "Documents") return true; crossAxisCount;
// For all other menus, respect sidebar permissions return Wrap(
return menuController.isMenuAllowed(stat.title); spacing: 6,
}) runSpacing: 6,
.map((stat) => _buildStatCard(stat, isProjectSelected)) alignment: WrapAlignment.start,
.toList(), 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 + Small)
/// Stat Card (Compact with wrapping text) Widget _buildStatCard(
Widget _buildStatCard(_StatItem statItem, bool isProjectSelected) { _StatItem statItem, bool isProjectSelected, double width) {
const double cardWidth = 80; const double cardHeight = 60;
const double cardHeight = 70;
// Attendance should always be enabled
final bool isEnabled = statItem.title == "Attendance" || isProjectSelected; final bool isEnabled = statItem.title == "Attendance" || isProjectSelected;
return Opacity( return Opacity(
@ -296,30 +304,28 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
ignoring: !isEnabled, ignoring: !isEnabled,
child: InkWell( child: InkWell(
onTap: () => _handleStatCardTap(statItem, isEnabled), onTap: () => _handleStatCardTap(statItem, isEnabled),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(6),
child: MyCard.bordered( child: MyCard.bordered(
width: cardWidth, width: width,
height: cardHeight, height: cardHeight,
paddingAll: 4, paddingAll: 4,
borderRadiusAll: 8, borderRadiusAll: 6,
border: Border.all(color: Colors.grey.withOpacity(0.15)), border: Border.all(color: Colors.grey.withOpacity(0.15)),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
_buildStatCardIconCompact(statItem), _buildStatCardIconCompact(statItem, size: 12),
MySpacing.height(4), MySpacing.height(4),
Expanded( Flexible(
child: Center( child: Text(
child: Text( statItem.title,
statItem.title, textAlign: TextAlign.center,
textAlign: TextAlign.center, style: const TextStyle(
style: const TextStyle( fontSize: 8,
fontSize: 10, overflow: TextOverflow.visible,
overflow: TextOverflow.visible,
),
maxLines: 2,
softWrap: true,
), ),
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 /// Handle Tap
void _handleStatCardTap(_StatItem statItem, bool isEnabled) { void _handleStatCardTap(_StatItem statItem, bool isEnabled) {
if (!isEnabled) { if (!isEnabled) {
@ -346,21 +365,6 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
Get.toNamed(statItem.route); 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 { class _StatItem {