From 8b6061cb3086034fdebbcb839765a469659b7d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:23:15 -0500 Subject: [PATCH 01/22] correction of change view for recurring and permant - show permanet and recurring in find shift --- .../domain/lib/src/entities/shifts/shift.dart | 24 ++++ .../permanent_order/permanent_order_view.dart | 42 +++++- .../recurring_order/recurring_order_view.dart | 48 ++++++- .../shifts_repository_impl.dart | 2 + .../presentation/widgets/my_shift_card.dart | 96 ++++++++++++-- .../widgets/tabs/find_shifts_tab.dart | 124 +++++++++++++++++- 6 files changed, 323 insertions(+), 13 deletions(-) diff --git a/apps/mobile/packages/domain/lib/src/entities/shifts/shift.dart b/apps/mobile/packages/domain/lib/src/entities/shifts/shift.dart index e24d6477..f3fb278e 100644 --- a/apps/mobile/packages/domain/lib/src/entities/shifts/shift.dart +++ b/apps/mobile/packages/domain/lib/src/entities/shifts/shift.dart @@ -31,6 +31,9 @@ class Shift extends Equatable { final bool? hasApplied; final double? totalValue; final Break? breakInfo; + final String? orderId; + final String? orderType; + final List? schedules; const Shift({ required this.id, @@ -62,6 +65,9 @@ class Shift extends Equatable { this.hasApplied, this.totalValue, this.breakInfo, + this.orderId, + this.orderType, + this.schedules, }); @override @@ -95,9 +101,27 @@ class Shift extends Equatable { hasApplied, totalValue, breakInfo, + orderId, + orderType, + schedules, ]; } +class ShiftSchedule extends Equatable { + const ShiftSchedule({ + required this.date, + required this.startTime, + required this.endTime, + }); + + final String date; + final String startTime; + final String endTime; + + @override + List get props => [date, startTime, endTime]; +} + class ShiftManager extends Equatable { const ShiftManager({required this.name, required this.phone, this.avatar}); diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/permanent_order/permanent_order_view.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/permanent_order/permanent_order_view.dart index 888bd150..c5041687 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/permanent_order/permanent_order_view.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/permanent_order/permanent_order_view.dart @@ -20,6 +20,42 @@ class PermanentOrderView extends StatelessWidget { /// Creates a [PermanentOrderView]. const PermanentOrderView({super.key}); + DateTime _firstPermanentShiftDate( + DateTime startDate, + List permanentDays, + ) { + final DateTime start = DateTime(startDate.year, startDate.month, startDate.day); + final DateTime end = start.add(const Duration(days: 29)); + final Set selected = permanentDays.toSet(); + for (DateTime day = start; !day.isAfter(end); day = day.add(const Duration(days: 1))) { + if (selected.contains(_weekdayLabel(day))) { + return day; + } + } + return start; + } + + String _weekdayLabel(DateTime date) { + switch (date.weekday) { + case DateTime.monday: + return 'MON'; + case DateTime.tuesday: + return 'TUE'; + case DateTime.wednesday: + return 'WED'; + case DateTime.thursday: + return 'THU'; + case DateTime.friday: + return 'FRI'; + case DateTime.saturday: + return 'SAT'; + case DateTime.sunday: + return 'SUN'; + default: + return 'SUN'; + } + } + @override Widget build(BuildContext context) { final TranslationsClientCreateOrderPermanentEn labels = @@ -42,6 +78,10 @@ class PermanentOrderView extends StatelessWidget { }, builder: (BuildContext context, PermanentOrderState state) { if (state.status == PermanentOrderStatus.success) { + final DateTime initialDate = _firstPermanentShiftDate( + state.startDate, + state.permanentDays, + ); return PermanentOrderSuccessView( title: labels.title, message: labels.subtitle, @@ -50,7 +90,7 @@ class PermanentOrderView extends StatelessWidget { ClientPaths.orders, (_) => false, arguments: { - 'initialDate': state.startDate.toIso8601String(), + 'initialDate': initialDate.toIso8601String(), }, ), ); diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/recurring_order/recurring_order_view.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/recurring_order/recurring_order_view.dart index 89a20519..a6f173c8 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/recurring_order/recurring_order_view.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/recurring_order/recurring_order_view.dart @@ -20,6 +20,43 @@ class RecurringOrderView extends StatelessWidget { /// Creates a [RecurringOrderView]. const RecurringOrderView({super.key}); + DateTime _firstRecurringShiftDate( + DateTime startDate, + DateTime endDate, + List recurringDays, + ) { + final DateTime start = DateTime(startDate.year, startDate.month, startDate.day); + final DateTime end = DateTime(endDate.year, endDate.month, endDate.day); + final Set selected = recurringDays.toSet(); + for (DateTime day = start; !day.isAfter(end); day = day.add(const Duration(days: 1))) { + if (selected.contains(_weekdayLabel(day))) { + return day; + } + } + return start; + } + + String _weekdayLabel(DateTime date) { + switch (date.weekday) { + case DateTime.monday: + return 'MON'; + case DateTime.tuesday: + return 'TUE'; + case DateTime.wednesday: + return 'WED'; + case DateTime.thursday: + return 'THU'; + case DateTime.friday: + return 'FRI'; + case DateTime.saturday: + return 'SAT'; + case DateTime.sunday: + return 'SUN'; + default: + return 'SUN'; + } + } + @override Widget build(BuildContext context) { final TranslationsClientCreateOrderRecurringEn labels = @@ -44,6 +81,15 @@ class RecurringOrderView extends StatelessWidget { }, builder: (BuildContext context, RecurringOrderState state) { if (state.status == RecurringOrderStatus.success) { + final DateTime maxEndDate = + state.startDate.add(const Duration(days: 29)); + final DateTime effectiveEndDate = + state.endDate.isAfter(maxEndDate) ? maxEndDate : state.endDate; + final DateTime initialDate = _firstRecurringShiftDate( + state.startDate, + effectiveEndDate, + state.recurringDays, + ); return RecurringOrderSuccessView( title: labels.title, message: labels.subtitle, @@ -52,7 +98,7 @@ class RecurringOrderView extends StatelessWidget { ClientPaths.orders, (_) => false, arguments: { - 'initialDate': state.startDate.toIso8601String(), + 'initialDate': initialDate.toIso8601String(), }, ), ); diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/data/repositories_impl/shifts_repository_impl.dart b/apps/mobile/packages/features/staff/shifts/lib/src/data/repositories_impl/shifts_repository_impl.dart index 8be4f612..53667bde 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/data/repositories_impl/shifts_repository_impl.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/data/repositories_impl/shifts_repository_impl.dart @@ -227,6 +227,8 @@ class ShiftsRepositoryImpl filledSlots: sr.assigned ?? 0, latitude: sr.shift.latitude, longitude: sr.shift.longitude, + orderId: sr.shift.order.id, + orderType: sr.shift.order.orderType?.stringValue, breakInfo: BreakAdapter.fromData( isPaid: sr.isBreakPaid ?? false, breakTime: sr.breakType?.stringValue, diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/my_shift_card.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/my_shift_card.dart index 86352524..f34b405b 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/my_shift_card.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/my_shift_card.dart @@ -77,6 +77,13 @@ class _MyShiftCardState extends State { String _getShiftType() { // Handling potential localization key availability try { + final String orderType = (widget.shift.orderType ?? '').toUpperCase(); + if (orderType == 'PERMANENT') { + return t.staff_shifts.filter.long_term; + } + if (orderType == 'RECURRING') { + return t.staff_shifts.filter.multi_day; + } if (widget.shift.durationDays != null && widget.shift.durationDays! > 30) { return t.staff_shifts.filter.long_term; } @@ -133,6 +140,24 @@ class _MyShiftCardState extends State { statusText = status?.toUpperCase() ?? ""; } + final schedules = widget.shift.schedules ?? []; + final hasSchedules = schedules.isNotEmpty; + final List visibleSchedules = schedules.length <= 5 + ? schedules + : schedules.take(3).toList(); + final int remainingSchedules = + schedules.length <= 5 ? 0 : schedules.length - 3; + final String scheduleRange = hasSchedules + ? () { + final first = schedules.first.date; + final last = schedules.last.date; + if (first == last) { + return _formatDate(first); + } + return '${_formatDate(first)} โ€“ ${_formatDate(last)}'; + }() + : ''; + return GestureDetector( onTap: () { Modular.to.pushNamed( @@ -299,7 +324,55 @@ class _MyShiftCardState extends State { const SizedBox(height: UiConstants.space2), // Date & Time - if (widget.shift.durationDays != null && + if (hasSchedules) ...[ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + UiIcons.clock, + size: UiConstants.iconXs, + color: UiColors.primary, + ), + const SizedBox(width: UiConstants.space1), + Text( + '${schedules.length} schedules', + style: UiTypography.footnote2m.copyWith( + color: UiColors.primary, + ), + ), + ], + ), + const SizedBox(height: UiConstants.space1), + Padding( + padding: const EdgeInsets.only(bottom: 2), + child: Text( + scheduleRange, + style: UiTypography.footnote2r.copyWith(color: UiColors.primary), + ), + ), + ...visibleSchedules.map( + (schedule) => Padding( + padding: const EdgeInsets.only(bottom: 2), + child: Text( + '${_formatDate(schedule.date)}, ${_formatTime(schedule.startTime)} โ€“ ${_formatTime(schedule.endTime)}', + style: UiTypography.footnote2r.copyWith( + color: UiColors.primary, + ), + ), + ), + ), + if (remainingSchedules > 0) + Text( + '+$remainingSchedules more schedules', + style: UiTypography.footnote2r.copyWith( + color: UiColors.primary.withOpacity(0.7), + ), + ), + ], + ), + ] else if (widget.shift.durationDays != null && widget.shift.durationDays! > 1) ...[ Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -324,17 +397,22 @@ class _MyShiftCardState extends State { ), const SizedBox(height: UiConstants.space1), Padding( - padding: const EdgeInsets.only(bottom: 2), - child: Text( - '${_formatDate(widget.shift.date)}, ${_formatTime(widget.shift.startTime)} โ€“ ${_formatTime(widget.shift.endTime)}', - style: UiTypography.footnote2r.copyWith(color: UiColors.primary), + padding: const EdgeInsets.only(bottom: 2), + child: Text( + '${_formatDate(widget.shift.date)}, ${_formatTime(widget.shift.startTime)} โ€“ ${_formatTime(widget.shift.endTime)}', + style: UiTypography.footnote2r.copyWith( + color: UiColors.primary, ), + ), ), if (widget.shift.durationDays! > 1) - Text( - '... +${widget.shift.durationDays! - 1} more days', - style: UiTypography.footnote2r.copyWith(color: UiColors.primary.withOpacity(0.7)), - ) + Text( + '... +${widget.shift.durationDays! - 1} more days', + style: UiTypography.footnote2r.copyWith( + color: + UiColors.primary.withOpacity(0.7), + ), + ) ], ), ] else ...[ diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/find_shifts_tab.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/find_shifts_tab.dart index bb426fd7..81e6ac03 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/find_shifts_tab.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/find_shifts_tab.dart @@ -20,6 +20,119 @@ class _FindShiftsTabState extends State { String _searchQuery = ''; String _jobType = 'all'; + bool _isRecurring(Shift shift) => + (shift.orderType ?? '').toUpperCase() == 'RECURRING'; + + bool _isPermanent(Shift shift) => + (shift.orderType ?? '').toUpperCase() == 'PERMANENT'; + + DateTime? _parseShiftDate(String date) { + if (date.isEmpty) return null; + try { + return DateTime.parse(date); + } catch (_) { + return null; + } + } + + List _groupMultiDayShifts(List shifts) { + final Map> grouped = >{}; + for (final shift in shifts) { + if (!_isRecurring(shift) && !_isPermanent(shift)) { + continue; + } + final orderId = shift.orderId; + final roleId = shift.roleId; + if (orderId == null || roleId == null) { + continue; + } + final key = '$orderId::$roleId'; + grouped.putIfAbsent(key, () => []).add(shift); + } + + final Set addedGroups = {}; + final List result = []; + + for (final shift in shifts) { + if (!_isRecurring(shift) && !_isPermanent(shift)) { + result.add(shift); + continue; + } + final orderId = shift.orderId; + final roleId = shift.roleId; + if (orderId == null || roleId == null) { + result.add(shift); + continue; + } + final key = '$orderId::$roleId'; + if (addedGroups.contains(key)) { + continue; + } + addedGroups.add(key); + final List group = grouped[key] ?? []; + if (group.isEmpty) { + result.add(shift); + continue; + } + group.sort((a, b) { + final ad = _parseShiftDate(a.date); + final bd = _parseShiftDate(b.date); + if (ad == null && bd == null) return 0; + if (ad == null) return 1; + if (bd == null) return -1; + return ad.compareTo(bd); + }); + + final Shift first = group.first; + final List schedules = group + .map((s) => ShiftSchedule( + date: s.date, + startTime: s.startTime, + endTime: s.endTime, + )) + .toList(); + + result.add( + Shift( + id: first.id, + roleId: first.roleId, + title: first.title, + clientName: first.clientName, + logoUrl: first.logoUrl, + hourlyRate: first.hourlyRate, + location: first.location, + locationAddress: first.locationAddress, + date: first.date, + startTime: first.startTime, + endTime: first.endTime, + createdDate: first.createdDate, + tipsAvailable: first.tipsAvailable, + travelTime: first.travelTime, + mealProvided: first.mealProvided, + parkingAvailable: first.parkingAvailable, + gasCompensation: first.gasCompensation, + description: first.description, + instructions: first.instructions, + managers: first.managers, + latitude: first.latitude, + longitude: first.longitude, + status: first.status, + durationDays: schedules.length, + requiredSlots: first.requiredSlots, + filledSlots: first.filledSlots, + hasApplied: first.hasApplied, + totalValue: first.totalValue, + breakInfo: first.breakInfo, + orderId: first.orderId, + orderType: first.orderType, + schedules: schedules, + ), + ); + } + + return result; + } + Widget _buildFilterTab(String id, String label) { final isSelected = _jobType == id; return GestureDetector( @@ -49,8 +162,10 @@ class _FindShiftsTabState extends State { @override Widget build(BuildContext context) { + final groupedJobs = _groupMultiDayShifts(widget.availableJobs); + // Filter logic - final filteredJobs = widget.availableJobs.where((s) { + final filteredJobs = groupedJobs.where((s) { final matchesSearch = s.title.toLowerCase().contains(_searchQuery.toLowerCase()) || s.location.toLowerCase().contains(_searchQuery.toLowerCase()) || @@ -60,10 +175,15 @@ class _FindShiftsTabState extends State { if (_jobType == 'all') return true; if (_jobType == 'one-day') { + if (_isRecurring(s) || _isPermanent(s)) return false; return s.durationDays == null || s.durationDays! <= 1; } if (_jobType == 'multi-day') { - return s.durationDays != null && s.durationDays! > 1; + return _isRecurring(s) || + (s.durationDays != null && s.durationDays! > 1); + } + if (_jobType == 'long-term') { + return _isPermanent(s); } return true; }).toList(); From fe28396a5854a1ffaa9ad6298c06e58e426ee406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Wed, 18 Feb 2026 19:34:58 -0500 Subject: [PATCH 02/22] adding tag type for shifts --- .../lib/src/presentation/widgets/my_shift_card.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/my_shift_card.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/my_shift_card.dart index f34b405b..03f20b49 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/my_shift_card.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/my_shift_card.dart @@ -216,8 +216,8 @@ class _MyShiftCardState extends State { letterSpacing: 0.5, ), ), - // Shift Type Badge - if (status == 'open' || status == 'pending') ...[ + // Shift Type Badge (Order type) + if ((widget.shift.orderType ?? '').isNotEmpty) ...[ const SizedBox(width: UiConstants.space2), Container( padding: const EdgeInsets.symmetric( @@ -225,13 +225,14 @@ class _MyShiftCardState extends State { vertical: 2, ), decoration: BoxDecoration( - color: UiColors.primary.withValues(alpha: 0.1), + color: UiColors.background, borderRadius: UiConstants.radiusSm, + border: Border.all(color: UiColors.border), ), child: Text( _getShiftType(), style: UiTypography.footnote2m.copyWith( - color: UiColors.primary, + color: UiColors.textSecondary, ), ), ), From ed854cb95893f10bf1089b0e63edaba14501f919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Thu, 19 Feb 2026 11:00:55 -0500 Subject: [PATCH 03/22] solving problem with apply button --- .../core/lib/src/routing/staff/navigator.dart | 9 ++++++- .../blocs/shifts/shifts_bloc.dart | 10 ++++++-- .../blocs/shifts/shifts_event.dart | 8 ++++++- .../pages/shift_details_page.dart | 9 +++++-- .../src/presentation/pages/shifts_page.dart | 24 +++++++++++++++++-- .../shifts/lib/src/staff_shifts_module.dart | 1 + 6 files changed, 53 insertions(+), 8 deletions(-) diff --git a/apps/mobile/packages/core/lib/src/routing/staff/navigator.dart b/apps/mobile/packages/core/lib/src/routing/staff/navigator.dart index 3ba4a8ea..0f624872 100644 --- a/apps/mobile/packages/core/lib/src/routing/staff/navigator.dart +++ b/apps/mobile/packages/core/lib/src/routing/staff/navigator.dart @@ -98,7 +98,11 @@ extension StaffNavigator on IModularNavigator { /// Parameters: /// * [selectedDate] - Optional date to pre-select in the shifts view /// * [initialTab] - Optional initial tab (via query parameter) - void toShifts({DateTime? selectedDate, String? initialTab}) { + void toShifts({ + DateTime? selectedDate, + String? initialTab, + bool? refreshAvailable, + }) { final Map args = {}; if (selectedDate != null) { args['selectedDate'] = selectedDate; @@ -106,6 +110,9 @@ extension StaffNavigator on IModularNavigator { if (initialTab != null) { args['initialTab'] = initialTab; } + if (refreshAvailable == true) { + args['refreshAvailable'] = true; + } navigate( StaffPaths.shifts, arguments: args.isEmpty ? null : args, diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/blocs/shifts/shifts_bloc.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/blocs/shifts/shifts_bloc.dart index 6a8c1c43..e6e0fe97 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/blocs/shifts/shifts_bloc.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/blocs/shifts/shifts_bloc.dart @@ -108,9 +108,15 @@ class ShiftsBloc extends Bloc ) async { final currentState = state; if (currentState is! ShiftsLoaded) return; - if (currentState.availableLoading || currentState.availableLoaded) return; + if (!event.force && + (currentState.availableLoading || currentState.availableLoaded)) { + return; + } - emit(currentState.copyWith(availableLoading: true)); + emit(currentState.copyWith( + availableLoading: true, + availableLoaded: false, + )); await handleError( emit: emit, action: () async { diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/blocs/shifts/shifts_event.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/blocs/shifts/shifts_event.dart index d25866e0..55ea9fd1 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/blocs/shifts/shifts_event.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/blocs/shifts/shifts_event.dart @@ -12,7 +12,13 @@ class LoadShiftsEvent extends ShiftsEvent {} class LoadHistoryShiftsEvent extends ShiftsEvent {} -class LoadAvailableShiftsEvent extends ShiftsEvent {} +class LoadAvailableShiftsEvent extends ShiftsEvent { + final bool force; + const LoadAvailableShiftsEvent({this.force = false}); + + @override + List get props => [force]; +} class LoadFindFirstEvent extends ShiftsEvent {} diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shift_details_page.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shift_details_page.dart index e4563de1..b2a17a60 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shift_details_page.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shift_details_page.dart @@ -93,7 +93,11 @@ class _ShiftDetailsPageState extends State { message: state.message, type: UiSnackbarType.success, ); - Modular.to.toShifts(selectedDate: state.shiftDate); + Modular.to.toShifts( + selectedDate: state.shiftDate, + initialTab: 'find', + refreshAvailable: true, + ); } else if (state is ShiftDetailsError) { if (_isApplying) { UiSnackbar.show( @@ -112,7 +116,8 @@ class _ShiftDetailsPageState extends State { ); } - Shift displayShift = widget.shift; + final Shift displayShift = + state is ShiftDetailsLoaded ? state.shift : widget.shift; final i18n = Translations.of(context).staff_shifts.shift_details; final duration = _calculateDuration(displayShift); diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shifts_page.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shifts_page.dart index 32ffc356..13776407 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shifts_page.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/pages/shifts_page.dart @@ -12,7 +12,13 @@ import '../widgets/tabs/history_shifts_tab.dart'; class ShiftsPage extends StatefulWidget { final String? initialTab; final DateTime? selectedDate; - const ShiftsPage({super.key, this.initialTab, this.selectedDate}); + final bool refreshAvailable; + const ShiftsPage({ + super.key, + this.initialTab, + this.selectedDate, + this.refreshAvailable = false, + }); @override State createState() => _ShiftsPageState(); @@ -22,6 +28,8 @@ class _ShiftsPageState extends State { late String _activeTab; DateTime? _selectedDate; bool _prioritizeFind = false; + bool _refreshAvailable = false; + bool _pendingAvailableRefresh = false; final ShiftsBloc _bloc = Modular.get(); @override @@ -30,6 +38,8 @@ class _ShiftsPageState extends State { _activeTab = widget.initialTab ?? 'myshifts'; _selectedDate = widget.selectedDate; _prioritizeFind = widget.initialTab == 'find'; + _refreshAvailable = widget.refreshAvailable; + _pendingAvailableRefresh = widget.refreshAvailable; if (_prioritizeFind) { _bloc.add(LoadFindFirstEvent()); } else { @@ -40,7 +50,9 @@ class _ShiftsPageState extends State { } if (_activeTab == 'find') { if (!_prioritizeFind) { - _bloc.add(LoadAvailableShiftsEvent()); + _bloc.add( + LoadAvailableShiftsEvent(force: _refreshAvailable), + ); } } } @@ -59,6 +71,10 @@ class _ShiftsPageState extends State { _selectedDate = widget.selectedDate; }); } + if (widget.refreshAvailable) { + _refreshAvailable = true; + _pendingAvailableRefresh = true; + } } @override @@ -77,6 +93,10 @@ class _ShiftsPageState extends State { } }, builder: (context, state) { + if (_pendingAvailableRefresh && state is ShiftsLoaded) { + _pendingAvailableRefresh = false; + _bloc.add(const LoadAvailableShiftsEvent(force: true)); + } final bool baseLoaded = state is ShiftsLoaded; final List myShifts = (state is ShiftsLoaded) ? state.myShifts diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/staff_shifts_module.dart b/apps/mobile/packages/features/staff/shifts/lib/src/staff_shifts_module.dart index 02bade2c..16518dcb 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/staff_shifts_module.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/staff_shifts_module.dart @@ -46,6 +46,7 @@ class StaffShiftsModule extends Module { return ShiftsPage( initialTab: queryParams['tab'] ?? args?['initialTab'], selectedDate: args?['selectedDate'], + refreshAvailable: args?['refreshAvailable'] == true, ); }, ); From d160610bf9f3e55f7f23b14fa2f62e949ff19ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:37:26 -0500 Subject: [PATCH 04/22] deleting few values of shift enum --- backend/dataconnect/connector/shiftRole/queries.gql | 4 ++-- backend/dataconnect/functions/seed.gql | 8 ++++---- backend/dataconnect/schema/shift.gql | 2 -- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/backend/dataconnect/connector/shiftRole/queries.gql b/backend/dataconnect/connector/shiftRole/queries.gql index 07720bf0..6795e79d 100644 --- a/backend/dataconnect/connector/shiftRole/queries.gql +++ b/backend/dataconnect/connector/shiftRole/queries.gql @@ -254,7 +254,7 @@ query listShiftRolesByVendorId( shiftRoles( where: { shift: { - status: {in: [IN_PROGRESS, CONFIRMED, ASSIGNED, OPEN, PENDING]} #IN_PROGRESS? PENDING? + status: {in: [IN_PROGRESS, ASSIGNED, OPEN]} #IN_PROGRESS? order: { vendorId: { eq: $vendorId } } @@ -511,7 +511,7 @@ query getCompletedShiftsByBusinessId( shifts( where: { order: { businessId: { eq: $businessId } } - status: {in: [IN_PROGRESS, CONFIRMED, COMPLETED, OPEN]} + status: {in: [IN_PROGRESS, COMPLETED, OPEN]} date: { ge: $dateFrom, le: $dateTo } } offset: $offset diff --git a/backend/dataconnect/functions/seed.gql b/backend/dataconnect/functions/seed.gql index 8c6b69c0..1c6e0fcd 100644 --- a/backend/dataconnect/functions/seed.gql +++ b/backend/dataconnect/functions/seed.gql @@ -927,7 +927,7 @@ mutation seedAll @transaction { placeId: "Eiw0MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw" latitude: 34.2611486 longitude: -118.5010287 - status: ASSIGNED + status: OPEN workersNeeded: 2 filled: 1 } @@ -950,7 +950,7 @@ mutation seedAll @transaction { placeId: "Eiw2ODAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw" latitude: 34.2611486 longitude: -118.5010287 - status: ASSIGNED + status: OPEN workersNeeded: 2 filled: 1 } @@ -996,7 +996,7 @@ mutation seedAll @transaction { placeId: "Eiw0MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw" latitude: 34.2611486 longitude: -118.5010287 - status: ASSIGNED + status: OPEN workersNeeded: 2 filled: 1 } @@ -1042,7 +1042,7 @@ mutation seedAll @transaction { placeId: "Eiw1MDAwIFNhbiBKb3NlIFN0cmVldCwgR3JhbmFkYSBIaWxscywgQ0EsIFVTQSIuKiwKFAoSCYNJZBTdmsKAEddGOfBj8LvTEhQKEglnNXI0zZrCgBEjR6om62lcVw" latitude: 34.2611486 longitude: -118.5010287 - status: ASSIGNED + status: OPEN workersNeeded: 2 filled: 1 } diff --git a/backend/dataconnect/schema/shift.gql b/backend/dataconnect/schema/shift.gql index 3e5f7c67..f03e54a7 100644 --- a/backend/dataconnect/schema/shift.gql +++ b/backend/dataconnect/schema/shift.gql @@ -1,9 +1,7 @@ enum ShiftStatus { DRAFT FILLED - PENDING ASSIGNED - CONFIRMED OPEN IN_PROGRESS COMPLETED From e6b3eca16d0ac5d3c18d0edf496e3c7a805e38fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:40:34 -0500 Subject: [PATCH 05/22] new query for my shifts --- .../client_create_order_repository_impl.dart | 6 +- .../widgets/shift_order_form_sheet.dart | 2 +- .../shifts_repository_impl.dart | 5 +- .../connector/application/queries.gql | 89 +++++++++++++++++++ 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/apps/mobile/packages/features/client/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart b/apps/mobile/packages/features/client/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart index 757aff1f..d808ff3d 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/data/repositories_impl/client_create_order_repository_impl.dart @@ -105,7 +105,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte .state(hub.state) .street(hub.street) .country(hub.country) - .status(dc.ShiftStatus.CONFIRMED) + .status(dc.ShiftStatus.OPEN) .workersNeeded(workersNeeded) .filled(0) .durationDays(1) @@ -224,7 +224,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte .state(hub.state) .street(hub.street) .country(hub.country) - .status(dc.ShiftStatus.CONFIRMED) + .status(dc.ShiftStatus.OPEN) .workersNeeded(workersNeeded) .filled(0) .durationDays(1) @@ -342,7 +342,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte .state(hub.state) .street(hub.street) .country(hub.country) - .status(dc.ShiftStatus.CONFIRMED) + .status(dc.ShiftStatus.OPEN) .workersNeeded(workersNeeded) .filled(0) .durationDays(1) diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/shift_order_form_sheet.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/shift_order_form_sheet.dart index 15bdac09..593a267a 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/shift_order_form_sheet.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/shift_order_form_sheet.dart @@ -265,7 +265,7 @@ class _ShiftOrderFormSheetState extends State { .state(selectedHub.state) .street(selectedHub.street) .country(selectedHub.country) - .status(dc.ShiftStatus.PENDING) + .status(dc.ShiftStatus.OPEN) .workersNeeded(workersNeeded) .filled(0) .durationDays(1) diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/data/repositories_impl/shifts_repository_impl.dart b/apps/mobile/packages/features/staff/shifts/lib/src/data/repositories_impl/shifts_repository_impl.dart index b1ada599..7d39b3c2 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/data/repositories_impl/shifts_repository_impl.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/data/repositories_impl/shifts_repository_impl.dart @@ -95,11 +95,12 @@ class ShiftsRepositoryImpl DateTime? end, }) async { final staffId = await _service.getStaffId(); - var query = _service.connector.getApplicationsByStaffId(staffId: staffId); + var query = _service.connector.getMyApplicationsByStaffId(staffId: staffId); if (start != null && end != null) { query = query.dayStart(_service.toTimestamp(start)).dayEnd(_service.toTimestamp(end)); } - final fdc.QueryResult response = await _service.executeProtected(() => query.execute()); + final fdc.QueryResult response = + await _service.executeProtected(() => query.execute()); final apps = response.data.applications; final List shifts = []; diff --git a/backend/dataconnect/connector/application/queries.gql b/backend/dataconnect/connector/application/queries.gql index 4a6d6396..e08aca4c 100644 --- a/backend/dataconnect/connector/application/queries.gql +++ b/backend/dataconnect/connector/application/queries.gql @@ -356,6 +356,95 @@ query getApplicationsByStaffId( } } +query getMyApplicationsByStaffId( + $staffId: UUID! + $offset: Int + $limit: Int + $dayStart: Timestamp + $dayEnd: Timestamp +) @auth(level: USER) { + applications( + where: { + staffId: { eq: $staffId } + status: { in: [ CONFIRMED, CHECKED_IN, CHECKED_OUT, LATE, PENDING] } + shift: { + date: { ge: $dayStart, le: $dayEnd } + } + + } + offset: $offset + limit: $limit + ) { + id + shiftId + staffId + status + appliedAt + checkInTime + checkOutTime + origin + createdAt + + shift { + id + title + date + startTime + endTime + location + status + durationDays + description + latitude + longitude + + order { + id + eventName + #location + + teamHub { + address + placeId + hubName + } + + business { + id + businessName + email + contactName + companyLogoUrl + } + vendor { + id + companyName + } + } + + } + + shiftRole { + id + roleId + count + assigned + startTime + endTime + hours + breakType + isBreakPaid + totalValue + role { + id + name + costPerHour + } + } + + } +} + query vaidateDayStaffApplication( $staffId: UUID! $offset: Int From b8772b301e3e752d9afaf8f92ab07cf7b8399f1f Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 19 Feb 2026 16:45:03 -0500 Subject: [PATCH 06/22] feat: Update Flutter version handling in CI and adjust pubspec files for compatibility --- .github/workflows/mobile-ci.yml | 2 +- apps/mobile/pubspec.lock | 2 +- apps/mobile/pubspec.yaml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 5f18d948..4afa04a4 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -74,7 +74,7 @@ jobs: - name: ๐Ÿฆ‹ Set up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.19.x' + flutter-version-file: pubspec.yaml channel: 'stable' cache: true diff --git a/apps/mobile/pubspec.lock b/apps/mobile/pubspec.lock index d9afe13f..9aa8910e 100644 --- a/apps/mobile/pubspec.lock +++ b/apps/mobile/pubspec.lock @@ -1530,4 +1530,4 @@ packages: version: "2.2.3" sdks: dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4" + flutter: ">=3.38.4 <4.0.0" diff --git a/apps/mobile/pubspec.yaml b/apps/mobile/pubspec.yaml index 6ffcd99f..bca32555 100644 --- a/apps/mobile/pubspec.yaml +++ b/apps/mobile/pubspec.yaml @@ -3,6 +3,7 @@ publish_to: 'none' description: "A sample project using melos and modular scaffold." environment: sdk: '>=3.10.0 <4.0.0' + flutter: '>=3.38.0 <4.0.0' workspace: - packages/design_system - packages/core From d7bd1174c912548e75fded59a24c276a400aab6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Thu, 19 Feb 2026 16:46:32 -0500 Subject: [PATCH 07/22] new query for history --- backend/dataconnect/connector/application/queries.gql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/dataconnect/connector/application/queries.gql b/backend/dataconnect/connector/application/queries.gql index e08aca4c..d2a8a205 100644 --- a/backend/dataconnect/connector/application/queries.gql +++ b/backend/dataconnect/connector/application/queries.gql @@ -784,10 +784,14 @@ query listCompletedApplicationsByStaffId( durationDays latitude longitude + orderId order { id eventName + orderType + startDate + endDate teamHub { address From 410e5b5cd16f4014548e59a4893fe2ce89152369 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 19 Feb 2026 16:47:25 -0500 Subject: [PATCH 08/22] feat: Update Flutter version file path in mobile CI workflow --- .github/workflows/mobile-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 4afa04a4..cacf7844 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -74,7 +74,7 @@ jobs: - name: ๐Ÿฆ‹ Set up Flutter uses: subosito/flutter-action@v2 with: - flutter-version-file: pubspec.yaml + flutter-version-file: 'apps/mobile/pubspec.yaml' channel: 'stable' cache: true @@ -120,7 +120,7 @@ jobs: - name: ๐Ÿฆ‹ Set up Flutter uses: subosito/flutter-action@v2 with: - flutter-version: '3.19.x' + flutter-version-file: 'apps/mobile/pubspec.yaml' channel: 'stable' cache: true From b6c3fb8487082b05c2193b5754ec41273d15f2c9 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 19 Feb 2026 16:49:23 -0500 Subject: [PATCH 09/22] feat: Update Flutter version to 3.38.x in mobile CI workflow --- .github/workflows/mobile-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index cacf7844..54f3f3ee 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -74,7 +74,7 @@ jobs: - name: ๐Ÿฆ‹ Set up Flutter uses: subosito/flutter-action@v2 with: - flutter-version-file: 'apps/mobile/pubspec.yaml' + flutter-version: '3.38.x' channel: 'stable' cache: true @@ -120,7 +120,7 @@ jobs: - name: ๐Ÿฆ‹ Set up Flutter uses: subosito/flutter-action@v2 with: - flutter-version-file: 'apps/mobile/pubspec.yaml' + flutter-version: '3.38.x' channel: 'stable' cache: true From 1dd36993738c5bc8c3816f75bb6e06a60123ab8d Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 19 Feb 2026 17:05:56 -0500 Subject: [PATCH 10/22] feat: Update mobile CI workflow to use melos for build and analysis --- .github/workflows/mobile-ci.yml | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 54f3f3ee..70219ce4 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -87,17 +87,31 @@ jobs: run: | cd apps/mobile echo "โš™๏ธ Running build_runner..." - flutter pub run build_runner build --delete-conflicting-outputs 2>&1 || true + melos run gen:build 2>&1 || true echo "" - echo "๐Ÿ”ฌ Running flutter analyze on all files..." - flutter analyze lib/ --no-fatal-infos 2>&1 | tee analyze_output.txt || true + echo "๐Ÿ”ฌ Running flutter analyze on all packages..." + # Analyze all packages in the workspace + for dir in packages/*/; do + if [ -d "$dir/lib" ]; then + echo "Analyzing: $dir" + flutter analyze "$dir/lib" --no-fatal-infos 2>&1 | tee -a analyze_output.txt || true + fi + done + + # Also analyze apps + for app_dir in apps/*/lib; do + if [ -d "$app_dir" ]; then + echo "Analyzing: $app_dir" + flutter analyze "$app_dir" --no-fatal-infos 2>&1 | tee -a analyze_output.txt || true + fi + done echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" # Check for actual errors (not just warnings) - if grep -E "^\s*(error|SEVERE):" analyze_output.txt > /dev/null; then + if grep -E "^\s*(error|SEVERE):" analyze_output.txt > /dev/null 2>&1; then echo "โŒ COMPILATION ERRORS FOUND:" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" grep -B 2 -A 1 -E "^\s*(error|SEVERE):" analyze_output.txt | sed 's/^/ /' @@ -145,6 +159,9 @@ jobs: echo "$CHANGED_FILES" echo "" + # Ensure flutter pub get in workspace + melos bootstrap --no-git-tag-version + # Run dart analyze on each changed file HAS_ERRORS=false FAILED_FILES=() @@ -153,7 +170,7 @@ jobs: if [[ -n "$file" && "$file" == *.dart ]]; then echo "๐Ÿ“ Analyzing: $file" - if ! flutter analyze "$file" --no-fatal-infos 2>&1 | tee -a lint_output.txt; then + if ! dart analyze "$file" --no-fatal-infos 2>&1 | tee -a lint_output.txt; then HAS_ERRORS=true FAILED_FILES+=("$file") fi From 1510b69d59b42544e033615f878e1954199acd98 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Thu, 19 Feb 2026 17:13:03 -0500 Subject: [PATCH 11/22] feat: Enhance mobile CI workflow to compare all changes in PRs and streamline analysis commands --- .github/workflows/mobile-ci.yml | 40 ++++++--------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 70219ce4..02aafadc 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -29,10 +29,10 @@ jobs: id: detect run: | if [[ "${{ github.event_name }}" == "pull_request" ]]; then - # For PR, compare with base branch + # For PR, compare all changes against base branch (not just latest commit) + # Using three-dot syntax (...) shows all files changed in the PR branch BASE_REF="${{ github.event.pull_request.base.ref }}" - HEAD_REF="${{ github.event.pull_request.head.ref }}" - CHANGED_FILES=$(git diff --name-only origin/$BASE_REF..origin/$HEAD_REF 2>/dev/null || echo "") + CHANGED_FILES=$(git diff --name-only origin/$BASE_REF...HEAD 2>/dev/null || echo "") else # For push, compare with previous commit if [[ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]]; then @@ -80,32 +80,12 @@ jobs: - name: ๐Ÿ“ฆ Get Flutter dependencies run: | - cd apps/mobile - flutter pub get + make mobile-install - name: ๐Ÿ”จ Run compilation check run: | - cd apps/mobile - echo "โš™๏ธ Running build_runner..." - melos run gen:build 2>&1 || true - - echo "" - echo "๐Ÿ”ฌ Running flutter analyze on all packages..." - # Analyze all packages in the workspace - for dir in packages/*/; do - if [ -d "$dir/lib" ]; then - echo "Analyzing: $dir" - flutter analyze "$dir/lib" --no-fatal-infos 2>&1 | tee -a analyze_output.txt || true - fi - done - - # Also analyze apps - for app_dir in apps/*/lib; do - if [ -d "$app_dir" ]; then - echo "Analyzing: $app_dir" - flutter analyze "$app_dir" --no-fatal-infos 2>&1 | tee -a analyze_output.txt || true - fi - done + echo "โš™๏ธ Running mobile analyze..." + make mobile-analyze 2>&1 | tee analyze_output.txt || true echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" @@ -140,13 +120,10 @@ jobs: - name: ๐Ÿ“ฆ Get Flutter dependencies run: | - cd apps/mobile - flutter pub get + make mobile-install - name: ๐Ÿ” Lint changed Dart files run: | - cd apps/mobile - # Get the list of changed files CHANGED_FILES="${{ needs.detect-changes.outputs.changed-files }}" @@ -159,9 +136,6 @@ jobs: echo "$CHANGED_FILES" echo "" - # Ensure flutter pub get in workspace - melos bootstrap --no-git-tag-version - # Run dart analyze on each changed file HAS_ERRORS=false FAILED_FILES=() From 49f32b24f410fb60bb03200ff7855e043ac1189d Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 01:02:37 -0500 Subject: [PATCH 12/22] feat: Update mobile CI workflow to use mobile-install-ci for CI-specific setup --- .github/workflows/mobile-ci.yml | 4 ++-- makefiles/dataconnect.mk | 19 ++++++++++++++++++- makefiles/mobile.mk | 9 ++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 02aafadc..70e41929 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -80,7 +80,7 @@ jobs: - name: ๐Ÿ“ฆ Get Flutter dependencies run: | - make mobile-install + make mobile-install-ci - name: ๐Ÿ”จ Run compilation check run: | @@ -120,7 +120,7 @@ jobs: - name: ๐Ÿ“ฆ Get Flutter dependencies run: | - make mobile-install + make mobile-install-ci - name: ๐Ÿ” Lint changed Dart files run: | diff --git a/makefiles/dataconnect.mk b/makefiles/dataconnect.mk index 7285b997..84b04dff 100644 --- a/makefiles/dataconnect.mk +++ b/makefiles/dataconnect.mk @@ -19,7 +19,7 @@ else $(error Invalid DC_ENV '$(DC_ENV)'. Use DC_ENV=dev or DC_ENV=validation) endif -.PHONY: dataconnect-enable-apis dataconnect-init dataconnect-deploy dataconnect-sql-migrate dataconnect-generate-sdk dataconnect-sync dataconnect-bootstrap-db check-gcloud-beta dataconnect-clean dataconnect-bootstrap-validation-db dataconnect-file dataconnect-file-validation dataconnect-file-dev dataconnect-seed dataconnect-test +.PHONY: dataconnect-enable-apis dataconnect-init dataconnect-deploy dataconnect-sql-migrate dataconnect-generate-sdk dataconnect-generate-sdk-ci dataconnect-sync dataconnect-bootstrap-db check-gcloud-beta dataconnect-clean dataconnect-bootstrap-validation-db dataconnect-file dataconnect-file-validation dataconnect-file-dev dataconnect-seed dataconnect-test #creation dataconnect file dataconnect-file: @@ -79,6 +79,23 @@ dataconnect-generate-sdk: dataconnect-file @firebase dataconnect:sdk:generate --project=$(FIREBASE_ALIAS) @echo "โœ… Data Connect SDK generation completed for [$(DC_ENV)]." +# CI-safe SDK generation: tries Firebase CLI if available, otherwise uses pre-generated SDK +dataconnect-generate-sdk-ci: dataconnect-file + @echo "--> Generating Firebase Data Connect SDK for CI [$(DC_SERVICE)]..." + @if command -v firebase >/dev/null 2>&1; then \ + echo " Firebase CLI found, generating SDK..."; \ + firebase dataconnect:sdk:generate --project=$(FIREBASE_ALIAS); \ + echo "โœ… Data Connect SDK generation completed for [$(DC_ENV)]."; \ + else \ + echo " Firebase CLI not found in CI environment"; \ + if [ -d "apps/mobile/packages/data_connect/lib/src/dataconnect_generated" ]; then \ + echo " โœ… Using pre-generated SDK from apps/mobile/packages/data_connect/lib/src/dataconnect_generated"; \ + else \ + echo "โŒ ERROR: Firebase CLI not available and pre-generated SDK not found!"; \ + exit 1; \ + fi; \ + fi + # Unified backend schema update workflow (schema -> deploy -> SDK) dataconnect-sync: dataconnect-file @echo "--> [1/3] Deploying Data Connect [$(DC_SERVICE)]..." diff --git a/makefiles/mobile.mk b/makefiles/mobile.mk index 43c3d618..dd75f3d7 100644 --- a/makefiles/mobile.mk +++ b/makefiles/mobile.mk @@ -1,6 +1,6 @@ # --- Mobile App Development --- -.PHONY: mobile-install mobile-info mobile-analyze mobile-client-dev-android mobile-staff-dev-android mobile-client-build mobile-staff-build mobile-hot-reload mobile-hot-restart +.PHONY: mobile-install mobile-install-ci mobile-info mobile-analyze mobile-client-dev-android mobile-staff-dev-android mobile-client-build mobile-staff-build mobile-hot-reload mobile-hot-restart MOBILE_DIR := apps/mobile @@ -15,6 +15,13 @@ mobile-install: install-melos dataconnect-generate-sdk @echo "--> Generating localization files..." @cd $(MOBILE_DIR) && melos run gen:l10n +mobile-install-ci: install-melos dataconnect-generate-sdk-ci + @echo "--> Bootstrapping mobile workspace for CI (Melos)..." + @cd $(MOBILE_DIR) && melos bootstrap + @echo "--> Generating localization files..." + @cd $(MOBILE_DIR) && melos run gen:l10n + @echo "โœ… CI mobile setup complete" + mobile-info: @echo "--> Fetching mobile command info..." @cd $(MOBILE_DIR) && melos run info From 0fad902991990874772e8958a12171c2b7dd667c Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 01:10:38 -0500 Subject: [PATCH 13/22] feat: Install Firebase CLI in CI workflow and simplify SDK generation process --- .github/workflows/mobile-ci.yml | 8 ++++++++ makefiles/dataconnect.mk | 18 ++---------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 70e41929..a4532cb0 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -78,6 +78,10 @@ jobs: channel: 'stable' cache: true + - name: ๐Ÿ”ง Install Firebase CLI + run: | + npm install -g firebase-tools + - name: ๐Ÿ“ฆ Get Flutter dependencies run: | make mobile-install-ci @@ -118,6 +122,10 @@ jobs: channel: 'stable' cache: true + - name: ๐Ÿ”ง Install Firebase CLI + run: | + npm install -g firebase-tools + - name: ๐Ÿ“ฆ Get Flutter dependencies run: | make mobile-install-ci diff --git a/makefiles/dataconnect.mk b/makefiles/dataconnect.mk index 84b04dff..acd5b428 100644 --- a/makefiles/dataconnect.mk +++ b/makefiles/dataconnect.mk @@ -79,22 +79,8 @@ dataconnect-generate-sdk: dataconnect-file @firebase dataconnect:sdk:generate --project=$(FIREBASE_ALIAS) @echo "โœ… Data Connect SDK generation completed for [$(DC_ENV)]." -# CI-safe SDK generation: tries Firebase CLI if available, otherwise uses pre-generated SDK -dataconnect-generate-sdk-ci: dataconnect-file - @echo "--> Generating Firebase Data Connect SDK for CI [$(DC_SERVICE)]..." - @if command -v firebase >/dev/null 2>&1; then \ - echo " Firebase CLI found, generating SDK..."; \ - firebase dataconnect:sdk:generate --project=$(FIREBASE_ALIAS); \ - echo "โœ… Data Connect SDK generation completed for [$(DC_ENV)]."; \ - else \ - echo " Firebase CLI not found in CI environment"; \ - if [ -d "apps/mobile/packages/data_connect/lib/src/dataconnect_generated" ]; then \ - echo " โœ… Using pre-generated SDK from apps/mobile/packages/data_connect/lib/src/dataconnect_generated"; \ - else \ - echo "โŒ ERROR: Firebase CLI not available and pre-generated SDK not found!"; \ - exit 1; \ - fi; \ - fi +# CI version: same as regular since Firebase CLI is now installed in CI +dataconnect-generate-sdk-ci: dataconnect-generate-sdk # Unified backend schema update workflow (schema -> deploy -> SDK) dataconnect-sync: dataconnect-file From 767b10e3377f7a01266e84e86df52b729913049e Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 01:14:18 -0500 Subject: [PATCH 14/22] fix: Remove trailing commas in reports_page.dart for consistency --- .../reports/lib/src/presentation/pages/reports_page.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mobile/packages/features/client/reports/lib/src/presentation/pages/reports_page.dart b/apps/mobile/packages/features/client/reports/lib/src/presentation/pages/reports_page.dart index fbc60def..ac0fc734 100644 --- a/apps/mobile/packages/features/client/reports/lib/src/presentation/pages/reports_page.dart +++ b/apps/mobile/packages/features/client/reports/lib/src/presentation/pages/reports_page.dart @@ -133,9 +133,9 @@ class _ReportsPageState extends State // Tabs Container( height: 44, - padding: const EdgeInsets.all(4), + padding: const EdgeInsets.all(4) decoration: BoxDecoration( - color: UiColors.white.withOpacity(0.2), + color: UiColors.white.withOpacity(0.2) borderRadius: BorderRadius.circular(12), ), child: TabBar( From 614851274b624b304e43a562b5a9dd0ba20802d9 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 01:26:13 -0500 Subject: [PATCH 15/22] feat: Update mobile CI workflow to streamline build process and remove CI-specific setup --- .github/workflows/mobile-ci.yml | 32 +++++++++++++++++++++++--------- makefiles/dataconnect.mk | 5 +---- makefiles/mobile.mk | 9 +-------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index a4532cb0..4d53bdd5 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -84,25 +84,39 @@ jobs: - name: ๐Ÿ“ฆ Get Flutter dependencies run: | - make mobile-install-ci + make mobile-install - name: ๐Ÿ”จ Run compilation check run: | - echo "โš™๏ธ Running mobile analyze..." - make mobile-analyze 2>&1 | tee analyze_output.txt || true + echo "๐Ÿ—๏ธ Building client app for Android (dev mode)..." + make mobile-client-build PLATFORM=apk MODE=dev 2>&1 | tee client_build.txt || true echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - # Check for actual errors (not just warnings) - if grep -E "^\s*(error|SEVERE):" analyze_output.txt > /dev/null 2>&1; then - echo "โŒ COMPILATION ERRORS FOUND:" + echo "๐Ÿ—๏ธ Building staff app for Android (dev mode)..." + make mobile-staff-build PLATFORM=apk MODE=dev 2>&1 | tee staff_build.txt || true + + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + + # Check for actual errors in both builds + if grep -E "^\s*(error|SEVERE|Error|failed)" client_build.txt > /dev/null 2>&1 || \ + grep -E "^\s*(error|SEVERE|Error|failed)" staff_build.txt > /dev/null 2>&1; then + echo "โŒ BUILD ERRORS FOUND:" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - grep -B 2 -A 1 -E "^\s*(error|SEVERE):" analyze_output.txt | sed 's/^/ /' + if grep -E "^\s*(error|SEVERE|Error|failed)" client_build.txt > /dev/null 2>&1; then + echo " CLIENT BUILD:" + grep -B 2 -A 1 -E "^\s*(error|SEVERE|Error|failed)" client_build.txt | sed 's/^/ /' + fi + if grep -E "^\s*(error|SEVERE|Error|failed)" staff_build.txt > /dev/null 2>&1; then + echo " STAFF BUILD:" + grep -B 2 -A 1 -E "^\s*(error|SEVERE|Error|failed)" staff_build.txt | sed 's/^/ /' + fi echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" exit 1 else - echo "โœ… Compilation check PASSED - No errors found" + echo "โœ… Build check PASSED - Both apps built successfully" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" fi @@ -128,7 +142,7 @@ jobs: - name: ๐Ÿ“ฆ Get Flutter dependencies run: | - make mobile-install-ci + make mobile-install - name: ๐Ÿ” Lint changed Dart files run: | diff --git a/makefiles/dataconnect.mk b/makefiles/dataconnect.mk index acd5b428..7285b997 100644 --- a/makefiles/dataconnect.mk +++ b/makefiles/dataconnect.mk @@ -19,7 +19,7 @@ else $(error Invalid DC_ENV '$(DC_ENV)'. Use DC_ENV=dev or DC_ENV=validation) endif -.PHONY: dataconnect-enable-apis dataconnect-init dataconnect-deploy dataconnect-sql-migrate dataconnect-generate-sdk dataconnect-generate-sdk-ci dataconnect-sync dataconnect-bootstrap-db check-gcloud-beta dataconnect-clean dataconnect-bootstrap-validation-db dataconnect-file dataconnect-file-validation dataconnect-file-dev dataconnect-seed dataconnect-test +.PHONY: dataconnect-enable-apis dataconnect-init dataconnect-deploy dataconnect-sql-migrate dataconnect-generate-sdk dataconnect-sync dataconnect-bootstrap-db check-gcloud-beta dataconnect-clean dataconnect-bootstrap-validation-db dataconnect-file dataconnect-file-validation dataconnect-file-dev dataconnect-seed dataconnect-test #creation dataconnect file dataconnect-file: @@ -79,9 +79,6 @@ dataconnect-generate-sdk: dataconnect-file @firebase dataconnect:sdk:generate --project=$(FIREBASE_ALIAS) @echo "โœ… Data Connect SDK generation completed for [$(DC_ENV)]." -# CI version: same as regular since Firebase CLI is now installed in CI -dataconnect-generate-sdk-ci: dataconnect-generate-sdk - # Unified backend schema update workflow (schema -> deploy -> SDK) dataconnect-sync: dataconnect-file @echo "--> [1/3] Deploying Data Connect [$(DC_SERVICE)]..." diff --git a/makefiles/mobile.mk b/makefiles/mobile.mk index dd75f3d7..43c3d618 100644 --- a/makefiles/mobile.mk +++ b/makefiles/mobile.mk @@ -1,6 +1,6 @@ # --- Mobile App Development --- -.PHONY: mobile-install mobile-install-ci mobile-info mobile-analyze mobile-client-dev-android mobile-staff-dev-android mobile-client-build mobile-staff-build mobile-hot-reload mobile-hot-restart +.PHONY: mobile-install mobile-info mobile-analyze mobile-client-dev-android mobile-staff-dev-android mobile-client-build mobile-staff-build mobile-hot-reload mobile-hot-restart MOBILE_DIR := apps/mobile @@ -15,13 +15,6 @@ mobile-install: install-melos dataconnect-generate-sdk @echo "--> Generating localization files..." @cd $(MOBILE_DIR) && melos run gen:l10n -mobile-install-ci: install-melos dataconnect-generate-sdk-ci - @echo "--> Bootstrapping mobile workspace for CI (Melos)..." - @cd $(MOBILE_DIR) && melos bootstrap - @echo "--> Generating localization files..." - @cd $(MOBILE_DIR) && melos run gen:l10n - @echo "โœ… CI mobile setup complete" - mobile-info: @echo "--> Fetching mobile command info..." @cd $(MOBILE_DIR) && melos run info From 2162b5493ed8b5a658d326623a97a53b93269899 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 01:33:15 -0500 Subject: [PATCH 16/22] fix: Change build mode from 'dev' to 'debug' for mobile client and staff apps --- .github/workflows/mobile-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 4d53bdd5..3230c8c6 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -89,13 +89,13 @@ jobs: - name: ๐Ÿ”จ Run compilation check run: | echo "๐Ÿ—๏ธ Building client app for Android (dev mode)..." - make mobile-client-build PLATFORM=apk MODE=dev 2>&1 | tee client_build.txt || true + make mobile-client-build PLATFORM=apk MODE=debug 2>&1 | tee client_build.txt || true echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ—๏ธ Building staff app for Android (dev mode)..." - make mobile-staff-build PLATFORM=apk MODE=dev 2>&1 | tee staff_build.txt || true + make mobile-staff-build PLATFORM=apk MODE=debug 2>&1 | tee staff_build.txt || true echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" From 518991f8959c0d97216770864f8e607882bd9bda Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 01:43:03 -0500 Subject: [PATCH 17/22] fix: Improve error handling in mobile app build process --- .github/workflows/mobile-ci.yml | 38 ++++++++++++++------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 3230c8c6..c0d99701 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -89,36 +89,30 @@ jobs: - name: ๐Ÿ”จ Run compilation check run: | echo "๐Ÿ—๏ธ Building client app for Android (dev mode)..." - make mobile-client-build PLATFORM=apk MODE=debug 2>&1 | tee client_build.txt || true + if ! make mobile-client-build PLATFORM=apk MODE=debug 2>&1 | tee client_build.txt; then + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "โŒ CLIENT APP BUILD FAILED" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + exit 1 + fi echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ—๏ธ Building staff app for Android (dev mode)..." - make mobile-staff-build PLATFORM=apk MODE=debug 2>&1 | tee staff_build.txt || true + if ! make mobile-staff-build PLATFORM=apk MODE=debug 2>&1 | tee staff_build.txt; then + echo "" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "โŒ STAFF APP BUILD FAILED" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + exit 1 + fi echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - - # Check for actual errors in both builds - if grep -E "^\s*(error|SEVERE|Error|failed)" client_build.txt > /dev/null 2>&1 || \ - grep -E "^\s*(error|SEVERE|Error|failed)" staff_build.txt > /dev/null 2>&1; then - echo "โŒ BUILD ERRORS FOUND:" - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - if grep -E "^\s*(error|SEVERE|Error|failed)" client_build.txt > /dev/null 2>&1; then - echo " CLIENT BUILD:" - grep -B 2 -A 1 -E "^\s*(error|SEVERE|Error|failed)" client_build.txt | sed 's/^/ /' - fi - if grep -E "^\s*(error|SEVERE|Error|failed)" staff_build.txt > /dev/null 2>&1; then - echo " STAFF BUILD:" - grep -B 2 -A 1 -E "^\s*(error|SEVERE|Error|failed)" staff_build.txt | sed 's/^/ /' - fi - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - exit 1 - else - echo "โœ… Build check PASSED - Both apps built successfully" - echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" - fi + echo "โœ… Build check PASSED - Both apps built successfully" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" lint: name: ๐Ÿงน Lint Changed Files From 50309bfb39e1b8fe15f3465b995a85cba2a34413 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 01:47:47 -0500 Subject: [PATCH 18/22] fix: Add pipefail option to compilation check for better error handling --- .github/workflows/mobile-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index c0d99701..46944d74 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -88,6 +88,8 @@ jobs: - name: ๐Ÿ”จ Run compilation check run: | + set -o pipefail + echo "๐Ÿ—๏ธ Building client app for Android (dev mode)..." if ! make mobile-client-build PLATFORM=apk MODE=debug 2>&1 | tee client_build.txt; then echo "" From c3f8a4768a6af75f3337b88fac64eb4210c89740 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 01:55:16 -0500 Subject: [PATCH 19/22] fix: Update mobile CI workflow for improved error handling and efficiency --- .github/workflows/mobile-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 46944d74..381c76a1 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -89,7 +89,7 @@ jobs: - name: ๐Ÿ”จ Run compilation check run: | set -o pipefail - + echo "๐Ÿ—๏ธ Building client app for Android (dev mode)..." if ! make mobile-client-build PLATFORM=apk MODE=debug 2>&1 | tee client_build.txt; then echo "" @@ -162,7 +162,7 @@ jobs: if [[ -n "$file" && "$file" == *.dart ]]; then echo "๐Ÿ“ Analyzing: $file" - if ! dart analyze "$file" --no-fatal-infos 2>&1 | tee -a lint_output.txt; then + if ! dart analyze "$file" 2>&1 | tee -a lint_output.txt; then HAS_ERRORS=true FAILED_FILES+=("$file") fi From af78b38ea2aff26adbb6b075092972bc97569556 Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 02:01:29 -0500 Subject: [PATCH 20/22] fix: Add pipefail option to lint step for improved error handling --- .github/workflows/mobile-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index 381c76a1..4a6e43ee 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -142,6 +142,8 @@ jobs: - name: ๐Ÿ” Lint changed Dart files run: | + set -o pipefail + # Get the list of changed files CHANGED_FILES="${{ needs.detect-changes.outputs.changed-files }}" From c261b340a17656383c4bafa611c4a2e48da0342b Mon Sep 17 00:00:00 2001 From: Achintha Isuru Date: Fri, 20 Feb 2026 02:09:54 -0500 Subject: [PATCH 21/22] refactor: Replace header implementation with ReportsHeader widget for cleaner code --- .../src/presentation/pages/reports_page.dart | 86 +------------------ 1 file changed, 4 insertions(+), 82 deletions(-) diff --git a/apps/mobile/packages/features/client/reports/lib/src/presentation/pages/reports_page.dart b/apps/mobile/packages/features/client/reports/lib/src/presentation/pages/reports_page.dart index 6c1e73be..823d163b 100644 --- a/apps/mobile/packages/features/client/reports/lib/src/presentation/pages/reports_page.dart +++ b/apps/mobile/packages/features/client/reports/lib/src/presentation/pages/reports_page.dart @@ -86,88 +86,10 @@ class _ReportsPageState extends State body: SingleChildScrollView( child: Column( children: [ - // Header - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - UiColors.primary, - UiColors.buttonPrimaryHover, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Column( - children: [ - Row( - children: [ - GestureDetector( - onTap: () => Modular.to.toClientHome(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: UiColors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - UiIcons.arrowLeft, - color: UiColors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - Text( - context.t.client_reports.title, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: UiColors.white, - ), - ), - ], - ), - const SizedBox(height: 24), - // Tabs - Container( - height: 44, - padding: const EdgeInsets.all(4) - decoration: BoxDecoration( - color: UiColors.white.withOpacity(0.2) - borderRadius: BorderRadius.circular(12), - ), - child: TabBar( - controller: _tabController, - indicator: BoxDecoration( - color: UiColors.white, - borderRadius: BorderRadius.circular(8), - ), - labelColor: UiColors.primary, - unselectedLabelColor: UiColors.white, - labelStyle: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - ), - indicatorSize: TabBarIndicatorSize.tab, - dividerColor: Colors.transparent, - tabs: [ - Tab(text: context.t.client_reports.tabs.today), - Tab(text: context.t.client_reports.tabs.week), - Tab(text: context.t.client_reports.tabs.month), - Tab(text: context.t.client_reports.tabs.quarter), - ], - ), - ), - ], - ), + // Header with title and tabs + ReportsHeader( + tabController: _tabController, + onTabChanged: _loadSummary, ), // Content From b1c5adb85f13de7af8bbb79969d8f945de829ed3 Mon Sep 17 00:00:00 2001 From: dhinesh-m24 Date: Fri, 20 Feb 2026 15:11:49 +0530 Subject: [PATCH 22/22] fix: update use-case.md file to match with updated prototype --- docs/ARCHITECTURE/web-application/use-case.md | 607 ++++++++++++++++-- 1 file changed, 538 insertions(+), 69 deletions(-) diff --git a/docs/ARCHITECTURE/web-application/use-case.md b/docs/ARCHITECTURE/web-application/use-case.md index a4f65c95..e36a1ac6 100644 --- a/docs/ARCHITECTURE/web-application/use-case.md +++ b/docs/ARCHITECTURE/web-application/use-case.md @@ -11,9 +11,10 @@ This document details the primary business actions and user flows within the **K * **Description:** Secure entry into the management console. * **Main Flow:** 1. User enters email and password on the login screen. - 2. System verifies credentials. + 2. System verifies credentials against authentication service. 3. System determines user role (Admin, Client, or Vendor). - 4. User is directed to their specific role-based dashboard. + 4. User is directed to their specific role-based dashboard with customizable widgets. + 5. System loads user-specific dashboard layout preferences. --- @@ -21,67 +22,257 @@ This document details the primary business actions and user flows within the **K ### 2.1 Global Operational Oversight * **Actor:** Admin -* **Description:** Monitoring the pulse of the entire platform. -* **Main Flow:** User accesses Admin Dashboard -> Views all active orders across all clients -> Monitors user registration trends. - -### 2.2 Marketplace & Vendor Management -* **Actor:** Admin -* **Description:** Expanding the platform's supply network. +* **Description:** Monitoring the pulse of the entire platform through a customizable dashboard. * **Main Flow:** - 1. User navigates to Marketplace. - 2. User invites a new Vendor via email. - 3. User sets global default rates for roles. - 4. User audits vendor performance scores. + 1. User accesses Admin Dashboard with global metrics. + 2. Views fill rate, total spend, performance score, and active events. + 3. Monitors today's orders with status indicators (RAPID, Fully Staffed, Partial Staffed). + 4. Reviews action items prioritized by urgency (critical, high, medium). + 5. Accesses ecosystem visualization showing connections between Buyers, Enterprises, Sectors, Partners, and Vendors. + 6. Customizes dashboard widget layout via drag-and-drop. -### 2.3 System Administration +### 2.2 Vendor & Partner Management * **Actor:** Admin -* **Description:** Configuring platform-wide settings and security. -* **Main Flow:** User updates system configurations -> Reviews security audit logs -> Manages internal support tickets. +* **Description:** Managing the vendor network and partnerships. +* **Main Flow:** + 1. User navigates to Vendor Marketplace. + 2. Reviews vendor approval status and performance metrics. + 3. Sets vendor tier levels (Approved Vendor, Gold Vendor). + 4. Monitors vendor CSAT scores and compliance rates. + 5. Views vendor rate books and service rates. + +### 2.3 Order & Schedule Management +* **Actor:** Admin +* **Description:** Overseeing all orders across the platform. +* **Main Flow:** + 1. User views all orders with filtering by status (All, Upcoming, Active, Past, Conflicts). + 2. Reviews order details including business, hub, date/time, assigned staff. + 3. Monitors assignment status (Requested vs Assigned counts). + 4. Detects and resolves scheduling conflicts. + 5. Accesses schedule view for visual timeline. + +### 2.4 Workforce Management +* **Actor:** Admin +* **Description:** Managing platform-wide workforce. +* **Main Flow:** + 1. User navigates to Staff Directory. + 2. Views staff with filters (position, department, hub, profile type). + 3. Monitors compliance status (background checks, certifications). + 4. Reviews staff performance metrics (rating, reliability score, shift coverage). + 5. Manages onboarding workflows for new staff. + +### 2.5 Analytics & Reporting +* **Actor:** Admin +* **Description:** Generating insights through reports and activity logs. +* **Main Flow:** + 1. User accesses Reports Dashboard. + 2. Selects report type (Staffing Cost, Staff Performance, Operational Efficiency, Client Trends). + 3. Configures report parameters and filters. + 4. Views report insights with AI-generated recommendations. + 5. Exports reports in multiple formats (PDF, Excel, CSV). + 6. Reviews Activity Log for audit trail. --- ## 3. Client Executive Workflows -### 3.1 Strategic Insights (Savings Engine) +### 3.1 Dashboard Overview * **Actor:** Client Executive -* **Description:** Using AI to optimize labor spend. +* **Description:** Personalized dashboard for order and labor management. * **Main Flow:** - 1. User opens the Savings Engine. - 2. User reviews identified cost-saving opportunities. - 3. User clicks "Approve Strategy" to implement recommendations (e.g., vendor consolidation). + 1. User opens Client Dashboard with customizable widgets. + 2. Views action items (overdue invoices, unfilled orders, rapid requests). + 3. Monitors key metrics (Today's Count, In Progress, Needs Attention). + 4. Reviews labor summary with cost breakdown by position. + 5. Analyzes sales analytics via pie charts. -### 3.2 Finance & Billing Management -* **Actor:** Client Executive / Finance Admin -* **Description:** Managing corporate financial obligations. -* **Main Flow:** User views all pending invoices -> Downloads detailed line-item reports -> Processes payments to Krow. +### 3.2 Order Management +* **Actor:** Client Executive / Operations Manager +* **Description:** Creating and managing staffing requests. +* **Main Flow:** + 1. User clicks "Order Now" or "RAPID Order" for urgent requests. + 2. Selects business, hub, and event details. + 3. Defines shifts with roles, counts, start/end times, and rates. + 4. Chooses order type (one-time, rapid, recurring, permanent). + 5. Enables conflict detection to prevent scheduling issues. + 6. Reviews detected conflicts before submission. + 7. Submits order to preferred vendor or marketplace. -### 3.3 Operations Overview +### 3.3 Vendor Discovery & Selection * **Actor:** Client Executive -* **Description:** High-level monitoring of venue operations. -* **Main Flow:** User views a summary of their venue orders -> Reviews ratings of assigned staff -> Monitors fulfillment rates. +* **Description:** Finding and managing vendor relationships. +* **Main Flow:** + 1. User navigates to Vendor Marketplace. + 2. Searches and filters vendors by region, category, rating, price. + 3. Views vendor profiles with metrics (staff count, rating, fill rate, response time). + 4. Expands vendor cards to view rate books by category. + 5. Sets preferred vendor for automatic order routing. + 6. Configures vendor preferences (locked vendors for optimization). + 7. Contacts vendors via integrated messaging. + +### 3.4 Savings Engine (Strategic Insights) +* **Actor:** Client Executive +* **Description:** Using AI to optimize labor spend and vendor mix. +* **Main Flow:** + 1. User opens Savings Engine. + 2. Reviews overview cards showing total spend, potential savings, fill rate. + 3. Selects analysis timeframe (7 days, 30 days, Quarter, Year). + 4. Navigates tabs for different insights: + - **Overview**: Dynamic dashboard with savings opportunities + - **Budget**: Budget utilization tracker + - **Strategies**: Smart operation strategies with AI recommendations + - **Predictions**: Cost forecasts and trend analysis + - **Vendors**: Vendor performance comparison + 5. Views actionable strategies (vendor consolidation, rate optimization). + 6. Exports analysis report. + +### 3.5 Finance & Invoicing +* **Actor:** Client Executive / Finance Admin +* **Description:** Managing invoices and payments. +* **Main Flow:** + 1. User views invoice list filtered by status (Open, Overdue, Paid, Disputed). + 2. Opens invoice detail to review line items by role and staff. + 3. Views from/to company information and payment terms. + 4. Downloads invoice in PDF or Excel format. + 5. Processes payment or disputes invoice with reason. + 6. Tracks payment history. + +### 3.6 Communication & Support +* **Actor:** Client Executive +* **Description:** Engaging with vendors and getting help. +* **Main Flow:** + 1. User accesses Message Center for conversations. + 2. Initiates conversation with vendors or admins. + 3. Views conversation threads grouped by type (client-vendor, client-admin). + 4. Accesses Tutorials for platform guidance. + 5. Submits support tickets via Support Center. --- ## 4. Vendor Workflows (Staffing Agency) -### 4.1 Vendor Operations (Order Fulfillment) +### 4.1 Vendor Dashboard +* **Actor:** Vendor Manager +* **Description:** Comprehensive view of operations and performance. +* **Main Flow:** + 1. User accesses Vendor Dashboard with customizable widgets. + 2. Views KPI cards (Orders Today, In Progress, RAPID, Staff Assigned). + 3. Monitors action items (urgent unfilled orders, expiring certifications, invoices to submit). + 4. Reviews recent orders table with assignment status. + 5. Accesses revenue carousel showing monthly revenue, total revenue, active orders. + 6. Views top clients by revenue and order count. + 7. Reviews client loyalty status (Champion, Loyal, At Risk). + 8. Monitors top performer staff by rating. + +### 4.2 Order Fulfillment * **Actor:** Vendor Manager * **Description:** Fulfilling client staffing requests. * **Main Flow:** - 1. User views incoming shift requests. - 2. User selects a shift. - 3. User uses the **Worker Selection Tool** to assign the best-fit staff. - 4. User confirms assignment. + 1. User views incoming orders via "Orders" section. + 2. Filters orders by tab (All, Conflicts, Upcoming, Active, Past). + 3. Reviews order details (business, hub, event, date/time, roles). + 4. Identifies RAPID orders (< 24 hours) needing immediate attention. + 5. Clicks "Assign Staff" to open Smart Assign Modal. + 6. Selects optimal staff based on skills, availability, and proximity. + 7. Confirms assignments and updates order status. + 8. Reviews conflict alerts for staff/venue overlaps. -### 4.2 Workforce Roster Management +### 4.3 Workforce Roster Management * **Actor:** Vendor Manager -* **Description:** Maintaining their agency's supply of workers. -* **Main Flow:** User navigates to Roster -> Adds new workers -> Updates compliance documents and certifications -> Edits worker profiles. +* **Description:** Managing agency's worker pool. +* **Main Flow:** + 1. User navigates to Staff Directory. + 2. Views staff with filtering options (profile type, position, department, hub). + 3. Toggles between grid and list view. + 4. Adds new staff via "Add Staff" button. + 5. Fills staff profile form (personal info, position, department, hub, contact). + 6. Edits existing staff profiles. + 7. Monitors staff metrics (rating, reliability score, shift coverage, cancellations). + 8. Reviews compliance status (background checks, certifications). -### 4.3 Vendor Finance +### 4.4 Staff Onboarding * **Actor:** Vendor Manager -* **Description:** Managing agency revenue and worker payouts. -* **Main Flow:** User views payout history -> Submits invoices for completed shifts -> Tracks pending payments from Krow. +* **Description:** Streamlined multi-step onboarding for new workers. +* **Main Flow:** + 1. User navigates to "Onboard Staff" section. + 2. Completes profile setup step (name, email, position, department). + 3. Uploads required documents (ID, certifications, licenses). + 4. Assigns training modules. + 5. Reviews completion status. + 6. Activates staff member upon completion. + +### 4.5 Compliance Management +* **Actor:** Vendor Manager +* **Description:** Maintaining workforce compliance standards. +* **Main Flow:** + 1. User accesses Compliance Dashboard. + 2. Views compliance metrics (background check status, certification expiry). + 3. Filters staff needing attention. + 4. Updates compliance documents in Document Vault. + 5. Tracks certification renewal deadlines. + +### 4.6 Schedule & Availability +* **Actor:** Vendor Manager +* **Description:** Managing staff availability and schedules. +* **Main Flow:** + 1. User navigates to Staff Availability. + 2. Views calendar-based availability grid. + 3. Updates staff availability preferences. + 4. Accesses Schedule view for visual timeline of assignments. + 5. Identifies gaps and conflicts. + +### 4.7 Client Relationship Management +* **Actor:** Vendor Manager +* **Description:** Managing client accounts and preferences. +* **Main Flow:** + 1. User navigates to Clients section. + 2. Views client list with business details. + 3. Adds new client accounts. + 4. Edits client information (contact, address, hubs, departments). + 5. Configures client preferences (favorite staff, blocked staff). + 6. Sets ERP integration details (vendor ID, cost center, EDI format). + +### 4.8 Rate Management +* **Actor:** Vendor Manager +* **Description:** Managing service rates and pricing. +* **Main Flow:** + 1. User accesses Service Rates section. + 2. Views rate cards by client and role. + 3. Creates new rate entries (role, client rate, employee wage). + 4. Configures markup percentage and vendor fee. + 5. Sets approved cap rates. + 6. Activates/deactivates rates. + +### 4.9 Vendor Finance & Invoicing +* **Actor:** Vendor Manager +* **Description:** Managing revenue and submitting invoices. +* **Main Flow:** + 1. User views invoice list for completed orders. + 2. Auto-generates invoices from completed events. + 3. Reviews invoice details with staff entries and line items. + 4. Edits invoice before submission if needed. + 5. Submits invoice to client. + 6. Tracks invoice status (Draft, Open, Confirmed, Paid). + 7. Downloads invoice for records. + +### 4.10 Performance Analytics +* **Actor:** Vendor Manager +* **Description:** Monitoring vendor performance metrics. +* **Main Flow:** + 1. User accesses Performance section. + 2. Reviews fill rate, on-time performance, client satisfaction. + 3. Views staff performance leaderboard. + 4. Analyzes revenue trends by client and timeframe. + +### 4.11 Savings Engine (Growth Opportunities) +* **Actor:** Vendor Manager +* **Description:** Identifying growth and optimization opportunities. +* **Main Flow:** + 1. User opens Savings Engine with vendor-specific tabs. + 2. Reviews performance metrics and benchmarks. + 3. Identifies opportunities to improve ratings and win more business. + 4. Views workforce utilization statistics. + 5. Analyzes growth forecasts. --- @@ -90,16 +281,181 @@ This document details the primary business actions and user flows within the **K ### 5.1 Order Details & History * **Actor:** All Roles * **Description:** Accessing granular data for any specific staffing request. -* **Main Flow:** User clicks any order ID -> System displays shift times, roles, assigned staff, and audit history. +* **Main Flow:** + 1. User clicks any order ID from lists or dashboards. + 2. System displays comprehensive order information: + - Event details (name, business, hub, date, time) + - Shift configuration with roles, counts, and rates + - Assigned staff with profiles + - Status history and audit trail + - Detected conflicts (if any) + - Invoice linkage (if completed) + 3. User can edit order (if permissions allow). + 4. User can assign/reassign staff. + 5. User can view related invoices. ### 5.2 Invoice Detail View * **Actor:** Admin, Client, Vendor * **Description:** Reviewing the breakdown of costs for a billing period. -* **Main Flow:** User opens an invoice -> System displays worker names, hours worked, bill rates, and total totals per role. +* **Main Flow:** + 1. User opens an invoice from the invoice list. + 2. System displays invoice header (invoice number, dates, status, parties). + 3. Views detailed breakdown: + - Roles section with staff entries per role + - Hours worked (regular, overtime, double-time) + - Bill rates and totals per role + - Additional charges + - Subtotal and grand total + 4. Reviews payment terms and PO reference. + 5. Downloads invoice in PDF or Excel. + 6. Copies invoice data to clipboard. + 7. Sends invoice via email (vendor role). + 8. Approves or disputes invoice (client role). + +### 5.3 Task Board +* **Actor:** All Roles +* **Description:** Collaborative task management across teams. +* **Main Flow:** + 1. User accesses Task Board. + 2. Views tasks in columns by status (Pending, In Progress, On Hold, Completed). + 3. Drags tasks between columns to update status. + 4. Creates new tasks with details (name, description, priority, due date). + 5. Assigns tasks to team members. + 6. Adds comments and attachments to tasks. + 7. Filters tasks by department, priority, or assignee. + +### 5.4 Message Center +* **Actor:** All Roles +* **Description:** Cross-platform communication hub. +* **Main Flow:** + 1. User accesses Message Center. + 2. Views conversation list with unread counts. + 3. Filters by conversation type (client-vendor, client-admin, internal). + 4. Opens conversation thread. + 5. Sends messages with attachments. + 6. Views system-generated messages for automated events. + 7. Archives completed conversations. + +### 5.5 Reports & Analytics +* **Actor:** All Roles (with role-specific access) +* **Description:** Data-driven insights and custom reporting. +* **Main Flow:** + 1. User accesses Reports Dashboard. + 2. Selects from report types: + - Staffing Cost Report + - Staff Performance Report + - Operational Efficiency Report + - Client Trends Report + - Custom Report Builder + 3. Configures report parameters (date range, filters, grouping). + 4. Views AI-generated insights banner with key findings. + 5. Exports report in preferred format. + 6. Schedules recurring reports for automated delivery. + 7. Saves report templates for reuse. + +### 5.6 Teams Management +* **Actor:** Admin, Client, Vendor +* **Description:** Creating and managing staff teams. +* **Main Flow:** + 1. User navigates to Teams section. + 2. Views team list with member counts. + 3. Creates new team with name and description. + 4. Adds team members from staff directory. + 5. Views team detail page with member profiles. + 6. Assigns teams to orders as groups. + +### 5.7 Staff Conflict Detection +* **Actor:** Admin, Vendor +* **Description:** Automated detection of scheduling conflicts. +* **Main Flow:** + 1. System automatically detects conflicts when creating/editing orders: + - **Staff Overlap**: Same staff assigned to overlapping shifts + - **Venue Overlap**: Same venue booked for overlapping times + - **Time Buffer**: Insufficient travel time between assignments + 2. System assigns severity level (Critical, High, Medium, Low). + 3. Displays conflict alerts with details (conflicting event, staff, location). + 4. User resolves conflicts before finalizing order. + 5. System tracks conflict resolution in audit log. + +### 5.8 Dashboard Customization +* **Actor:** All Roles +* **Description:** Personalizing dashboard layouts. +* **Main Flow:** + 1. User clicks "Customize Dashboard" button. + 2. Enters customization mode with drag-and-drop interface. + 3. Reorders widgets by dragging. + 4. Hides/shows widgets using visibility controls. + 5. Previews changes in real-time. + 6. Saves layout preferences to user profile. + 7. Resets to default layout if desired. + +--- + +## 6. Advanced Features + +### 6.1 Smart Assignment Engine (Vendor) +* **Actor:** Vendor Manager +* **Description:** AI-powered staff assignment optimization. +* **Main Flow:** + 1. User clicks "Smart Assign" on an order. + 2. System analyzes requirements (skills, location, time, availability). + 3. Engine scores available staff based on: + - Skill match + - Proximity to venue + - Past performance + - Availability + - Client preferences + 4. Presents ranked staff recommendations. + 5. User reviews suggestions and confirms assignments. + +### 6.2 Auto-Invoice Generation +* **Actor:** Vendor Manager +* **Description:** Automated invoice creation from completed orders. +* **Main Flow:** + 1. When order status changes to "Completed", system triggers auto-invoice. + 2. System aggregates staff entries, hours, and rates. + 3. Generates invoice line items by role. + 4. Calculates totals (regular, overtime, double-time). + 5. Applies additional charges if configured. + 6. Creates draft invoice for vendor review. + 7. Vendor reviews and submits to client. + +### 6.3 Vendor Preferences & Optimization (Client) +* **Actor:** Client Executive +* **Description:** Configuring vendor routing and procurement strategies. +* **Main Flow:** + 1. User accesses Client Vendor Preferences panel. + 2. Sets preferred vendor for automatic order routing. + 3. Configures locked vendors (never used for optimization). + 4. Enables/disables procurement optimization. + 5. System respects preferences when suggesting vendors in Savings Engine. + +### 6.4 Contract Conversion & Tier Optimization +* **Actor:** Admin, Client (via Savings Engine) +* **Description:** Analyzing opportunities to move spend to preferred vendors. +* **Main Flow:** + 1. User accesses "Conversion Map" tab in Savings Engine. + 2. Views non-contracted spend by vendor. + 3. System identifies conversion opportunities to approved/gold vendors. + 4. Reviews potential savings from rate arbitrage. + 5. Approves conversion strategy. + 6. System routes future orders accordingly. + +### 6.5 Predictive Savings Model +* **Actor:** Admin, Client +* **Description:** Forecasting cost savings through AI analysis. +* **Main Flow:** + 1. User accesses "Predictions" tab in Savings Engine. + 2. System analyzes historical spend, rates, and vendor performance. + 3. Generates forecasts for 7 days, 30 days, quarter, year. + 4. Identifies rate optimization opportunities. + 5. Recommends vendor consolidation strategies. + 6. Shows projected ROI for each strategy. --- # Use Case Diagram + ```mermaid flowchart TD subgraph AccessControl [Access & Authentication] @@ -118,53 +474,166 @@ flowchart TD subgraph AdminWorkflows [Admin Workflows] AdminDash --> GlobalOversight[Global Oversight] + GlobalOversight --> EcosystemWheel[Ecosystem Wheel] GlobalOversight --> ViewAllOrders[View All Orders] - GlobalOversight --> ViewAllUsers[View All Users] + GlobalOversight --> ActionItems[Action Items] - AdminDash --> MarketplaceMgmt[Marketplace Management] - MarketplaceMgmt --> OnboardVendor[Onboard Vendor] - MarketplaceMgmt --> ManageRates[Manage Global Rates] + AdminDash --> VendorMgmt[Vendor Management] + VendorMgmt --> ApproveVendors[Approve Vendors] + VendorMgmt --> SetTiers[Set Vendor Tiers] - AdminDash --> SystemAdmin[System Administration] - SystemAdmin --> ConfigSettings[Configure Settings] - SystemAdmin --> AuditLogs[View Audit Logs] + AdminDash --> WorkforceMgmt[Workforce Management] + WorkforceMgmt --> StaffDirectory[Staff Directory] + WorkforceMgmt --> Compliance[Compliance Dashboard] + + AdminDash --> AnalyticsReports[Analytics & Reports] + AnalyticsReports --> ReportsDashboard[Reports Dashboard] + AnalyticsReports --> ActivityLog[Activity Log] end subgraph ClientWorkflows [Client Executive Workflows] - ClientDash --> ClientInsights[Strategic Insights] - ClientInsights --> SavingsEngine[Savings Engine] - SavingsEngine --> ViewOpp[View Opportunity] - ViewOpp --> ApproveStrategy[Approve Strategy] + ClientDash --> ClientActionItems[Action Items] + ClientActionItems --> ReviewAlerts[Review Alerts] - ClientDash --> ClientFinance[Finance & Billing] + ClientDash --> OrderMgmt[Order Management] + OrderMgmt --> CreateOrder[Create Order] + CreateOrder --> DefineShifts[Define Shifts & Roles] + DefineShifts --> ConflictDetection[Conflict Detection] + ConflictDetection --> SubmitOrder[Submit Order] + + OrderMgmt --> ViewMyOrders[View My Orders] + ViewMyOrders --> OrderDetail[Order Detail] + + ClientDash --> VendorDiscovery[Vendor Discovery] + VendorDiscovery --> BrowseMarketplace[Browse Marketplace] + BrowseMarketplace --> SetPreferred[Set Preferred Vendor] + BrowseMarketplace --> ContactVendor[Contact Vendor] + + ClientDash --> SavingsEngine[Savings Engine] + SavingsEngine --> AnalyzeSpend[Analyze Spend] + AnalyzeSpend --> ViewStrategies[View Strategies] + ViewStrategies --> ApproveStrategy[Approve Strategy] + SavingsEngine --> PredictiveSavings[Predictive Savings] + SavingsEngine --> ConversionMap[Conversion Map] + + ClientDash --> ClientFinance[Finance & Invoicing] ClientFinance --> ViewInvoices[View Invoices] - ClientFinance --> PayInvoice[Pay Invoice] + ViewInvoices --> InvoiceDetail[Invoice Detail] + InvoiceDetail --> PayInvoice[Pay Invoice] + InvoiceDetail --> DisputeInvoice[Dispute Invoice] - ClientDash --> ClientOps[Operations Overview] - ClientOps --> ViewMyOrders[View My Orders] - ClientOps --> ViewMyStaff[View Assigned Staff] + ClientDash --> Communication[Communication] + Communication --> MessageCenter[Message Center] + Communication --> SupportCenter[Support Center] end subgraph VendorWorkflows [Vendor Workflows] - VendorDash --> VendorOps[Vendor Operations] - VendorOps --> ViewRequests[View Shift Requests] - ViewRequests --> AssignWorker[Assign Worker] - VendorOps --> ManageRoster[Manage Worker Roster] - ManageRoster --> UpdateWorkerProfile[Update Worker Profile] + VendorDash --> VendorKPIs[KPI Dashboard] + VendorKPIs --> RevenueStats[Revenue Stats] + VendorKPIs --> TopClients[Top Clients] + VendorKPIs --> TopPerformers[Top Performers] - VendorDash --> VendorFinance[Vendor Finance] - VendorFinance --> ViewPayouts[View Payouts] + VendorDash --> OrderFulfillment[Order Fulfillment] + OrderFulfillment --> ViewOrders[View Orders] + ViewOrders --> FilterOrders[Filter Orders] + FilterOrders --> AssignStaff[Smart Assign Staff] + AssignStaff --> ResolveConflicts[Resolve Conflicts] + + VendorDash --> RosterMgmt[Roster Management] + RosterMgmt --> StaffDir[Staff Directory] + StaffDir --> AddStaff[Add Staff] + StaffDir --> EditStaff[Edit Staff] + StaffDir --> ViewMetrics[View Staff Metrics] + + RosterMgmt --> OnboardStaff[Onboard Staff] + OnboardStaff --> ProfileSetup[Profile Setup] + ProfileSetup --> UploadDocs[Upload Documents] + UploadDocs --> AssignTraining[Assign Training] + AssignTraining --> ActivateStaff[Activate Staff] + + VendorDash --> ComplianceMgmt[Compliance Management] + ComplianceMgmt --> ComplianceDash[Compliance Dashboard] + ComplianceDash --> DocumentVault[Document Vault] + ComplianceDash --> CertTracking[Certification Tracking] + + VendorDash --> ScheduleAvail[Schedule & Availability] + ScheduleAvail --> StaffAvailability[Staff Availability] + ScheduleAvail --> ScheduleView[Schedule View] + + VendorDash --> ClientMgmt[Client Management] + ClientMgmt --> ManageClients[Manage Clients] + ManageClients --> ClientPrefs[Client Preferences] + + VendorDash --> RateMgmt[Rate Management] + RateMgmt --> ServiceRates[Service Rates] + ServiceRates --> RateCards[Rate Cards] + + VendorDash --> VendorFinance[Finance] + VendorFinance --> AutoInvoice[Auto-Generate Invoice] VendorFinance --> SubmitInvoice[Submit Invoice] + VendorFinance --> TrackPayments[Track Payments] + + VendorDash --> VendorPerformance[Performance Analytics] + VendorPerformance --> FillRate[Fill Rate] + VendorPerformance --> CSAT[Client Satisfaction] + VendorPerformance --> RevenueAnalysis[Revenue Analysis] end subgraph SharedModules [Shared Functional Modules] - ViewAllOrders -.-> OrderDetail[Order Details] - ViewMyOrders -.-> OrderDetail - ViewRequests -.-> OrderDetail + TaskBoard[Task Board] -.-> Tasks[Manage Tasks] + Tasks -.-> DragDrop[Drag & Drop Status] - AssignWorker -.-> WorkerSelection[Worker Selection Tool] + MessageCenter -.-> Conversations[Conversations] + Conversations -.-> SendMessage[Send Message] - ViewInvoices -.-> InvoiceDetail[Invoice Detail View] - SubmitInvoice -.-> InvoiceDetail + ReportsDashboard -.-> ReportTypes[Report Types] + ReportTypes -.-> CustomBuilder[Custom Report Builder] + ReportTypes -.-> ScheduledReports[Scheduled Reports] + ReportTypes -.-> ExportReport[Export Report] + + TeamsModule[Teams] -.-> CreateTeam[Create Team] + CreateTeam -.-> AddMembers[Add Members] + + DashboardCustom[Dashboard Customization] -.-> DragWidgets[Drag Widgets] + DragWidgets -.-> HideShow[Hide/Show Widgets] + HideShow -.-> SaveLayout[Save Layout] end ``` + +--- + +## Summary of Key Enhancements + +**Compared to the original document, this updated version includes:** + +1. **Detailed Dashboard Workflows**: Comprehensive descriptions of customizable dashboards for each role with specific widgets and metrics. + +2. **Advanced Order Management**: Multi-step order creation with shift configuration, conflict detection, and order type options (one-time, rapid, recurring, permanent). + +3. **Smart Assignment**: AI-powered staff assignment engine for vendors to optimize worker selection. + +4. **Savings Engine**: Detailed AI-driven cost optimization workflows with predictive modeling, vendor conversion strategies, and budget tracking. + +5. **Vendor Marketplace**: Complete vendor discovery and selection process with filtering, rate comparison, and preference settings. + +6. **Enhanced Finance**: Auto-invoice generation, detailed invoice views, export capabilities, and dispute resolution. + +7. **Onboarding Workflow**: Multi-step staff onboarding process for vendors. + +8. **Compliance Management**: Dedicated compliance dashboard and document vault. + +9. **Conflict Detection**: Automated scheduling conflict detection with severity levels. + +10. **Communication Hub**: Integrated message center for cross-platform communication. + +11. **Teams Management**: Team creation and assignment workflows. + +12. **Advanced Analytics**: Multiple report types, custom report builder, scheduled reports, and AI-generated insights. + +13. **Dashboard Customization**: Drag-and-drop widget management with layout persistence. + +14. **Schedule & Availability**: Calendar-based staff availability management with visual schedule view. + +15. **Client & Rate Management**: Vendor-side client relationship and service rate management. + +This document now accurately reflects the robust feature set implemented in the krow_web_application.