Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/app/view/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:go_router/go_router.dart';
import 'package:ht_auth_repository/ht_auth_repository.dart';
import 'package:ht_dashboard/app/bloc/app_bloc.dart';
import 'package:ht_dashboard/app/config/app_environment.dart';
import 'package:ht_dashboard/app_configuration/bloc/app_configuration_bloc.dart';
import 'package:ht_dashboard/authentication/bloc/authentication_bloc.dart';
import 'package:ht_dashboard/l10n/app_localizations.dart';
import 'package:ht_dashboard/router/router.dart';
Expand Down Expand Up @@ -81,6 +82,11 @@ class App extends StatelessWidget {
authenticationRepository: context.read<HtAuthRepository>(),
),
),
BlocProvider(
create: (context) => AppConfigurationBloc(
appConfigRepository: context.read<HtDataRepository<AppConfig>>(),
),
),
],
child: _AppView(
htAuthenticationRepository: _htAuthenticationRepository,
Expand Down
25 changes: 24 additions & 1 deletion lib/app_configuration/bloc/app_configuration_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ class AppConfigurationBloc
AppConfigurationBloc({
required HtDataRepository<AppConfig> appConfigRepository,
}) : _appConfigRepository = appConfigRepository,
super(const AppConfigurationState()) {
super(
const AppConfigurationState(),
) {
on<AppConfigurationLoaded>(_onAppConfigurationLoaded);
on<AppConfigurationUpdated>(_onAppConfigurationUpdated);
on<AppConfigurationFieldChanged>(_onAppConfigurationFieldChanged);
on<AppConfigurationDiscarded>(_onAppConfigurationDiscarded);
}

final HtDataRepository<AppConfig> _appConfigRepository;
Expand All @@ -30,7 +33,10 @@ class AppConfigurationBloc
state.copyWith(
status: AppConfigurationStatus.success,
appConfig: appConfig,
originalAppConfig: appConfig, // Store the original config
isDirty: false,
clearShowSaveSuccess:
true, // Clear any previous success snackbar flag
),
);
} on HtHttpException catch (e) {
Expand Down Expand Up @@ -64,7 +70,9 @@ class AppConfigurationBloc
state.copyWith(
status: AppConfigurationStatus.success,
appConfig: updatedConfig,
originalAppConfig: updatedConfig, // Update original config on save
isDirty: false,
showSaveSuccess: true, // Set flag to show success snackbar
),
);
} on HtHttpException catch (e) {
Expand Down Expand Up @@ -93,6 +101,21 @@ class AppConfigurationBloc
appConfig: event.appConfig,
isDirty: true,
clearErrorMessage: true, // Clear any previous error messages
clearShowSaveSuccess: true, // Clear success snackbar on field change
),
);
}

void _onAppConfigurationDiscarded(
AppConfigurationDiscarded event,
Emitter<AppConfigurationState> emit,
) {
emit(
state.copyWith(
appConfig: state.originalAppConfig, // Revert to original config
isDirty: false,
clearErrorMessage: true, // Clear any previous error messages
clearShowSaveSuccess: true, // Clear success snackbar
),
);
}
Expand Down
8 changes: 8 additions & 0 deletions lib/app_configuration/bloc/app_configuration_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ class AppConfigurationUpdated extends AppConfigurationEvent {
List<Object?> get props => [appConfig];
}

/// {@template app_configuration_discarded}
/// Event to discard any unsaved changes to the application configuration.
/// {@endtemplate}
class AppConfigurationDiscarded extends AppConfigurationEvent {
/// {@macro app_configuration_discarded}
const AppConfigurationDiscarded();
}

/// {@template app_configuration_field_changed}
/// Event to notify that a field in the application configuration has changed.
///
Expand Down
17 changes: 17 additions & 0 deletions lib/app_configuration/bloc/app_configuration_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ class AppConfigurationState extends Equatable {
const AppConfigurationState({
this.status = AppConfigurationStatus.initial,
this.appConfig,
this.originalAppConfig,
this.errorMessage,
this.isDirty = false,
this.showSaveSuccess = false,
});

/// The current status of the application configuration.
Expand All @@ -33,35 +35,50 @@ class AppConfigurationState extends Equatable {
/// The loaded or updated application configuration.
final AppConfig? appConfig;

/// The original application configuration loaded from the backend.
final AppConfig? originalAppConfig;

/// An error message if an operation failed.
final String? errorMessage;

/// Indicates if there are unsaved changes to the configuration.
final bool isDirty;

/// Indicates if a save operation was successful and a snackbar should be shown.
final bool showSaveSuccess;

/// Creates a copy of the current state with updated values.
AppConfigurationState copyWith({
AppConfigurationStatus? status,
AppConfig? appConfig,
AppConfig? originalAppConfig,
String? errorMessage,
bool? isDirty,
bool clearErrorMessage = false,
bool? showSaveSuccess,
bool clearShowSaveSuccess = false,
}) {
return AppConfigurationState(
status: status ?? this.status,
appConfig: appConfig ?? this.appConfig,
originalAppConfig: originalAppConfig ?? this.originalAppConfig,
errorMessage: clearErrorMessage
? null
: errorMessage ?? this.errorMessage,
isDirty: isDirty ?? this.isDirty,
showSaveSuccess: clearShowSaveSuccess
? false
: showSaveSuccess ?? this.showSaveSuccess,
);
}

@override
List<Object?> get props => [
status,
appConfig,
originalAppConfig,
errorMessage,
isDirty,
showSaveSuccess,
];
}
Loading