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 ab54d771..9fb4251f 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 @@ -1129,15 +1129,18 @@ "title": "Privacy & Security", "privacy_section": "Privacy", "legal_section": "Legal", - "location_sharing": { - "title": "Location Sharing", - "subtitle": "Share location during shifts" + "profile_visibility": { + "title": "Profile Visibility", + "subtitle": "Let clients see your profile" }, "terms_of_service": { "title": "Terms of Service" }, "privacy_policy": { "title": "Privacy Policy" + }, + "success": { + "profile_visibility_updated": "Profile visibility updated successfully!" } }, "success": { 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 e537d3da..77370c8e 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 @@ -1129,15 +1129,18 @@ "title": "Privacidad y Seguridad", "privacy_section": "Privacidad", "legal_section": "Legal", - "location_sharing": { - "title": "Compartir Ubicación", - "subtitle": "Compartir ubicación durante turnos" + "profile_visibility": { + "title": "Visibilidad del Perfil", + "subtitle": "Deja que los clientes vean tu perfil" }, "terms_of_service": { "title": "Términos de Servicio" }, "privacy_policy": { "title": "Política de Privacidad" + }, + "success": { + "profile_visibility_updated": "¡Visibilidad del perfil actualizada exitosamente!" } }, "success": { diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/data/repositories_impl/privacy_settings_repository_impl.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/data/repositories_impl/privacy_settings_repository_impl.dart index b317e470..66225fc4 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/data/repositories_impl/privacy_settings_repository_impl.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/data/repositories_impl/privacy_settings_repository_impl.dart @@ -1,79 +1,92 @@ +import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc; import 'package:flutter/services.dart'; import 'package:krow_data_connect/krow_data_connect.dart'; -import '../../domain/entities/privacy_settings_entity.dart'; import '../../domain/repositories/privacy_settings_repository_interface.dart'; /// Data layer implementation of privacy settings repository -/// -/// Handles all backend communication for privacy settings, -/// using DataConnectService for automatic auth and token refresh, +/// +/// Handles all backend communication for privacy settings via Data Connect, /// and loads legal documents from app assets class PrivacySettingsRepositoryImpl implements PrivacySettingsRepositoryInterface { - final DataConnectService _service; - PrivacySettingsRepositoryImpl(this._service); + final DataConnectService _service; + @override - Future getPrivacySettings() async { - return _service.run( - () async { - // TODO: Call Data Connect query to fetch privacy settings - // For now, return default settings - return PrivacySettingsEntity( - locationSharing: true, - updatedAt: DateTime.now(), - ); - }, - ); + Future getProfileVisibility() async { + return _service.run(() async { + // Get current user ID + final String staffId = await _service.getStaffId(); + + // Call Data Connect query: getStaffProfileVisibility + final fdc.QueryResult< + GetStaffProfileVisibilityData, + GetStaffProfileVisibilityVariables + > + response = await _service.connector + .getStaffProfileVisibility(staffId: staffId) + .execute(); + + // Return the profile visibility status from the first result + if (response.data.staff != null) { + return response.data.staff?.isProfileVisible ?? true; + } + + // Default to visible if no staff record found + return true; + }); } @override - Future updateLocationSharing(bool enabled) async { - return _service.run( - () async { - // TODO: Call Data Connect mutation to update location sharing preference - // For now, return updated settings - return PrivacySettingsEntity( - locationSharing: enabled, - updatedAt: DateTime.now(), - ); - }, - ); + Future updateProfileVisibility(bool isVisible) async { + return _service.run(() async { + // Get staff ID for the current user + final String staffId = await _service.getStaffId(); + + // Call Data Connect mutation: UpdateStaffProfileVisibility + await _service.connector + .updateStaffProfileVisibility( + id: staffId, + isProfileVisible: isVisible, + ) + .execute(); + + // Return the requested visibility state + return isVisible; + }); } @override Future getTermsOfService() async { - return _service.run( - () async { - try { - // Load from package asset path - return await rootBundle.loadString( - 'packages/staff_privacy_security/lib/src/assets/legal/terms_of_service.txt', - ); - } catch (e) { - // Final fallback if asset not found - return 'Terms of Service - Content unavailable. Please contact support@krow.com'; - } - }, - ); + return _service.run(() async { + try { + // Load from package asset path + return await rootBundle.loadString( + 'packages/staff_privacy_security/lib/src/assets/legal/terms_of_service.txt', + ); + } catch (e) { + // Final fallback if asset not found + print('Error loading terms of service: $e'); + return 'Terms of Service - Content unavailable. Please contact support@krow.com'; + } + }); } @override Future getPrivacyPolicy() async { - return _service.run( - () async { - try { - // Load from package asset path - return await rootBundle.loadString( - 'packages/staff_privacy_security/lib/src/assets/legal/privacy_policy.txt', - ); - } catch (e) { - // Final fallback if asset not found - return 'Privacy Policy - Content unavailable. Please contact privacy@krow.com'; - } - }, - ); + return _service.run(() async { + try { + // Load from package asset path + return await rootBundle.loadString( + 'packages/staff_privacy_security/lib/src/assets/legal/privacy_policy.txt', + ); + } catch (e) { + // Final fallback if asset not found + print('Error loading privacy policy: $e'); + return 'Privacy Policy - Content unavailable. Please contact privacy@krow.com'; + } + }); } } diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/repositories/privacy_settings_repository_interface.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/repositories/privacy_settings_repository_interface.dart index 666cc0b9..8057a76e 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/repositories/privacy_settings_repository_interface.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/repositories/privacy_settings_repository_interface.dart @@ -1,14 +1,12 @@ -import '../entities/privacy_settings_entity.dart'; - /// Interface for privacy settings repository operations abstract class PrivacySettingsRepositoryInterface { - /// Fetch the current user's privacy settings - Future getPrivacySettings(); + /// Fetch the current staff member's profile visibility setting + Future getProfileVisibility(); - /// Update location sharing preference + /// Update profile visibility preference /// - /// Returns the updated privacy settings - Future updateLocationSharing(bool enabled); + /// Returns the updated profile visibility status + Future updateProfileVisibility(bool isVisible); /// Fetch terms of service content Future getTermsOfService(); diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/get_privacy_settings_usecase.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/get_privacy_settings_usecase.dart deleted file mode 100644 index f3066bcb..00000000 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/get_privacy_settings_usecase.dart +++ /dev/null @@ -1,22 +0,0 @@ -import '../entities/privacy_settings_entity.dart'; -import '../repositories/privacy_settings_repository_interface.dart'; - -/// Use case to retrieve the current user's privacy settings -class GetPrivacySettingsUseCase { - final PrivacySettingsRepositoryInterface _repository; - - GetPrivacySettingsUseCase(this._repository); - - /// Execute the use case to get privacy settings - Future call() async { - try { - return await _repository.getPrivacySettings(); - } catch (e) { - // Return default settings on error - return PrivacySettingsEntity( - locationSharing: true, - updatedAt: DateTime.now(), - ); - } - } -} diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/get_profile_visibility_usecase.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/get_profile_visibility_usecase.dart new file mode 100644 index 00000000..3b21da61 --- /dev/null +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/get_profile_visibility_usecase.dart @@ -0,0 +1,19 @@ +import '../repositories/privacy_settings_repository_interface.dart'; + +/// Use case to retrieve the current staff member's profile visibility setting +class GetProfileVisibilityUseCase { + final PrivacySettingsRepositoryInterface _repository; + + GetProfileVisibilityUseCase(this._repository); + + /// Execute the use case to get profile visibility status + /// Returns true if profile is visible, false if hidden + Future call() async { + try { + return await _repository.getProfileVisibility(); + } catch (e) { + // Return default (visible) on error + return true; + } + } +} diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/update_location_sharing_usecase.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/update_location_sharing_usecase.dart deleted file mode 100644 index 2ee00d33..00000000 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/update_location_sharing_usecase.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:equatable/equatable.dart'; - -import '../entities/privacy_settings_entity.dart'; -import '../repositories/privacy_settings_repository_interface.dart'; - -/// Parameters for updating location sharing -class UpdateLocationSharingParams extends Equatable { - /// Whether to enable or disable location sharing - final bool enabled; - - const UpdateLocationSharingParams({required this.enabled}); - - @override - List get props => [enabled]; -} - -/// Use case to update location sharing preference -class UpdateLocationSharingUseCase { - final PrivacySettingsRepositoryInterface _repository; - - UpdateLocationSharingUseCase(this._repository); - - /// Execute the use case to update location sharing - Future call(UpdateLocationSharingParams params) async { - try { - return await _repository.updateLocationSharing(params.enabled); - } catch (e) { - // Return current settings on error - return PrivacySettingsEntity( - locationSharing: params.enabled, - updatedAt: DateTime.now(), - ); - } - } -} diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/update_profile_visibility_usecase.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/update_profile_visibility_usecase.dart new file mode 100644 index 00000000..9048ae59 --- /dev/null +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/domain/usecases/update_profile_visibility_usecase.dart @@ -0,0 +1,32 @@ +import 'package:equatable/equatable.dart'; + +import '../repositories/privacy_settings_repository_interface.dart'; + +/// Parameters for updating profile visibility +class UpdateProfileVisibilityParams extends Equatable { + /// Whether to show (true) or hide (false) the profile + final bool isVisible; + + const UpdateProfileVisibilityParams({required this.isVisible}); + + @override + List get props => [isVisible]; +} + +/// Use case to update profile visibility setting +class UpdateProfileVisibilityUseCase { + final PrivacySettingsRepositoryInterface _repository; + + UpdateProfileVisibilityUseCase(this._repository); + + /// Execute the use case to update profile visibility + /// Returns the updated visibility status + Future call(UpdateProfileVisibilityParams params) async { + try { + return await _repository.updateProfileVisibility(params.isVisible); + } catch (e) { + // Return the requested state on error (optimistic) + return params.isVisible; + } + } +} diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_bloc.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_bloc.dart index 70b51944..d333824d 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_bloc.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_bloc.dart @@ -1,10 +1,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:equatable/equatable.dart'; -import '../../domain/entities/privacy_settings_entity.dart'; -import '../../domain/repositories/privacy_settings_repository_interface.dart'; -import '../../domain/usecases/get_privacy_settings_usecase.dart'; -import '../../domain/usecases/update_location_sharing_usecase.dart'; +import '../../domain/usecases/get_profile_visibility_usecase.dart'; +import '../../domain/usecases/update_profile_visibility_usecase.dart'; import '../../domain/usecases/get_terms_usecase.dart'; import '../../domain/usecases/get_privacy_policy_usecase.dart'; @@ -14,72 +12,75 @@ part 'privacy_security_state.dart'; /// BLoC managing privacy and security settings state class PrivacySecurityBloc extends Bloc { - final GetPrivacySettingsUseCase _getPrivacySettingsUseCase; - final UpdateLocationSharingUseCase _updateLocationSharingUseCase; + final GetProfileVisibilityUseCase _getProfileVisibilityUseCase; + final UpdateProfileVisibilityUseCase _updateProfileVisibilityUseCase; final GetTermsUseCase _getTermsUseCase; final GetPrivacyPolicyUseCase _getPrivacyPolicyUseCase; PrivacySecurityBloc({ - required GetPrivacySettingsUseCase getPrivacySettingsUseCase, - required UpdateLocationSharingUseCase updateLocationSharingUseCase, + required GetProfileVisibilityUseCase getProfileVisibilityUseCase, + required UpdateProfileVisibilityUseCase updateProfileVisibilityUseCase, required GetTermsUseCase getTermsUseCase, required GetPrivacyPolicyUseCase getPrivacyPolicyUseCase, - }) : _getPrivacySettingsUseCase = getPrivacySettingsUseCase, - _updateLocationSharingUseCase = updateLocationSharingUseCase, + }) : _getProfileVisibilityUseCase = getProfileVisibilityUseCase, + _updateProfileVisibilityUseCase = updateProfileVisibilityUseCase, _getTermsUseCase = getTermsUseCase, _getPrivacyPolicyUseCase = getPrivacyPolicyUseCase, super(const PrivacySecurityState()) { - on(_onFetchPrivacySettings); - on(_onUpdateLocationSharing); + on(_onFetchProfileVisibility); + on(_onUpdateProfileVisibility); on(_onFetchTerms); on(_onFetchPrivacyPolicy); + on(_onClearProfileVisibilityUpdated); } - Future _onFetchPrivacySettings( - FetchPrivacySettingsEvent event, + Future _onFetchProfileVisibility( + FetchProfileVisibilityEvent event, Emitter emit, ) async { emit(state.copyWith(isLoading: true, error: null)); try { - final settings = await _getPrivacySettingsUseCase.call(); + final bool isVisible = await _getProfileVisibilityUseCase.call(); emit( state.copyWith( isLoading: false, - privacySettings: settings, + isProfileVisible: isVisible, ), ); } catch (e) { emit( state.copyWith( isLoading: false, - error: 'Failed to fetch privacy settings', + error: 'Failed to fetch profile visibility', ), ); } } - Future _onUpdateLocationSharing( - UpdateLocationSharingEvent event, + Future _onUpdateProfileVisibility( + UpdateProfileVisibilityEvent event, Emitter emit, ) async { - emit(state.copyWith(isUpdating: true, error: null)); + emit(state.copyWith(isUpdating: true, error: null, profileVisibilityUpdated: false)); try { - final settings = await _updateLocationSharingUseCase.call( - UpdateLocationSharingParams(enabled: event.enabled), + final bool isVisible = await _updateProfileVisibilityUseCase.call( + UpdateProfileVisibilityParams(isVisible: event.isVisible), ); emit( state.copyWith( isUpdating: false, - privacySettings: settings, + isProfileVisible: isVisible, + profileVisibilityUpdated: true, ), ); } catch (e) { emit( state.copyWith( isUpdating: false, - error: 'Failed to update location sharing', + error: 'Failed to update profile visibility', + profileVisibilityUpdated: false, ), ); } @@ -92,7 +93,7 @@ class PrivacySecurityBloc emit(state.copyWith(isLoadingTerms: true, error: null)); try { - final content = await _getTermsUseCase.call(); + final String content = await _getTermsUseCase.call(); emit( state.copyWith( isLoadingTerms: false, @@ -116,7 +117,7 @@ class PrivacySecurityBloc emit(state.copyWith(isLoadingPrivacyPolicy: true, error: null)); try { - final content = await _getPrivacyPolicyUseCase.call(); + final String content = await _getPrivacyPolicyUseCase.call(); emit( state.copyWith( isLoadingPrivacyPolicy: false, @@ -132,4 +133,11 @@ class PrivacySecurityBloc ); } } + + void _onClearProfileVisibilityUpdated( + ClearProfileVisibilityUpdatedEvent event, + Emitter emit, + ) { + emit(state.copyWith(profileVisibilityUpdated: false)); + } } diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_event.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_event.dart index d1a9caac..6dbfcfdd 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_event.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_event.dart @@ -5,23 +5,23 @@ abstract class PrivacySecurityEvent extends Equatable { const PrivacySecurityEvent(); @override - List get props => []; + List get props => []; } -/// Event to fetch current privacy settings -class FetchPrivacySettingsEvent extends PrivacySecurityEvent { - const FetchPrivacySettingsEvent(); +/// Event to fetch current profile visibility setting +class FetchProfileVisibilityEvent extends PrivacySecurityEvent { + const FetchProfileVisibilityEvent(); } -/// Event to update location sharing preference -class UpdateLocationSharingEvent extends PrivacySecurityEvent { - /// Whether to enable or disable location sharing - final bool enabled; +/// Event to update profile visibility +class UpdateProfileVisibilityEvent extends PrivacySecurityEvent { + /// Whether to show (true) or hide (false) the profile + final bool isVisible; - const UpdateLocationSharingEvent({required this.enabled}); + const UpdateProfileVisibilityEvent({required this.isVisible}); @override - List get props => [enabled]; + List get props => [isVisible]; } /// Event to fetch terms of service @@ -33,3 +33,8 @@ class FetchTermsEvent extends PrivacySecurityEvent { class FetchPrivacyPolicyEvent extends PrivacySecurityEvent { const FetchPrivacyPolicyEvent(); } + +/// Event to clear the profile visibility updated flag after showing snackbar +class ClearProfileVisibilityUpdatedEvent extends PrivacySecurityEvent { + const ClearProfileVisibilityUpdatedEvent(); +} diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_state.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_state.dart index 14a6c39d..a84666ad 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_state.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/blocs/privacy_security_state.dart @@ -2,15 +2,18 @@ part of 'privacy_security_bloc.dart'; /// State for privacy security BLoC class PrivacySecurityState extends Equatable { - /// Current privacy settings - final PrivacySettingsEntity? privacySettings; + /// Current profile visibility setting (true = visible, false = hidden) + final bool isProfileVisible; - /// Whether settings are currently loading + /// Whether profile visibility is currently loading final bool isLoading; - /// Whether settings are currently being updated + /// Whether profile visibility is currently being updated final bool isUpdating; + /// Whether the profile visibility was just successfully updated + final bool profileVisibilityUpdated; + /// Terms of service content final String? termsContent; @@ -27,9 +30,10 @@ class PrivacySecurityState extends Equatable { final String? error; const PrivacySecurityState({ - this.privacySettings, + this.isProfileVisible = true, this.isLoading = false, this.isUpdating = false, + this.profileVisibilityUpdated = false, this.termsContent, this.isLoadingTerms = false, this.privacyPolicyContent, @@ -39,9 +43,10 @@ class PrivacySecurityState extends Equatable { /// Create a copy with optional field overrides PrivacySecurityState copyWith({ - PrivacySettingsEntity? privacySettings, + bool? isProfileVisible, bool? isLoading, bool? isUpdating, + bool? profileVisibilityUpdated, String? termsContent, bool? isLoadingTerms, String? privacyPolicyContent, @@ -49,9 +54,10 @@ class PrivacySecurityState extends Equatable { String? error, }) { return PrivacySecurityState( - privacySettings: privacySettings ?? this.privacySettings, + isProfileVisible: isProfileVisible ?? this.isProfileVisible, isLoading: isLoading ?? this.isLoading, isUpdating: isUpdating ?? this.isUpdating, + profileVisibilityUpdated: profileVisibilityUpdated ?? this.profileVisibilityUpdated, termsContent: termsContent ?? this.termsContent, isLoadingTerms: isLoadingTerms ?? this.isLoadingTerms, privacyPolicyContent: privacyPolicyContent ?? this.privacyPolicyContent, @@ -62,10 +68,11 @@ class PrivacySecurityState extends Equatable { } @override - List get props => [ - privacySettings, + List get props => [ + isProfileVisible, isLoading, isUpdating, + profileVisibilityUpdated, termsContent, isLoadingTerms, privacyPolicyContent, @@ -73,3 +80,4 @@ class PrivacySecurityState extends Equatable { error, ]; } + diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/pages/privacy_security_page.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/pages/privacy_security_page.dart index 5897fa8e..28749dbe 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/pages/privacy_security_page.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/pages/privacy_security_page.dart @@ -25,7 +25,7 @@ class PrivacySecurityPage extends StatelessWidget { ), body: BlocProvider.value( value: Modular.get() - ..add(const FetchPrivacySettingsEvent()), + ..add(const FetchProfileVisibilityEvent()), child: BlocBuilder( builder: (BuildContext context, PrivacySecurityState state) { if (state.isLoading) { diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/widgets/legal/legal_section_widget.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/widgets/legal/legal_section_widget.dart index e1dfc013..d50540a3 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/widgets/legal/legal_section_widget.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/widgets/legal/legal_section_widget.dart @@ -23,7 +23,7 @@ class LegalSectionWidget extends StatelessWidget { // Legal Section Header SettingsSectionHeader( title: t.staff_privacy_security.legal_section, - icon: Icons.shield, + icon: UiIcons.shield, ), Container( diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/widgets/privacy/privacy_section_widget.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/widgets/privacy/privacy_section_widget.dart index 8209ead0..c8a54a63 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/widgets/privacy/privacy_section_widget.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/presentation/widgets/privacy/privacy_section_widget.dart @@ -7,48 +7,64 @@ import '../../blocs/privacy_security_bloc.dart'; import '../settings_section_header_widget.dart'; import '../settings_switch_tile_widget.dart'; -/// Widget displaying privacy settings including location sharing preference +/// Widget displaying privacy settings including profile visibility preference class PrivacySectionWidget extends StatelessWidget { const PrivacySectionWidget({super.key}); @override Widget build(BuildContext context) { - return BlocBuilder( - builder: (BuildContext context, PrivacySecurityState state) { - return Column( - children: [ - // Privacy Section Header - SettingsSectionHeader( - title: t.staff_privacy_security.privacy_section, - icon: UiIcons.eye, - ), - const SizedBox(height: 12.0), - Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(UiConstants.radiusBase), - border: Border.all( - color: UiColors.border, + return BlocListener( + listener: (BuildContext context, PrivacySecurityState state) { + // Show success message when profile visibility update just completed + if (state.profileVisibilityUpdated && state.error == null) { + UiSnackbar.show( + context, + message: t.staff_privacy_security.success.profile_visibility_updated, + type: UiSnackbarType.success, + ); + // Clear the flag after showing the snackbar + context.read().add( + const ClearProfileVisibilityUpdatedEvent(), + ); + } + }, + child: BlocBuilder( + builder: (BuildContext context, PrivacySecurityState state) { + return Column( + children: [ + // Privacy Section Header + SettingsSectionHeader( + title: t.staff_privacy_security.privacy_section, + icon: UiIcons.eye, + ), + const SizedBox(height: 12.0), + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(UiConstants.radiusBase), + border: Border.all( + color: UiColors.border, + ), + ), + child: Column( + children: [ + SettingsSwitchTile( + title: t.staff_privacy_security.profile_visibility.title, + subtitle: t.staff_privacy_security.profile_visibility.subtitle, + value: state.isProfileVisible, + onChanged: (bool value) { + BlocProvider.of(context).add( + UpdateProfileVisibilityEvent(isVisible: value), + ); + }, + ), + ], ), ), - child: Column( - children: [ - SettingsSwitchTile( - title: t.staff_privacy_security.location_sharing.title, - subtitle: t.staff_privacy_security.location_sharing.subtitle, - value: state.privacySettings?.locationSharing ?? false, - onChanged: (bool value) { - BlocProvider.of(context).add( - UpdateLocationSharingEvent(enabled: value), - ); - }, - ), - ], - ), - ), - ], - ); - }, + ], + ); + }, + ), ); } } diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/staff_privacy_security_module.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/staff_privacy_security_module.dart index 86667131..22b0d405 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/staff_privacy_security_module.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/src/staff_privacy_security_module.dart @@ -6,9 +6,9 @@ import 'package:krow_data_connect/krow_data_connect.dart'; import 'data/repositories_impl/privacy_settings_repository_impl.dart'; import 'domain/repositories/privacy_settings_repository_interface.dart'; import 'domain/usecases/get_privacy_policy_usecase.dart'; -import 'domain/usecases/get_privacy_settings_usecase.dart'; +import 'domain/usecases/get_profile_visibility_usecase.dart'; import 'domain/usecases/get_terms_usecase.dart'; -import 'domain/usecases/update_location_sharing_usecase.dart'; +import 'domain/usecases/update_profile_visibility_usecase.dart'; import 'presentation/blocs/legal/privacy_policy_cubit.dart'; import 'presentation/blocs/legal/terms_cubit.dart'; import 'presentation/blocs/privacy_security_bloc.dart'; @@ -33,12 +33,12 @@ class PrivacySecurityModule extends Module { // Use Cases i.addSingleton( - () => GetPrivacySettingsUseCase( + () => GetProfileVisibilityUseCase( i(), ), ); i.addSingleton( - () => UpdateLocationSharingUseCase( + () => UpdateProfileVisibilityUseCase( i(), ), ); @@ -56,8 +56,8 @@ class PrivacySecurityModule extends Module { // BLoC i.add( () => PrivacySecurityBloc( - getPrivacySettingsUseCase: i(), - updateLocationSharingUseCase: i(), + getProfileVisibilityUseCase: i(), + updateProfileVisibilityUseCase: i(), getTermsUseCase: i(), getPrivacyPolicyUseCase: i(), ), diff --git a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/staff_privacy_security.dart b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/staff_privacy_security.dart index d6630e8c..a638651d 100644 --- a/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/staff_privacy_security.dart +++ b/apps/mobile/packages/features/staff/profile_sections/settings/privacy_security/lib/staff_privacy_security.dart @@ -1,7 +1,5 @@ export 'src/domain/entities/privacy_settings_entity.dart'; export 'src/domain/repositories/privacy_settings_repository_interface.dart'; -export 'src/domain/usecases/get_privacy_settings_usecase.dart'; -export 'src/domain/usecases/update_location_sharing_usecase.dart'; export 'src/domain/usecases/get_terms_usecase.dart'; export 'src/domain/usecases/get_privacy_policy_usecase.dart'; export 'src/data/repositories_impl/privacy_settings_repository_impl.dart'; 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 53667bde..b1ada599 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 @@ -15,6 +15,8 @@ class ShiftsRepositoryImpl // Cache: ApplicationID -> RoleID (For Accept/Decline w/ Update mutation) final Map _appToRoleIdMap = {}; + // This need to be an APPLICATION + // THERE SHOULD BE APPLICATIONSTATUS and SHIFTSTATUS enums in the domain layer to avoid this string mapping and potential bugs. @override Future> getMyShifts({ required DateTime start, diff --git a/backend/dataconnect/connector/staff/mutations.gql b/backend/dataconnect/connector/staff/mutations.gql index 797ca1bd..23f9b0c7 100644 --- a/backend/dataconnect/connector/staff/mutations.gql +++ b/backend/dataconnect/connector/staff/mutations.gql @@ -214,3 +214,12 @@ mutation UpdateStaff( mutation DeleteStaff($id: UUID!) @auth(level: USER) { staff_delete(id: $id) } + +mutation UpdateStaffProfileVisibility($id: UUID!, $isProfileVisible: Boolean!) @auth(level: USER) { + staff_update( + id: $id + data: { + isProfileVisible: $isProfileVisible + } + ) +} diff --git a/backend/dataconnect/connector/staff/queries.gql b/backend/dataconnect/connector/staff/queries.gql index aecf8891..61bb7113 100644 --- a/backend/dataconnect/connector/staff/queries.gql +++ b/backend/dataconnect/connector/staff/queries.gql @@ -204,3 +204,10 @@ query filterStaff( zipCode } } + +query getStaffProfileVisibility($staffId: UUID!) @auth(level: USER) { + staff(id: $staffId) { + id + isProfileVisible + } +}