From c9a46a1a714794e2e2bd692be00860fe7b1a0286 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Sat, 7 Mar 2026 02:47:55 -0500 Subject: [PATCH] feat: implement attire section toggles for required and non-essential items in AttirePage --- .../src/presentation/pages/attire_page.dart | 237 ++++++++++++++---- 1 file changed, 191 insertions(+), 46 deletions(-) diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/attire/lib/src/presentation/pages/attire_page.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/attire/lib/src/presentation/pages/attire_page.dart index 989033ab..fd8702a8 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/attire/lib/src/presentation/pages/attire_page.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/attire/lib/src/presentation/pages/attire_page.dart @@ -8,13 +8,20 @@ import 'package:krow_domain/krow_domain.dart'; import 'package:staff_attire/src/presentation/blocs/attire/attire_cubit.dart'; import 'package:staff_attire/src/presentation/blocs/attire/attire_state.dart'; -import '../widgets/attire_filter_chips.dart'; import '../widgets/attire_info_card.dart'; import '../widgets/attire_item_card.dart'; -class AttirePage extends StatelessWidget { +class AttirePage extends StatefulWidget { const AttirePage({super.key}); + @override + State createState() => _AttirePageState(); +} + +class _AttirePageState extends State { + bool _showRequired = true; + bool _showNonEssential = true; + @override Widget build(BuildContext context) { final AttireCubit cubit = Modular.get(); @@ -42,7 +49,12 @@ class AttirePage extends StatelessWidget { return const Center(child: CircularProgressIndicator()); } - final List filteredOptions = state.filteredOptions; + final List requiredItems = state.options + .where((AttireItem item) => item.isMandatory) + .toList(); + final List nonEssentialItems = state.options + .where((AttireItem item) => !item.isMandatory) + .toList(); return Column( children: [ @@ -55,55 +67,110 @@ class AttirePage extends StatelessWidget { const AttireInfoCard(), const SizedBox(height: UiConstants.space6), - // Filter Chips - AttireFilterChips( - selectedFilter: state.filter, - onFilterChanged: cubit.updateFilter, + // Section toggle chips + Row( + children: [ + _SectionTab( + label: 'Required', + isSelected: _showRequired, + onTap: () => setState( + () => _showRequired = !_showRequired, + ), + ), + const SizedBox(width: UiConstants.space3), + _SectionTab( + label: 'Non-Essential', + isSelected: _showNonEssential, + onTap: () => setState( + () => _showNonEssential = !_showNonEssential, + ), + ), + ], ), const SizedBox(height: UiConstants.space6), - // Item List - if (filteredOptions.isEmpty) - Padding( - padding: const EdgeInsets.symmetric( - vertical: UiConstants.space10, - ), - child: Center( - child: Column( - children: [ - const Icon( - UiIcons.shirt, - size: 48, - color: UiColors.iconInactive, - ), - const SizedBox(height: UiConstants.space4), - Text( - context.t.staff_profile_attire.capture.no_items_filter, - style: UiTypography.body1m.textSecondary, - ), - ], - ), + // Required section + if (_showRequired) ...[ + _SectionHeader( + title: 'Required', + count: requiredItems.length, + ), + const SizedBox(height: UiConstants.space3), + if (requiredItems.isEmpty) + _EmptySection( + message: context + .t + .staff_profile_attire + .capture + .no_items_filter, + ) + else + ...requiredItems.map((AttireItem item) { + return Padding( + padding: const EdgeInsets.only( + bottom: UiConstants.space3, + ), + child: AttireItemCard( + item: item, + isUploading: false, + uploadedPhotoUrl: state.photoUrls[item.id], + onTap: () { + Modular.to.toAttireCapture( + item: item, + initialPhotoUrl: state.photoUrls[item.id], + ); + }, + ), + ); + }), + ], + + // Divider between sections + if (_showRequired && _showNonEssential) + const Padding( + padding: EdgeInsets.symmetric( + vertical: UiConstants.space8, ), + child: Divider(), ) else - ...filteredOptions.map((AttireItem item) { - return Padding( - padding: const EdgeInsets.only( - bottom: UiConstants.space3, - ), - child: AttireItemCard( - item: item, - isUploading: false, - uploadedPhotoUrl: state.photoUrls[item.id], - onTap: () { - Modular.to.toAttireCapture( - item: item, - initialPhotoUrl: state.photoUrls[item.id], - ); - }, - ), - ); - }), + const SizedBox(height: UiConstants.space6), + + // Non-Essential section + if (_showNonEssential) ...[ + _SectionHeader( + title: 'Non-Essential', + count: nonEssentialItems.length, + ), + const SizedBox(height: UiConstants.space3), + if (nonEssentialItems.isEmpty) + _EmptySection( + message: context + .t + .staff_profile_attire + .capture + .no_items_filter, + ) + else + ...nonEssentialItems.map((AttireItem item) { + return Padding( + padding: const EdgeInsets.only( + bottom: UiConstants.space3, + ), + child: AttireItemCard( + item: item, + isUploading: false, + uploadedPhotoUrl: state.photoUrls[item.id], + onTap: () { + Modular.to.toAttireCapture( + item: item, + initialPhotoUrl: state.photoUrls[item.id], + ); + }, + ), + ); + }), + ], const SizedBox(height: UiConstants.space20), ], ), @@ -117,3 +184,81 @@ class AttirePage extends StatelessWidget { ); } } + +class _SectionTab extends StatelessWidget { + const _SectionTab({ + required this.label, + required this.isSelected, + required this.onTap, + }); + + final String label; + final bool isSelected; + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: UiConstants.space4, + vertical: UiConstants.space2, + ), + decoration: BoxDecoration( + color: isSelected ? UiColors.primary : UiColors.white, + borderRadius: UiConstants.radiusFull, + border: Border.all( + color: isSelected ? UiColors.primary : UiColors.border, + ), + ), + child: Text( + label, + style: isSelected + ? UiTypography.footnote2m.white + : UiTypography.footnote2m.textSecondary, + ), + ), + ); + } +} + +class _SectionHeader extends StatelessWidget { + const _SectionHeader({required this.title, required this.count}); + + final String title; + final int count; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Text(title, style: UiTypography.headline4b), + const SizedBox(width: UiConstants.space2), + Text('($count)', style: UiTypography.body1m.textSecondary), + ], + ); + } +} + +class _EmptySection extends StatelessWidget { + const _EmptySection({required this.message}); + + final String message; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: UiConstants.space6), + child: Center( + child: Column( + children: [ + const Icon(UiIcons.shirt, size: 48, color: UiColors.iconInactive), + const SizedBox(height: UiConstants.space4), + Text(message, style: UiTypography.body1m.textSecondary), + ], + ), + ), + ); + } +}