From 4f94bf6835eceed4e076dfd3341f3d5c5ad85b98 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Tue, 10 Feb 2026 15:34:52 -0500 Subject: [PATCH] feat: Refactor mobile UI components to adhere to design system tokens and improve loading and snackbar functionalities --- apps/mobile/NEXT_SPRINT_TASKS.md | 9 +- .../design_system/lib/design_system.dart | 2 + .../design_system/lib/src/ui_colors.dart | 2 +- .../design_system/lib/src/ui_icons.dart | 9 + .../lib/src/widgets/ui_loading_page.dart | 33 +++ .../lib/src/widgets/ui_snackbar.dart | 99 ++++++++ .../presentation/pages/availability_page.dart | 221 ++++++++---------- .../features/staff/availability/pubspec.yaml | 16 +- 8 files changed, 259 insertions(+), 132 deletions(-) create mode 100644 apps/mobile/packages/design_system/lib/src/widgets/ui_loading_page.dart create mode 100644 apps/mobile/packages/design_system/lib/src/widgets/ui_snackbar.dart diff --git a/apps/mobile/NEXT_SPRINT_TASKS.md b/apps/mobile/NEXT_SPRINT_TASKS.md index 8f88959e..790e32cf 100644 --- a/apps/mobile/NEXT_SPRINT_TASKS.md +++ b/apps/mobile/NEXT_SPRINT_TASKS.md @@ -28,10 +28,13 @@ - track minimum shift hours in the staff profile and show a warning if they try to apply for shifts that are below their minimum hours. - this need to be added in the BE and also a FE validation (5 hrs). + - Cannot cancel before 24 hours of the shift start time. If do we should charge for 4 hours of work for each shifts. + - verify the order creation process in the client app. - Vendor don't need to verify the order, when the order is created it should be automatically published. - rethink the order status, we need to simplify it. + - Validation layer - Profile info - emergency contact @@ -43,4 +46,8 @@ - there should be manual verification by the client even if the ai verification is passed. - to track false positives and false negatives. - documents - - tax forms \ No newline at end of file + - tax forms + +- How do we handle the current bank account verifcaiton in the current legacy application. +- We need have a show a list of clothing items in the staff app -> shift page. +- Template models for the pdf reports in the client and web apps. \ No newline at end of file diff --git a/apps/mobile/packages/design_system/lib/design_system.dart b/apps/mobile/packages/design_system/lib/design_system.dart index a20a8d7c..b447dd7b 100644 --- a/apps/mobile/packages/design_system/lib/design_system.dart +++ b/apps/mobile/packages/design_system/lib/design_system.dart @@ -12,3 +12,5 @@ export 'src/widgets/ui_button.dart'; export 'src/widgets/ui_chip.dart'; export 'src/widgets/ui_error_snackbar.dart'; export 'src/widgets/ui_success_snackbar.dart'; +export 'src/widgets/ui_loading_page.dart'; +export 'src/widgets/ui_snackbar.dart'; diff --git a/apps/mobile/packages/design_system/lib/src/ui_colors.dart b/apps/mobile/packages/design_system/lib/src/ui_colors.dart index 2462d0f3..30a56dc3 100644 --- a/apps/mobile/packages/design_system/lib/src/ui_colors.dart +++ b/apps/mobile/packages/design_system/lib/src/ui_colors.dart @@ -120,7 +120,7 @@ class UiColors { static const Color textDescription = mutedForeground; /// Success text (#10B981) - static const Color textSuccess = Color(0xFF10B981); + static const Color textSuccess = Color(0xFF0A8159); /// Error text (#F04444) static const Color textError = destructive; diff --git a/apps/mobile/packages/design_system/lib/src/ui_icons.dart b/apps/mobile/packages/design_system/lib/src/ui_icons.dart index d5c9b139..aa4c2e74 100644 --- a/apps/mobile/packages/design_system/lib/src/ui_icons.dart +++ b/apps/mobile/packages/design_system/lib/src/ui_icons.dart @@ -225,4 +225,13 @@ class UiIcons { /// Globe icon static const IconData globe = _IconLib.globe; + + /// Sunrise icon + static const IconData sunrise = _IconLib.sunrise; + + /// Sun icon + static const IconData sun = _IconLib.sun; + + /// Moon icon + static const IconData moon = _IconLib.moon; } diff --git a/apps/mobile/packages/design_system/lib/src/widgets/ui_loading_page.dart b/apps/mobile/packages/design_system/lib/src/widgets/ui_loading_page.dart new file mode 100644 index 00000000..9d59ebbe --- /dev/null +++ b/apps/mobile/packages/design_system/lib/src/widgets/ui_loading_page.dart @@ -0,0 +1,33 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import '../ui_colors.dart'; + +/// A common loading page that adheres to the design system. +/// It features a blurred background using [UiColors.popupShadow] and a [CircularProgressIndicator]. +class UiLoadingPage extends StatelessWidget { + /// Creates a [UiLoadingPage]. + const UiLoadingPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: UiColors.transparent, + body: Stack( + fit: StackFit.expand, + children: [ + // Background blur and color + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Container(color: UiColors.popupShadow), + ), + ), + // Center loading indicator + const Center(child: CircularProgressIndicator()), + ], + ), + ); + } +} diff --git a/apps/mobile/packages/design_system/lib/src/widgets/ui_snackbar.dart b/apps/mobile/packages/design_system/lib/src/widgets/ui_snackbar.dart new file mode 100644 index 00000000..25ca55d0 --- /dev/null +++ b/apps/mobile/packages/design_system/lib/src/widgets/ui_snackbar.dart @@ -0,0 +1,99 @@ +import 'dart:ui'; +import 'package:flutter/material.dart'; +import '../ui_colors.dart'; +import '../ui_icons.dart'; +import '../ui_typography.dart'; + +/// Types of snackbars available in the design system. +enum UiSnackbarType { + /// Success state - green text and light blurred green background. + success, + + /// Message state - blue text and light blurred blue background. + message, + + /// Warning state - dark yellow text and light blurred yellow background. + warning, + + /// Error state - red text and light blurred red background. + error, +} + +/// A centralized snackbar widget that adheres to the design system with glassmorphism effects. +class UiSnackbar { + UiSnackbar._(); + + /// Shows a snackbar with the specified [message] and [type]. + static void show( + BuildContext context, { + required String message, + required UiSnackbarType type, + Duration duration = const Duration(seconds: 3), + }) { + final Color textColor; + final Color backgroundColor; + final IconData icon; + + switch (type) { + case UiSnackbarType.success: + textColor = UiColors.textSuccess; + backgroundColor = UiColors.tagSuccess.withValues(alpha: 0.7); + icon = UiIcons.success; + break; + case UiSnackbarType.message: + textColor = UiColors.primary; + backgroundColor = UiColors.tagInProgress.withValues(alpha: 0.7); + icon = UiIcons.info; + break; + case UiSnackbarType.warning: + textColor = UiColors.textWarning; + backgroundColor = UiColors.tagPending.withValues(alpha: 0.7); + icon = UiIcons.warning; + break; + case UiSnackbarType.error: + textColor = UiColors.textError; + backgroundColor = UiColors.tagError.withValues(alpha: 0.7); + icon = UiIcons.error; + break; + } + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + duration: duration, + backgroundColor: UiColors.transparent, + elevation: 0, + behavior: SnackBarBehavior.floating, + content: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: textColor.withValues(alpha: 0.2), + width: 1, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + spacing: 12, + children: [ + Icon(icon, color: textColor, size: 20), + Expanded( + child: Text( + message, + style: UiTypography.body2b.copyWith(color: textColor), + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/apps/mobile/packages/features/staff/availability/lib/src/presentation/pages/availability_page.dart b/apps/mobile/packages/features/staff/availability/lib/src/presentation/pages/availability_page.dart index 91fc33ee..8725ceac 100644 --- a/apps/mobile/packages/features/staff/availability/lib/src/presentation/pages/availability_page.dart +++ b/apps/mobile/packages/features/staff/availability/lib/src/presentation/pages/availability_page.dart @@ -1,9 +1,9 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_modular/flutter_modular.dart' hide ModularWatchExtension; +import 'package:flutter_modular/flutter_modular.dart' + hide ModularWatchExtension; import 'package:intl/intl.dart'; -import 'package:lucide_icons/lucide_icons.dart'; import '../blocs/availability_bloc.dart'; import '../blocs/availability_event.dart'; @@ -44,7 +44,6 @@ class _AvailabilityPageState extends State { return BlocProvider.value( value: _bloc, child: Scaffold( - backgroundColor: AppColors.krowBackground, appBar: UiAppBar( title: 'My Availability', centerTitle: false, @@ -53,13 +52,18 @@ class _AvailabilityPageState extends State { body: BlocListener( listener: (context, state) { if (state is AvailabilityLoaded && state.successMessage != null) { - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(state.successMessage!), - backgroundColor: Colors.green, - behavior: SnackBarBehavior.floating, - ), + UiSnackbar.show( + context, + message: state.successMessage!, + type: UiSnackbarType.success, + ); + } + + if (state is AvailabilityError) { + UiSnackbar.show( + context, + message: state.message, + type: UiSnackbarType.error, ); } }, @@ -78,16 +82,14 @@ class _AvailabilityPageState extends State { padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, + spacing: 24, children: [ _buildQuickSet(context), - const SizedBox(height: 24), _buildWeekNavigation(context, state), - const SizedBox(height: 24), _buildSelectedDayAvailability( context, state.selectedDayAvailability, ), - const SizedBox(height: 24), _buildInfoCard(), ], ), @@ -96,12 +98,7 @@ class _AvailabilityPageState extends State { ), ), if (state.isActionInProgress) - Container( - color: Colors.black.withOpacity(0.3), - child: const Center( - child: CircularProgressIndicator(), - ), - ), + const UiLoadingPage(), // Show loading overlay during actions ], ); } else if (state is AvailabilityError) { @@ -119,45 +116,27 @@ class _AvailabilityPageState extends State { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.1), + color: UiColors.primary.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( + Text( 'Quick Set Availability', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF333F48), - ), + style: UiTypography.body4r.copyWith(color: UiColors.textFilter), ), const SizedBox(height: 12), Row( children: [ + Expanded(child: _buildQuickSetButton(context, 'All Week', 'all')), + const SizedBox(width: 8), Expanded( - child: _buildQuickSetButton( - context, - 'All Week', - 'all', - ), + child: _buildQuickSetButton(context, 'Weekdays', 'weekdays'), ), const SizedBox(width: 8), Expanded( - child: _buildQuickSetButton( - context, - 'Weekdays', - 'weekdays', - ), - ), - const SizedBox(width: 8), - Expanded( - child: _buildQuickSetButton( - context, - 'Weekends', - 'weekends', - ), + child: _buildQuickSetButton(context, 'Weekends', 'weekends'), ), const SizedBox(width: 8), Expanded( @@ -184,23 +163,24 @@ class _AvailabilityPageState extends State { return SizedBox( height: 32, child: OutlinedButton( - onPressed: () => context.read().add(PerformQuickSet(type)), + onPressed: () => + context.read().add(PerformQuickSet(type)), style: OutlinedButton.styleFrom( padding: EdgeInsets.zero, side: BorderSide( color: isDestructive - ? Colors.red.withOpacity(0.2) - : AppColors.krowBlue.withOpacity(0.2), + ? UiColors.destructive.withValues(alpha: 0.2) + : UiColors.primary.withValues(alpha: 0.2), ), - backgroundColor: Colors.transparent, + backgroundColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), - foregroundColor: isDestructive ? Colors.red : AppColors.krowBlue, + foregroundColor: isDestructive ? UiColors.destructive : UiColors.primary, ), child: Text( label, - style: const TextStyle(fontSize: 10, fontWeight: FontWeight.w500), + style: UiTypography.body4r, maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -221,7 +201,7 @@ class _AvailabilityPageState extends State { border: Border.all(color: Colors.grey.shade100), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.05), + color: UiColors.black.withValues(alpha: 0.05), blurRadius: 2, offset: const Offset(0, 1), ), @@ -236,20 +216,24 @@ class _AvailabilityPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildNavButton( - LucideIcons.chevronLeft, - () => context.read().add(const NavigateWeek(-1)), + UiIcons.chevronLeft, + () => context.read().add( + const NavigateWeek(-1), + ), ), Text( monthYear, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, + color: UiColors.foreground, ), ), _buildNavButton( - LucideIcons.chevronRight, - () => context.read().add(const NavigateWeek(1)), + UiIcons.chevronRight, + () => context.read().add( + const NavigateWeek(1), + ), ), ], ), @@ -257,7 +241,9 @@ class _AvailabilityPageState extends State { // Days Row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: state.days.map((day) => _buildDayItem(context, day, state.selectedDate)).toList(), + children: state.days + .map((day) => _buildDayItem(context, day, state.selectedDate)) + .toList(), ), ], ), @@ -274,12 +260,16 @@ class _AvailabilityPageState extends State { color: Color(0xFFF1F5F9), // slate-100 shape: BoxShape.circle, ), - child: Icon(icon, size: 20, color: AppColors.krowMuted), + child: Icon(icon, size: 20, color: UiColors.mutedForeground), ), ); } - Widget _buildDayItem(BuildContext context, DayAvailability day, DateTime selectedDate) { + Widget _buildDayItem( + BuildContext context, + DayAvailability day, + DateTime selectedDate, + ) { final isSelected = AvailabilityLoaded.isSameDay(day.date, selectedDate); final isAvailable = day.isAvailable; final isToday = AvailabilityLoaded.isSameDay(day.date, DateTime.now()); @@ -292,22 +282,22 @@ class _AvailabilityPageState extends State { padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: isSelected - ? AppColors.krowBlue + ? UiColors.primary : (isAvailable - ? const Color(0xFFECFDF5) - : const Color(0xFFF8FAFC)), // emerald-50 or slate-50 + ? const Color(0xFFECFDF5) + : const Color(0xFFF8FAFC)), // emerald-50 or slate-50 borderRadius: BorderRadius.circular(16), border: Border.all( color: isSelected - ? AppColors.krowBlue + ? UiColors.primary : (isAvailable - ? const Color(0xFFA7F3D0) - : Colors.transparent), // emerald-200 + ? const Color(0xFFA7F3D0) + : Colors.transparent), // emerald-200 ), boxShadow: isSelected ? [ BoxShadow( - color: AppColors.krowBlue.withOpacity(0.3), + color: UiColors.primary.withValues(alpha: 0.3), blurRadius: 8, offset: const Offset(0, 4), ), @@ -326,22 +316,22 @@ class _AvailabilityPageState extends State { fontSize: 18, fontWeight: FontWeight.bold, color: isSelected - ? Colors.white + ? UiColors.white : (isAvailable - ? const Color(0xFF047857) - : AppColors.krowMuted), // emerald-700 + ? const Color(0xFF047857) + : UiColors.mutedForeground), // emerald-700 ), ), const SizedBox(height: 2), Text( - DateFormat('EEE').format(day.date), + DateFormat('EEE').format(day.date), style: TextStyle( fontSize: 10, color: isSelected - ? Colors.white.withOpacity(0.8) + ? UiColors.white.withValues(alpha: 0.8) : (isAvailable - ? const Color(0xFF047857) - : AppColors.krowMuted), + ? const Color(0xFF047857) + : UiColors.mutedForeground), ), ), ], @@ -353,7 +343,7 @@ class _AvailabilityPageState extends State { width: 6, height: 6, decoration: const BoxDecoration( - color: AppColors.krowBlue, + color: UiColors.primary, shape: BoxShape.circle, ), ), @@ -380,7 +370,7 @@ class _AvailabilityPageState extends State { border: Border.all(color: Colors.grey.shade100), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.05), + color: UiColors.black.withValues(alpha: 0.05), blurRadius: 2, offset: const Offset(0, 1), ), @@ -400,22 +390,23 @@ class _AvailabilityPageState extends State { style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, + color: UiColors.foreground, ), ), Text( isAvailable ? 'You are available' : 'Not available', style: const TextStyle( fontSize: 14, - color: AppColors.krowMuted, + color: UiColors.mutedForeground, ), ), ], ), Switch( value: isAvailable, - onChanged: (val) => context.read().add(ToggleDayStatus(day)), - activeColor: AppColors.krowBlue, + onChanged: (val) => + context.read().add(ToggleDayStatus(day)), + activeColor: UiColors.primary, ), ], ), @@ -426,37 +417,37 @@ class _AvailabilityPageState extends State { ...day.slots.map((slot) { // Get UI config for this slot ID final uiConfig = _getSlotUiConfig(slot.id); - + return _buildTimeSlotItem(context, day, slot, uiConfig); }).toList(), ], ), ); } - + Map _getSlotUiConfig(String slotId) { switch (slotId) { case 'morning': return { - 'icon': LucideIcons.sunrise, + 'icon': UiIcons.sunrise, 'bg': const Color(0xFFE6EBF9), // bg-[#0032A0]/10 'iconColor': const Color(0xFF0032A0), }; case 'afternoon': return { - 'icon': LucideIcons.sun, + 'icon': UiIcons.sun, 'bg': const Color(0xFFCCD6EC), // bg-[#0032A0]/20 'iconColor': const Color(0xFF0032A0), }; case 'evening': return { - 'icon': LucideIcons.moon, + 'icon': UiIcons.moon, 'bg': const Color(0xFFEBEDEE), // bg-[#333F48]/10 'iconColor': const Color(0xFF333F48), }; default: return { - 'icon': LucideIcons.clock, + 'icon': UiIcons.clock, 'bg': Colors.grey.shade100, 'iconColor': Colors.grey, }; @@ -464,15 +455,15 @@ class _AvailabilityPageState extends State { } Widget _buildTimeSlotItem( - BuildContext context, - DayAvailability day, - AvailabilitySlot slot, - Map uiConfig + BuildContext context, + DayAvailability day, + AvailabilitySlot slot, + Map uiConfig, ) { // Determine styles based on state - final isEnabled = day.isAvailable; + final isEnabled = day.isAvailable; final isActive = slot.isAvailable; - + // Container style Color bgColor; Color borderColor; @@ -481,8 +472,8 @@ class _AvailabilityPageState extends State { bgColor = const Color(0xFFF8FAFC); // slate-50 borderColor = const Color(0xFFF1F5F9); // slate-100 } else if (isActive) { - bgColor = AppColors.krowBlue.withOpacity(0.05); - borderColor = AppColors.krowBlue.withOpacity(0.2); + bgColor = UiColors.primary.withValues(alpha: 0.05); + borderColor = UiColors.primary.withValues(alpha: 0.2); } else { bgColor = const Color(0xFFF8FAFC); // slate-50 borderColor = const Color(0xFFE2E8F0); // slate-200 @@ -490,14 +481,18 @@ class _AvailabilityPageState extends State { // Text colors final titleColor = (isEnabled && isActive) - ? AppColors.krowCharcoal - : AppColors.krowMuted; + ? UiColors.foreground + : UiColors.mutedForeground; final subtitleColor = (isEnabled && isActive) - ? AppColors.krowMuted + ? UiColors.mutedForeground : Colors.grey.shade400; return GestureDetector( - onTap: isEnabled ? () => context.read().add(ToggleSlotStatus(day, slot.id)) : null, + onTap: isEnabled + ? () => context.read().add( + ToggleSlotStatus(day, slot.id), + ) + : null, child: AnimatedContainer( duration: const Duration(milliseconds: 200), margin: const EdgeInsets.only(bottom: 12), @@ -539,10 +534,7 @@ class _AvailabilityPageState extends State { ), Text( slot.timeRange, - style: TextStyle( - fontSize: 12, - color: subtitleColor, - ), + style: TextStyle(fontSize: 12, color: subtitleColor), ), ], ), @@ -553,14 +545,10 @@ class _AvailabilityPageState extends State { width: 24, height: 24, decoration: const BoxDecoration( - color: AppColors.krowBlue, + color: UiColors.primary, shape: BoxShape.circle, ), - child: const Icon( - LucideIcons.check, - size: 16, - color: Colors.white, - ), + child: const Icon(UiIcons.check, size: 16, color: UiColors.white), ) else if (isEnabled && !isActive) Container( @@ -584,13 +572,13 @@ class _AvailabilityPageState extends State { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.05), + color: UiColors.primary.withValues(alpha: 0.05), borderRadius: BorderRadius.circular(12), ), child: const Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon(LucideIcons.clock, size: 20, color: AppColors.krowBlue), + Icon(UiIcons.clock, size: 20, color: UiColors.primary), SizedBox(width: 12), Expanded( child: Column( @@ -601,13 +589,13 @@ class _AvailabilityPageState extends State { style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, + color: UiColors.foreground, ), ), SizedBox(height: 2), Text( "When enabled, you'll only be matched with shifts during your available times.", - style: TextStyle(fontSize: 12, color: AppColors.krowMuted), + style: TextStyle(fontSize: 12, color: UiColors.mutedForeground), ), ], ), @@ -618,14 +606,3 @@ class _AvailabilityPageState extends State { } } -class AppColors { - static const Color krowBlue = Color(0xFF0A39DF); - static const Color krowYellow = Color(0xFFFFED4A); - static const Color krowCharcoal = Color(0xFF121826); - static const Color krowMuted = Color(0xFF6A7382); - static const Color krowBorder = Color(0xFFE3E6E9); - static const Color krowBackground = Color(0xFFFAFBFC); - - static const Color white = Colors.white; - static const Color black = Colors.black; -} diff --git a/apps/mobile/packages/features/staff/availability/pubspec.yaml b/apps/mobile/packages/features/staff/availability/pubspec.yaml index fe5ef376..b8353e1a 100644 --- a/apps/mobile/packages/features/staff/availability/pubspec.yaml +++ b/apps/mobile/packages/features/staff/availability/pubspec.yaml @@ -1,22 +1,17 @@ name: staff_availability description: Staff Availability Feature version: 0.0.1 -publish_to: 'none' +publish_to: "none" resolution: workspace environment: - sdk: '>=3.10.0 <4.0.0' + sdk: ">=3.10.0 <4.0.0" flutter: ">=1.17.0" dependencies: flutter: sdk: flutter - flutter_bloc: ^8.1.3 - equatable: ^2.0.5 - intl: ^0.20.0 - lucide_icons: ^0.257.0 - flutter_modular: ^6.3.2 - + # Internal packages core_localization: path: ../../../core_localization @@ -28,6 +23,11 @@ dependencies: path: ../../../data_connect krow_core: path: ../../../core + + flutter_bloc: ^8.1.3 + equatable: ^2.0.5 + intl: ^0.20.0 + flutter_modular: ^6.3.2 firebase_data_connect: ^0.2.2+2 firebase_auth: ^6.1.4