diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json b/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json index 851578db..40b07667 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json +++ b/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json @@ -148,9 +148,17 @@ "edit_mode_active": "Edit Mode Active", "drag_instruction": "Drag to reorder, toggle visibility", "reset": "Reset", + "todays_coverage": "TODAY'S COVERAGE", + "percent_covered": "$percent% Covered", "metric_needed": "Needed", "metric_filled": "Filled", "metric_open": "Open", + "spending": { + "this_week": "This Week", + "next_7_days": "Next 7 Days", + "shifts_count": "$count shifts", + "scheduled_count": "$count scheduled" + }, "view_all": "View all", "insight_lightbulb": "Save $amount/month", "insight_tip": "Book 48hrs ahead for better rates" @@ -237,6 +245,14 @@ "scan_button": "Scan NFC Tag", "tag_identified": "Tag Identified", "assign_button": "Assign Tag" + }, + "delete_dialog": { + "title": "Confirm Hub Deletion", + "message": "Are you sure you want to delete \"$hubName\"?", + "undo_warning": "This action cannot be undone.", + "dependency_warning": "Note that if there are any shifts/orders assigned to this hub we shouldn't be able to delete the hub.", + "cancel": "Cancel", + "delete": "Delete" } }, "client_create_order": { @@ -337,14 +353,26 @@ "cancelled": "CANCELLED", "get_direction": "Get direction", "total": "Total", - "hrs": "HRS", + "hrs": "Hrs", "workers": "$count workers", "clock_in": "CLOCK IN", "clock_out": "CLOCK OUT", "coverage": "Coverage", "workers_label": "$filled/$needed Workers", "confirmed_workers": "Workers Confirmed", - "no_workers": "No workers confirmed yet." + "no_workers": "No workers confirmed yet.", + "today": "Today", + "tomorrow": "Tomorrow", + "workers_needed": "$count Workers Needed", + "all_confirmed": "All Workers Confirmed", + "confirmed_workers_title": "CONFIRMED WORKERS", + "message_all": "Message All", + "show_more_workers": "Show $count more workers", + "checked_in": "Checked In", + "call_dialog": { + "title": "Call", + "message": "Do you want to call $phone?" + } } }, "client_billing": { @@ -498,6 +526,10 @@ "menu_items": { "personal_info": "Personal Info", "emergency_contact": "Emergency Contact", + "emergency_contact_page": { + "save_success": "Emergency contacts saved successfully", + "save_continue": "Save & Continue" + }, "experience": "Experience", "attire": "Attire", "documents": "Documents", @@ -853,6 +885,7 @@ }, "staff_certificates": { "title": "Certificates", + "error_loading": "Error loading certificates", "progress": { "title": "Your Progress", "verified_count": "$completed of $total verified", @@ -988,6 +1021,41 @@ "applying_dialog": { "title": "Applying" } + }, + "card": { + "just_now": "Just now", + "assigned": "Assigned $time ago", + "accept_shift": "Accept shift", + "decline_shift": "Decline shift" + }, + "my_shifts_tab": { + "confirm_dialog": { + "title": "Accept Shift", + "message": "Are you sure you want to accept this shift?", + "success": "Shift confirmed!" + }, + "decline_dialog": { + "title": "Decline Shift", + "message": "Are you sure you want to decline this shift? This action cannot be undone.", + "success": "Shift declined." + }, + "sections": { + "awaiting": "Awaiting Confirmation", + "cancelled": "Cancelled Shifts", + "confirmed": "Confirmed Shifts" + }, + "empty": { + "title": "No shifts this week", + "subtitle": "Try finding new jobs in the Find tab" + }, + "date": { + "today": "Today", + "tomorrow": "Tomorrow" + }, + "card": { + "cancelled": "CANCELLED", + "compensation": "• 4hr compensation" + } } }, "staff_time_card": { diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json b/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json index 6abaaf82..7627b0e3 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json +++ b/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json @@ -148,9 +148,17 @@ "edit_mode_active": "Modo Edición Activo", "drag_instruction": "Arrastra para reordenar, cambia la visibilidad", "reset": "Restablecer", + "todays_coverage": "COBERTURA DE HOY", + "percent_covered": "$percent% Cubierto", "metric_needed": "Necesario", "metric_filled": "Lleno", "metric_open": "Abierto", + "spending": { + "this_week": "Esta Semana", + "next_7_days": "Próximos 7 Días", + "shifts_count": "$count turnos", + "scheduled_count": "$count programados" + }, "view_all": "Ver todo", "insight_lightbulb": "Ahorra $amount/mes", "insight_tip": "Reserva con 48h de antelación para mejores tarifas" @@ -237,6 +245,14 @@ "scan_button": "Escanear Etiqueta NFC", "tag_identified": "Etiqueta Identificada", "assign_button": "Asignar Etiqueta" + }, + "delete_dialog": { + "title": "Confirmar eliminación de Hub", + "message": "¿Estás seguro de que quieres eliminar \"$hubName\"?", + "undo_warning": "Esta acción no se puede deshacer.", + "dependency_warning": "Ten en cuenta que si hay turnos/órdenes asignados a este hub no deberíamos poder eliminarlo.", + "cancel": "Cancelar", + "delete": "Eliminar" } }, "client_create_order": { @@ -337,14 +353,26 @@ "cancelled": "CANCELADO", "get_direction": "Obtener dirección", "total": "Total", - "hrs": "HRS", + "hrs": "Hrs", "workers": "$count trabajadores", "clock_in": "ENTRADA", "clock_out": "SALIDA", "coverage": "Cobertura", "workers_label": "$filled/$needed Trabajadores", "confirmed_workers": "Trabajadores Confirmados", - "no_workers": "Ningún trabajador confirmado aún." + "no_workers": "Ningún trabajador confirmado aún.", + "today": "Hoy", + "tomorrow": "Mañana", + "workers_needed": "$count Trabajadores Necesarios", + "all_confirmed": "Todos los trabajadores confirmados", + "confirmed_workers_title": "TRABAJADORES CONFIRMADOS", + "message_all": "Mensaje a todos", + "show_more_workers": "Mostrar $count trabajadores más", + "checked_in": "Registrado", + "call_dialog": { + "title": "Llamar", + "message": "¿Quieres llamar a $phone?" + } } }, "client_billing": { @@ -498,6 +526,10 @@ "menu_items": { "personal_info": "Información Personal", "emergency_contact": "Contacto de Emergencia", + "emergency_contact_page": { + "save_success": "Contactos de emergencia guardados con éxito", + "save_continue": "Guardar y Continuar" + }, "experience": "Experiencia", "attire": "Vestimenta", "documents": "Documentos", @@ -853,6 +885,7 @@ }, "staff_certificates": { "title": "Certificados", + "error_loading": "Error al cargar certificados", "progress": { "title": "Tu Progreso", "verified_count": "$completed de $total verificados", @@ -988,6 +1021,41 @@ "applying_dialog": { "title": "Solicitando" } + }, + "card": { + "just_now": "Recién", + "assigned": "Asignado hace $time", + "accept_shift": "Aceptar turno", + "decline_shift": "Rechazar turno" + }, + "my_shifts_tab": { + "confirm_dialog": { + "title": "Aceptar Turno", + "message": "¿Estás seguro de que quieres aceptar este turno?", + "success": "¡Turno confirmado!" + }, + "decline_dialog": { + "title": "Rechazar Turno", + "message": "¿Estás seguro de que quieres rechazar este turno? Esta acción no se puede deshacer.", + "success": "Turno rechazado." + }, + "sections": { + "awaiting": "Esperando Confirmación", + "cancelled": "Turnos Cancelados", + "confirmed": "Turnos Confirmados" + }, + "empty": { + "title": "Sin turnos esta semana", + "subtitle": "Intenta buscar nuevos trabajos en la pestaña Buscar" + }, + "date": { + "today": "Hoy", + "tomorrow": "Mañana" + }, + "card": { + "cancelled": "CANCELADO", + "compensation": "• Compensación de 4h" + } } }, "staff_time_card": { diff --git a/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart b/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart index 6b07dcf1..f9ea9264 100644 --- a/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart +++ b/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart @@ -238,7 +238,7 @@ class AuthRepositoryImpl final QueryResult response = await executeProtected(() => _dataConnect.getUserById(id: firebaseUserId).execute()); final dc.GetUserByIdUser? user = response.data.user; - return user != null && user.userRole == 'BUSINESS'; + return user != null && (user.userRole == 'BUSINESS' || user.userRole == 'BOTH'); } /// Creates Business and User entities in PostgreSQL for a Firebase user. @@ -261,18 +261,28 @@ class AuthRepositoryImpl final dc.CreateBusinessBusinessInsert businessData = createBusinessResponse.data.business_insert; onBusinessCreated(businessData.id); - // Create User entity in PostgreSQL + // Check if User entity already exists in PostgreSQL + final QueryResult userResult = + await executeProtected(() => _dataConnect.getUserById(id: firebaseUser.uid).execute()); + final dc.GetUserByIdUser? existingUser = userResult.data.user; - final OperationResult createUserResponse = - await executeProtected(() => _dataConnect.createUser( - id: firebaseUser.uid, - role: dc.UserBaseRole.USER, - ) - .email(email) - .userRole('BUSINESS') - .execute()); - - final dc.CreateUserUserInsert newUserData = createUserResponse.data.user_insert; + if (existingUser != null) { + // User exists (likely in another app like STAFF). Update role to BOTH. + await executeProtected(() => _dataConnect.updateUser( + id: firebaseUser.uid, + ) + .userRole('BOTH') + .execute()); + } else { + // Create new User entity in PostgreSQL + await executeProtected(() => _dataConnect.createUser( + id: firebaseUser.uid, + role: dc.UserBaseRole.USER, + ) + .email(email) + .userRole('BUSINESS') + .execute()); + } return _getUserProfile( firebaseUserId: firebaseUser.uid, @@ -331,11 +341,11 @@ class AuthRepositoryImpl technicalMessage: 'Firebase UID $firebaseUserId not found in users table', ); } - if (requireBusinessRole && user.userRole != 'BUSINESS') { + if (requireBusinessRole && user.userRole != 'BUSINESS' && user.userRole != 'BOTH') { await _firebaseAuth.signOut(); dc.ClientSessionStore.instance.clear(); throw UnauthorizedAppException( - technicalMessage: 'User role is ${user.userRole}, expected BUSINESS', + technicalMessage: 'User role is ${user.userRole}, expected BUSINESS or BOTH', ); } diff --git a/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_get_started_page.dart b/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_get_started_page.dart index c6bd75be..f730ba34 100644 --- a/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_get_started_page.dart +++ b/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_get_started_page.dart @@ -27,94 +27,108 @@ class ClientGetStartedPage extends StatelessWidget { ), SafeArea( - child: Column( - children: [ - const SizedBox(height: UiConstants.space10), - // Logo - Center( - child: Image.asset( - UiImageAssets.logoBlue, - height: 40, - fit: BoxFit.contain, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: constraints.maxHeight, + ), + child: IntrinsicHeight( + child: Column( + children: [ + const SizedBox(height: UiConstants.space10), + // Logo + Center( + child: Image.asset( + UiImageAssets.logoBlue, + height: 40, + fit: BoxFit.contain, + ), + ), + + const Spacer(), + + // Content Cards Area (Keeping prototype layout) + Container( + height: 300, + padding: const EdgeInsets.symmetric( + horizontal: UiConstants.space6, + ), + child: Stack( + children: [ + // Representative cards from prototype + Positioned( + top: 20, + left: 0, + right: 20, + child: _ShiftOrderCard(), + ), + Positioned( + bottom: 40, + right: 0, + left: 40, + child: _WorkerProfileCard(), + ), + Positioned( + top: 60, + right: 10, + child: _CalendarCard(), + ), + ], + ), + ), + + const Spacer(), + + // Bottom Content + Padding( + padding: const EdgeInsets.symmetric( + horizontal: UiConstants.space6, + vertical: UiConstants.space10, + ), + child: Column( + children: [ + Text( + t.client_authentication.get_started_page.title, + textAlign: TextAlign.center, + style: UiTypography.displayM, + ), + const SizedBox(height: UiConstants.space3), + Text( + t.client_authentication.get_started_page + .subtitle, + textAlign: TextAlign.center, + style: UiTypography.body2r.textSecondary, + ), + const SizedBox(height: UiConstants.space8), + + // Sign In Button + UiButton.primary( + text: t.client_authentication.get_started_page + .sign_in_button, + onPressed: () => Modular.to.toClientSignIn(), + fullWidth: true, + ), + + const SizedBox(height: UiConstants.space3), + + // Create Account Button + UiButton.secondary( + text: t.client_authentication.get_started_page + .create_account_button, + onPressed: () => Modular.to.toClientSignUp(), + fullWidth: true, + ), + ], + ), + ), + ], + ), + ), ), - ), - - const Spacer(), - - // Content Cards Area (Keeping prototype layout) - Container( - height: 300, - padding: const EdgeInsets.symmetric( - horizontal: UiConstants.space6, - ), - child: Stack( - children: [ - // Representative cards from prototype - Positioned( - top: 20, - left: 0, - right: 20, - child: _ShiftOrderCard(), - ), - Positioned( - bottom: 40, - right: 0, - left: 40, - child: _WorkerProfileCard(), - ), - Positioned(top: 60, right: 10, child: _CalendarCard()), - ], - ), - ), - - const Spacer(), - - // Bottom Content - Padding( - padding: const EdgeInsets.symmetric( - horizontal: UiConstants.space6, - vertical: UiConstants.space10, - ), - child: Column( - children: [ - Text( - t.client_authentication.get_started_page.title, - textAlign: TextAlign.center, - style: UiTypography.displayM, - ), - const SizedBox(height: UiConstants.space3), - Text( - t.client_authentication.get_started_page.subtitle, - textAlign: TextAlign.center, - style: UiTypography.body2r.textSecondary, - ), - const SizedBox(height: UiConstants.space8), - - // Sign In Button - UiButton.primary( - text: t - .client_authentication - .get_started_page - .sign_in_button, - onPressed: () => Modular.to.toClientSignIn(), - fullWidth: true, - ), - - const SizedBox(height: UiConstants.space3), - - // Create Account Button - UiButton.secondary( - text: t - .client_authentication - .get_started_page - .create_account_button, - onPressed: () => Modular.to.toClientSignUp(), - fullWidth: true, - ), - ], - ), - ), - ], + ); + }, ), ), ], diff --git a/apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart b/apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart index eefd4be3..47a6dbc6 100644 --- a/apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart +++ b/apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart @@ -151,10 +151,12 @@ class CoverageRepositoryImpl implements CoverageRepository { shiftId: app.shiftId, roleId: app.roleId, title: app.shiftRole.role.name, - location: app.shiftRole.shift.location ?? '', - startTime: '00:00', - workersNeeded: 0, - date: date, + location: app.shiftRole.shift.location ?? + app.shiftRole.shift.locationAddress ?? + '', + startTime: _formatTime(app.shiftRole.startTime) ?? '00:00', + workersNeeded: app.shiftRole.count, + date: app.shiftRole.shift.date?.toDateTime() ?? date, workers: [], ); diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/one_time_order/one_time_order_success_view.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/one_time_order/one_time_order_success_view.dart index e2e98350..a9981270 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/one_time_order/one_time_order_success_view.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/one_time_order/one_time_order_success_view.dart @@ -63,6 +63,8 @@ class OneTimeOrderSuccessView extends StatelessWidget { color: UiColors.accent, shape: BoxShape.circle, ), + + child: const Center( child: Icon( UiIcons.check, diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/rapid_order/rapid_order_view.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/rapid_order/rapid_order_view.dart index 559f4b53..da6a5df4 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/rapid_order/rapid_order_view.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/rapid_order/rapid_order_view.dart @@ -72,6 +72,12 @@ class _RapidOrderFormState extends State<_RapidOrderForm> { TextPosition(offset: _messageController.text.length), ); } + } else if (state is RapidOrderFailure) { + UiSnackbar.show( + context, + message: translateErrorKey(state.error), + type: UiSnackbarType.error, + ); } }, child: Scaffold( diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/coverage_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/coverage_widget.dart index cc54f893..d90c7f6d 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/coverage_widget.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/coverage_widget.dart @@ -1,3 +1,4 @@ +import 'package:core_localization/core_localization.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; @@ -47,7 +48,7 @@ class CoverageWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - "TODAY'S COVERAGE", + t.client_home.dashboard.todays_coverage, style: UiTypography.footnote1b.copyWith( color: UiColors.textPrimary, letterSpacing: 0.5, @@ -64,8 +65,8 @@ class CoverageWidget extends StatelessWidget { color: backgroundColor, borderRadius: UiConstants.radiusLg, ), - child: Text( - '$coveragePercent% Covered', + child: Text( + t.client_home.dashboard.percent_covered(percent: coveragePercent), style: UiTypography.footnote2b.copyWith(color: textColor), ), ), @@ -81,7 +82,7 @@ class CoverageWidget extends StatelessWidget { child: _MetricCard( icon: UiIcons.target, iconColor: UiColors.primary, - label: 'Needed', + label: t.client_home.dashboard.metric_needed, value: '$totalNeeded', ), ), @@ -91,7 +92,7 @@ class CoverageWidget extends StatelessWidget { child: _MetricCard( icon: UiIcons.success, iconColor: UiColors.iconSuccess, - label: 'Filled', + label: t.client_home.dashboard.metric_filled, value: '$totalConfirmed', valueColor: UiColors.textSuccess, ), @@ -101,7 +102,7 @@ class CoverageWidget extends StatelessWidget { child: _MetricCard( icon: UiIcons.error, iconColor: UiColors.iconError, - label: 'Open', + label: t.client_home.dashboard.metric_open, value: '${totalNeeded - totalConfirmed}', valueColor: UiColors.textError, ), 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 c2d7d93f..15bdac09 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 @@ -65,6 +65,8 @@ class _ShiftOrderFormSheetState extends State { dc.ListTeamHubsByOwnerIdTeamHubs? _selectedHub; bool _showSuccess = false; Map? _submitData; + bool _isSubmitting = false; + String? _errorMessage; @override void initState() { @@ -190,7 +192,25 @@ class _ShiftOrderFormSheetState extends State { } Future _handleSubmit() async { - await _submitNewOrder(); + if (_isSubmitting) return; + + setState(() { + _isSubmitting = true; + _errorMessage = null; + }); + + try { + await _submitNewOrder(); + } catch (e) { + if (!mounted) return; + setState(() { + _isSubmitting = false; + _errorMessage = 'Failed to create order. Please try again.'; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(_errorMessage!)), + ); + } } Future _submitNewOrder() async { @@ -296,6 +316,7 @@ class _ShiftOrderFormSheetState extends State { 'date': _dateController.text, }; _showSuccess = true; + _isSubmitting = false; }); } @@ -770,7 +791,7 @@ class _ShiftOrderFormSheetState extends State { UiButton.primary( text: widget.initialData != null ? 'Update Order' : 'Post Order', - onPressed: widget.isLoading ? null : _handleSubmit, + onPressed: (widget.isLoading || _isSubmitting) ? null : _handleSubmit, ), SizedBox(height: MediaQuery.of(context).padding.bottom + UiConstants.space5), ], diff --git a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/spending_widget.dart b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/spending_widget.dart index 7ef551ed..f2beac80 100644 --- a/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/spending_widget.dart +++ b/apps/mobile/packages/features/client/home/lib/src/presentation/widgets/spending_widget.dart @@ -78,7 +78,7 @@ class SpendingWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'This Week', + t.client_home.dashboard.spending.this_week, style: UiTypography.footnote2r.white.copyWith( color: UiColors.white.withValues(alpha: 0.7), fontSize: 9, @@ -93,7 +93,7 @@ class SpendingWidget extends StatelessWidget { ), ), Text( - '$weeklyShifts shifts', + t.client_home.dashboard.spending.shifts_count(count: weeklyShifts), style: UiTypography.footnote2r.white.copyWith( color: UiColors.white.withValues(alpha: 0.6), fontSize: 9, @@ -107,7 +107,7 @@ class SpendingWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( - 'Next 7 Days', + t.client_home.dashboard.spending.next_7_days, style: UiTypography.footnote2r.white.copyWith( color: UiColors.white.withValues(alpha: 0.7), fontSize: 9, @@ -122,7 +122,7 @@ class SpendingWidget extends StatelessWidget { ), ), Text( - '$next7DaysScheduled scheduled', + t.client_home.dashboard.spending.scheduled_count(count: next7DaysScheduled), style: UiTypography.footnote2r.white.copyWith( color: UiColors.white.withValues(alpha: 0.6), fontSize: 9, diff --git a/apps/mobile/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart b/apps/mobile/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart index eb93cb7e..c8fdffed 100644 --- a/apps/mobile/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart +++ b/apps/mobile/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart @@ -227,23 +227,23 @@ class ClientHubsPage extends StatelessWidget { } Future _confirmDeleteHub(BuildContext context, Hub hub) async { - final String hubName = hub.name.isEmpty ? 'this hub' : hub.name; + final String hubName = hub.name.isEmpty ? t.client_hubs.title : hub.name; return showDialog( context: context, barrierDismissible: false, builder: (BuildContext dialogContext) { return AlertDialog( - title: const Text('Confirm Hub Deletion'), + title: Text(t.client_hubs.delete_dialog.title), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Are you sure you want to delete "$hubName"?'), + Text(t.client_hubs.delete_dialog.message(hubName: hubName)), const SizedBox(height: UiConstants.space2), - const Text('This action cannot be undone.'), + Text(t.client_hubs.delete_dialog.undo_warning), const SizedBox(height: UiConstants.space2), Text( - 'Note that if there are any shifts/orders assigned to this hub we shouldn\'t be able to delete the hub.', + t.client_hubs.delete_dialog.dependency_warning, style: UiTypography.footnote1r.copyWith( color: UiColors.textSecondary, ), @@ -253,7 +253,7 @@ class ClientHubsPage extends StatelessWidget { actions: [ TextButton( onPressed: () => Modular.to.pop(), - child: const Text('Cancel'), + child: Text(t.client_hubs.delete_dialog.cancel), ), TextButton( onPressed: () { @@ -265,7 +265,7 @@ class ClientHubsPage extends StatelessWidget { style: TextButton.styleFrom( foregroundColor: UiColors.destructive, ), - child: const Text('Delete'), + child: Text(t.client_hubs.delete_dialog.delete), ), ], ); diff --git a/apps/mobile/packages/features/client/view_orders/lib/src/presentation/widgets/view_order_card.dart b/apps/mobile/packages/features/client/view_orders/lib/src/presentation/widgets/view_order_card.dart index 4106b4b0..480faece 100644 --- a/apps/mobile/packages/features/client/view_orders/lib/src/presentation/widgets/view_order_card.dart +++ b/apps/mobile/packages/features/client/view_orders/lib/src/presentation/widgets/view_order_card.dart @@ -89,8 +89,8 @@ class _ViewOrderCardState extends State { final DateTime tomorrow = today.add(const Duration(days: 1)); final DateTime checkDate = DateTime(date.year, date.month, date.day); - if (checkDate == today) return 'Today'; - if (checkDate == tomorrow) return 'Tomorrow'; + if (checkDate == today) return t.client_view_orders.card.today; + if (checkDate == tomorrow) return t.client_view_orders.card.tomorrow; return DateFormat('EEE, MMM d').format(date); } catch (_) { return dateStr; @@ -279,19 +279,19 @@ class _ViewOrderCardState extends State { _buildStatItem( icon: UiIcons.dollar, value: '\$${cost.round()}', - label: 'Total', + label: t.client_view_orders.card.total, ), _buildStatDivider(), _buildStatItem( icon: UiIcons.clock, value: hours.toStringAsFixed(1), - label: 'Hrs', + label: t.client_view_orders.card.hrs, ), _buildStatDivider(), _buildStatItem( icon: UiIcons.users, value: '${order.workersNeeded}', - label: 'Workers', + label: t.client_create_order.one_time.workers_label, ), ], ), @@ -303,14 +303,14 @@ class _ViewOrderCardState extends State { children: [ Expanded( child: _buildTimeDisplay( - label: 'Clock In', + label: t.client_view_orders.card.clock_in, time: _formatTime(timeStr: order.startTime), ), ), const SizedBox(width: UiConstants.space3), Expanded( child: _buildTimeDisplay( - label: 'Clock Out', + label: t.client_view_orders.card.clock_out, time: _formatTime(timeStr: order.endTime), ), ), @@ -341,8 +341,8 @@ class _ViewOrderCardState extends State { const SizedBox(width: UiConstants.space2), Text( coveragePercent == 100 - ? 'All Workers Confirmed' - : '${order.workersNeeded} Workers Needed', + ? t.client_view_orders.card.all_confirmed + : t.client_view_orders.card.workers_needed(count: order.workersNeeded), style: UiTypography.body2m.textPrimary, ), ], @@ -378,7 +378,7 @@ class _ViewOrderCardState extends State { Padding( padding: const EdgeInsets.only(left: 12), child: Text( - '+${order.confirmedApps.length - 3} more', + t.client_view_orders.card.show_more_workers(count: order.confirmedApps.length - 3), style: UiTypography.footnote2r.textSecondary, ), ), @@ -408,13 +408,13 @@ class _ViewOrderCardState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - 'CONFIRMED WORKERS', + t.client_view_orders.card.confirmed_workers_title, style: UiTypography.footnote2b.textSecondary, ), GestureDetector( onTap: () {}, child: Text( - 'Message All', + t.client_view_orders.card.message_all, style: UiTypography.footnote2b.copyWith( color: UiColors.primary, ), @@ -433,7 +433,7 @@ class _ViewOrderCardState extends State { child: TextButton( onPressed: () {}, child: Text( - 'Show ${order.confirmedApps.length - 5} more workers', + t.client_view_orders.card.show_more_workers(count: order.confirmedApps.length - 5), style: UiTypography.body2m.copyWith( color: UiColors.primary, ), @@ -569,7 +569,7 @@ class _ViewOrderCardState extends State { borderRadius: UiConstants.radiusSm, ), child: Text( - 'Checked In', + t.client_view_orders.card.checked_in, style: UiTypography.titleUppercase4m.copyWith( color: UiColors.textSuccess, ), @@ -615,16 +615,16 @@ class _ViewOrderCardState extends State { context: context, builder: (BuildContext context) { return AlertDialog( - title: const Text('Call'), - content: Text('Do you want to call $phone?'), + title: Text(t.client_view_orders.card.call_dialog.title), + content: Text(t.client_view_orders.card.call_dialog.message(phone: phone)), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), - child: const Text('Cancel'), + child: Text(t.common.cancel), ), TextButton( onPressed: () => Navigator.of(context).pop(true), - child: const Text('Call'), + child: Text(t.client_view_orders.card.call_dialog.title), ), ], ); diff --git a/apps/mobile/packages/features/staff/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart b/apps/mobile/packages/features/staff/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart index 36f3ffe5..0d4bca6b 100644 --- a/apps/mobile/packages/features/staff/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart +++ b/apps/mobile/packages/features/staff/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart @@ -156,24 +156,30 @@ class AuthRepositoryImpl .userRole('STAFF') .execute()); } else { - if (user.userRole != 'STAFF') { - await firebaseAuth.signOut(); - throw const domain.UnauthorizedAppException( - technicalMessage: 'User is not authorized for this app.', - ); - } + // User exists in PostgreSQL. Check if they have a STAFF profile. final QueryResult staffResponse = await executeProtected(() => dataConnect .getStaffByUserId( userId: firebaseUser.uid, ) .execute()); + if (staffResponse.data.staffs.isNotEmpty) { + // If profile exists, they should use Login mode. await firebaseAuth.signOut(); throw const domain.AccountExistsException( - technicalMessage: 'This user already has a staff profile. Please log in.', + technicalMessage: + 'This user already has a staff profile. Please log in.', ); } + + // If they don't have a staff profile but they exist as BUSINESS, + // they are allowed to "Sign Up" for Staff. + // We update their userRole to 'BOTH'. + if (user.userRole == 'BUSINESS') { + await executeProtected(() => + dataConnect.updateUser(id: firebaseUser.uid).userRole('BOTH').execute()); + } } } else { if (user == null) { @@ -182,7 +188,8 @@ class AuthRepositoryImpl technicalMessage: 'Authenticated user profile not found in database.', ); } - if (user.userRole != 'STAFF') { + // Allow STAFF or BOTH roles to log in to the Staff App + if (user.userRole != 'STAFF' && user.userRole != 'BOTH') { await firebaseAuth.signOut(); throw const domain.UnauthorizedAppException( technicalMessage: 'User is not authorized for this app.', diff --git a/apps/mobile/packages/features/staff/authentication/lib/src/presentation/blocs/auth_event.dart b/apps/mobile/packages/features/staff/authentication/lib/src/presentation/blocs/auth_event.dart index 51407bb9..cc9a9bea 100644 --- a/apps/mobile/packages/features/staff/authentication/lib/src/presentation/blocs/auth_event.dart +++ b/apps/mobile/packages/features/staff/authentication/lib/src/presentation/blocs/auth_event.dart @@ -5,7 +5,7 @@ import 'package:staff_authentication/src/domain/ui_entities/auth_mode.dart'; abstract class AuthEvent extends Equatable { const AuthEvent(); @override - List get props => []; + List get props => []; } /// Event for requesting a sign-in with a phone number. @@ -19,7 +19,7 @@ class AuthSignInRequested extends AuthEvent { const AuthSignInRequested({this.phoneNumber, required this.mode}); @override - List get props => [mode]; + List get props => [phoneNumber, mode]; } /// Event for submitting an OTP (One-Time Password) for verification. @@ -43,7 +43,7 @@ class AuthOtpSubmitted extends AuthEvent { }); @override - List get props => [verificationId, smsCode, mode]; + List get props => [verificationId, smsCode, mode]; } /// Event for clearing any authentication error in the state. @@ -57,7 +57,7 @@ class AuthResetRequested extends AuthEvent { const AuthResetRequested({required this.mode}); @override - List get props => [mode]; + List get props => [mode]; } /// Event for ticking down the resend cooldown. @@ -67,7 +67,7 @@ class AuthCooldownTicked extends AuthEvent { const AuthCooldownTicked(this.secondsRemaining); @override - List get props => [secondsRemaining]; + List get props => [secondsRemaining]; } /// Event for updating the current draft OTP in the state. @@ -78,7 +78,7 @@ class AuthOtpUpdated extends AuthEvent { const AuthOtpUpdated(this.otp); @override - List get props => [otp]; + List get props => [otp]; } /// Event for updating the current draft phone number in the state. @@ -89,5 +89,5 @@ class AuthPhoneUpdated extends AuthEvent { const AuthPhoneUpdated(this.phoneNumber); @override - List get props => [phoneNumber]; + List get props => [phoneNumber]; } diff --git a/apps/mobile/packages/features/staff/authentication/lib/src/presentation/pages/phone_verification_page.dart b/apps/mobile/packages/features/staff/authentication/lib/src/presentation/pages/phone_verification_page.dart index ceef6f69..9cbf1455 100644 --- a/apps/mobile/packages/features/staff/authentication/lib/src/presentation/pages/phone_verification_page.dart +++ b/apps/mobile/packages/features/staff/authentication/lib/src/presentation/pages/phone_verification_page.dart @@ -50,7 +50,13 @@ class _PhoneVerificationPageState extends State { required BuildContext context, required String phoneNumber, }) { - final String normalized = phoneNumber.replaceAll(RegExp(r'\\D'), ''); + String normalized = phoneNumber.replaceAll(RegExp(r'\D'), ''); + + // Handle US numbers entered with a leading 1 + if (normalized.length == 11 && normalized.startsWith('1')) { + normalized = normalized.substring(1); + } + if (normalized.length == 10) { BlocProvider.of( context, diff --git a/apps/mobile/packages/features/staff/authentication/lib/src/presentation/widgets/phone_verification_page/phone_input/phone_input_form_field.dart b/apps/mobile/packages/features/staff/authentication/lib/src/presentation/widgets/phone_verification_page/phone_input/phone_input_form_field.dart index e12cd2da..0ed74eff 100644 --- a/apps/mobile/packages/features/staff/authentication/lib/src/presentation/widgets/phone_verification_page/phone_input/phone_input_form_field.dart +++ b/apps/mobile/packages/features/staff/authentication/lib/src/presentation/widgets/phone_verification_page/phone_input/phone_input_form_field.dart @@ -88,7 +88,7 @@ class _PhoneInputFormFieldState extends State { keyboardType: TextInputType.phone, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, - LengthLimitingTextInputFormatter(10), + LengthLimitingTextInputFormatter(11), ], decoration: InputDecoration( hintText: t.staff_authentication.phone_input.hint, diff --git a/apps/mobile/packages/features/staff/home/lib/src/presentation/widgets/shift_card.dart b/apps/mobile/packages/features/staff/home/lib/src/presentation/widgets/shift_card.dart index e688681d..f8bf4992 100644 --- a/apps/mobile/packages/features/staff/home/lib/src/presentation/widgets/shift_card.dart +++ b/apps/mobile/packages/features/staff/home/lib/src/presentation/widgets/shift_card.dart @@ -1,3 +1,4 @@ +import 'package:core_localization/core_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; @@ -58,9 +59,9 @@ class _ShiftCardState extends State { try { final date = DateTime.parse(dateStr); final diff = DateTime.now().difference(date); - if (diff.inHours < 1) return 'Just now'; - if (diff.inHours < 24) return 'Pending ${diff.inHours}h ago'; - return 'Pending ${diff.inDays}d ago'; + if (diff.inHours < 1) return t.staff_shifts.card.just_now; + if (diff.inHours < 24) return t.staff_shifts.details.pending_time(time: '${diff.inHours}h'); + return t.staff_shifts.details.pending_time(time: '${diff.inDays}d'); } catch (e) { return ''; } @@ -220,7 +221,11 @@ class _ShiftCardState extends State { borderRadius: UiConstants.radiusFull, ), child: Text( - 'Assigned ${_getTimeAgo(widget.shift.createdDate).replaceAll('Pending ', '')}', + t.staff_shifts.card.assigned( + time: _getTimeAgo(widget.shift.createdDate) + .replaceAll('Pending ', '') + .replaceAll('Just now', 'just now'), + ), style: UiTypography.body3m.white, ), ), @@ -302,13 +307,13 @@ class _ShiftCardState extends State { children: [ _buildTag( UiIcons.zap, - 'Immediate start', + t.staff_shifts.tags.immediate_start, UiColors.accent.withValues(alpha: 0.3), UiColors.foreground, ), _buildTag( UiIcons.timer, - 'No experience', + t.staff_shifts.tags.no_experience, UiColors.tagError, UiColors.textError, ), @@ -342,7 +347,7 @@ class _ShiftCardState extends State { BorderRadius.circular(UiConstants.radiusBase), ), ), - child: const Text('Accept shift'), + child: Text(t.staff_shifts.card.accept_shift), ), ), const SizedBox(height: UiConstants.space2), @@ -361,7 +366,7 @@ class _ShiftCardState extends State { BorderRadius.circular(UiConstants.radiusBase), ), ), - child: const Text('Decline shift'), + child: Text(t.staff_shifts.card.decline_shift), ), ), const SizedBox(height: UiConstants.space5), diff --git a/apps/mobile/packages/features/staff/profile_sections/compliance/certificates/lib/src/presentation/pages/certificates_page.dart b/apps/mobile/packages/features/staff/profile_sections/compliance/certificates/lib/src/presentation/pages/certificates_page.dart index aed50873..0a1893a5 100644 --- a/apps/mobile/packages/features/staff/profile_sections/compliance/certificates/lib/src/presentation/pages/certificates_page.dart +++ b/apps/mobile/packages/features/staff/profile_sections/compliance/certificates/lib/src/presentation/pages/certificates_page.dart @@ -35,14 +35,14 @@ class CertificatesPage extends StatelessWidget { if (state.status == CertificatesStatus.failure) { return Scaffold( - appBar: AppBar(title: const Text('Certificates')), + appBar: AppBar(title: Text(t.staff_certificates.title)), body: Center( child: Padding( padding: const EdgeInsets.all(16.0), - child: Text( - state.errorMessage != null - ? translateErrorKey(state.errorMessage!) - : 'Error loading certificates', + child: Text( + state.errorMessage != null + ? translateErrorKey(state.errorMessage!) + : t.staff_certificates.error_loading, textAlign: TextAlign.center, style: UiTypography.body2r.textSecondary, ), diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/emergency_contact/lib/src/presentation/widgets/emergency_contact_save_button.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/emergency_contact/lib/src/presentation/widgets/emergency_contact_save_button.dart index 825e32fa..c332ac74 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/emergency_contact/lib/src/presentation/widgets/emergency_contact_save_button.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/emergency_contact/lib/src/presentation/widgets/emergency_contact_save_button.dart @@ -1,3 +1,4 @@ +import 'package:core_localization/core_localization.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -18,7 +19,7 @@ class EmergencyContactSaveButton extends StatelessWidget { if (state.status == EmergencyContactStatus.saved) { UiSnackbar.show( context, - message: 'Emergency contacts saved successfully', + message: t.staff.profile.menu_items.emergency_contact_page.save_success, type: UiSnackbarType.success, margin: const EdgeInsets.only(bottom: 150, left: 16, right: 16), ); @@ -48,7 +49,7 @@ class EmergencyContactSaveButton extends StatelessWidget { ), ), ) - : const Text('Save & Continue'), + : Text(t.staff.profile.menu_items.emergency_contact_page.save_continue), ), ), ); diff --git a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/my_shifts_tab.dart b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/my_shifts_tab.dart index cd5694d4..e17654e3 100644 --- a/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/my_shifts_tab.dart +++ b/apps/mobile/packages/features/staff/shifts/lib/src/presentation/widgets/tabs/my_shifts_tab.dart @@ -105,12 +105,12 @@ class _MyShiftsTabState extends State { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Accept Shift'), - content: const Text('Are you sure you want to accept this shift?'), + title: Text(t.staff_shifts.my_shifts_tab.confirm_dialog.title), + content: Text(t.staff_shifts.my_shifts_tab.confirm_dialog.message), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), - child: const Text('Cancel'), + child: Text(t.common.cancel), ), TextButton( onPressed: () { @@ -118,14 +118,14 @@ class _MyShiftsTabState extends State { context.read().add(AcceptShiftEvent(id)); UiSnackbar.show( context, - message: 'Shift confirmed!', + message: t.staff_shifts.my_shifts_tab.confirm_dialog.success, type: UiSnackbarType.success, ); }, style: TextButton.styleFrom( foregroundColor: UiColors.success, ), - child: const Text('Accept'), + child: Text(t.staff_shifts.shift_details.accept_shift), ), ], ), @@ -136,14 +136,14 @@ class _MyShiftsTabState extends State { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Decline Shift'), - content: const Text( - 'Are you sure you want to decline this shift? This action cannot be undone.', + title: Text(t.staff_shifts.my_shifts_tab.decline_dialog.title), + content: Text( + t.staff_shifts.my_shifts_tab.decline_dialog.message, ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), - child: const Text('Cancel'), + child: Text(t.common.cancel), ), TextButton( onPressed: () { @@ -151,14 +151,14 @@ class _MyShiftsTabState extends State { context.read().add(DeclineShiftEvent(id)); UiSnackbar.show( context, - message: 'Shift declined.', + message: t.staff_shifts.my_shifts_tab.decline_dialog.success, type: UiSnackbarType.error, ); }, style: TextButton.styleFrom( foregroundColor: UiColors.destructive, ), - child: const Text('Decline'), + child: Text(t.staff_shifts.shift_details.decline), ), ], ), @@ -169,9 +169,9 @@ class _MyShiftsTabState extends State { try { final date = DateTime.parse(dateStr); final now = DateTime.now(); - if (_isSameDay(date, now)) return "Today"; + if (_isSameDay(date, now)) return t.staff_shifts.my_shifts_tab.date.today; final tomorrow = now.add(const Duration(days: 1)); - if (_isSameDay(date, tomorrow)) return "Tomorrow"; + if (_isSameDay(date, tomorrow)) return t.staff_shifts.my_shifts_tab.date.tomorrow; return DateFormat('EEE, MMM d').format(date); } catch (_) { return dateStr; @@ -338,7 +338,7 @@ class _MyShiftsTabState extends State { const SizedBox(height: UiConstants.space5), if (widget.pendingAssignments.isNotEmpty) ...[ _buildSectionHeader( - "Awaiting Confirmation", + t.staff_shifts.my_shifts_tab.sections.awaiting, UiColors.textWarning, ), ...widget.pendingAssignments.map( @@ -356,7 +356,7 @@ class _MyShiftsTabState extends State { ], if (visibleCancelledShifts.isNotEmpty) ...[ - _buildSectionHeader("Cancelled Shifts", UiColors.textSecondary), + _buildSectionHeader(t.staff_shifts.my_shifts_tab.sections.cancelled, UiColors.textSecondary), ...visibleCancelledShifts.map( (shift) => Padding( padding: const EdgeInsets.only(bottom: UiConstants.space4), @@ -378,7 +378,7 @@ class _MyShiftsTabState extends State { // Confirmed Shifts if (visibleMyShifts.isNotEmpty) ...[ - _buildSectionHeader("Confirmed Shifts", UiColors.textSecondary), + _buildSectionHeader(t.staff_shifts.my_shifts_tab.sections.confirmed, UiColors.textSecondary), ...visibleMyShifts.map( (shift) => Padding( padding: const EdgeInsets.only(bottom: UiConstants.space3), @@ -390,10 +390,10 @@ class _MyShiftsTabState extends State { if (visibleMyShifts.isEmpty && widget.pendingAssignments.isEmpty && widget.cancelledShifts.isEmpty) - const EmptyStateView( + EmptyStateView( icon: UiIcons.calendar, - title: "No shifts this week", - subtitle: "Try finding new jobs in the Find tab", + title: t.staff_shifts.my_shifts_tab.empty.title, + subtitle: t.staff_shifts.my_shifts_tab.empty.subtitle, ), const SizedBox(height: UiConstants.space32), @@ -462,13 +462,13 @@ class _MyShiftsTabState extends State { ), const SizedBox(width: 6), Text( - "CANCELLED", + t.staff_shifts.my_shifts_tab.card.cancelled, style: UiTypography.footnote2b.textError, ), if (isLastMinute) ...[ const SizedBox(width: 4), Text( - "• 4hr compensation", + t.staff_shifts.my_shifts_tab.card.compensation, style: UiTypography.footnote2m.textSuccess, ), ], diff --git a/backend/dataconnect/connector/application/queries.gql b/backend/dataconnect/connector/application/queries.gql index 4458488d..44c66795 100644 --- a/backend/dataconnect/connector/application/queries.gql +++ b/backend/dataconnect/connector/application/queries.gql @@ -598,16 +598,19 @@ query listStaffsApplicationsByBusinessForDay( appliedAt status - shiftRole{ - shift{ + shiftRole { + startTime + shift { + date location + locationAddress cost } count assigned hours - role{ + role { name } } diff --git a/backend/dataconnect/connector/order/mutations.gql b/backend/dataconnect/connector/order/mutations.gql index 6827d73a..32423968 100644 --- a/backend/dataconnect/connector/order/mutations.gql +++ b/backend/dataconnect/connector/order/mutations.gql @@ -46,7 +46,7 @@ mutation createOrder( detectedConflicts: $detectedConflicts poReference: $poReference } - ) + ) } mutation updateOrder( @@ -92,7 +92,7 @@ mutation updateOrder( detectedConflicts: $detectedConflicts poReference: $poReference } - ) + ) } mutation deleteOrder($id: UUID!) @auth(level: USER) { diff --git a/backend/dataconnect/connector/shiftRole/queries.gql b/backend/dataconnect/connector/shiftRole/queries.gql index 86314355..98b83f94 100644 --- a/backend/dataconnect/connector/shiftRole/queries.gql +++ b/backend/dataconnect/connector/shiftRole/queries.gql @@ -321,7 +321,6 @@ query listShiftRolesByBusinessAndDateRange( shift: { date: { ge: $start, le: $end } order: { businessId: { eq: $businessId } } - status: { eq: $status } } } offset: $offset diff --git a/backend/dataconnect/schema/order.gql b/backend/dataconnect/schema/order.gql index 16a60eac..1c815e60 100644 --- a/backend/dataconnect/schema/order.gql +++ b/backend/dataconnect/schema/order.gql @@ -22,7 +22,7 @@ enum OrderDuration { } #events -type Order @table(name: "orders") { +type Order @table(name: "orders", key: ["id"]) { id: UUID! @default(expr: "uuidV4()") eventName: String diff --git a/backend/dataconnect/schema/shift.gql b/backend/dataconnect/schema/shift.gql index 96b1d2d1..3e5f7c67 100644 --- a/backend/dataconnect/schema/shift.gql +++ b/backend/dataconnect/schema/shift.gql @@ -10,7 +10,7 @@ enum ShiftStatus { CANCELED } -type Shift @table(name: "shifts") { +type Shift @table(name: "shifts", key: ["id"]) { id: UUID! @default(expr: "uuidV4()") title: String!