Skip to content

Commit 2c97bbd

Browse files
committed
refactor(auth): improve authentication bloc
- Replaced AuthenticationUserChanged with AuthenticationStatusChanged. - Updated state management to use AuthenticationStatus enum. - Improved error handling and feedback. - Enhanced code clarity and readability. - Standardized error message handling.
1 parent baf7d97 commit 2c97bbd

File tree

4 files changed

+227
-108
lines changed

4 files changed

+227
-108
lines changed

lib/authentication/bloc/authentication_bloc.dart

Lines changed: 161 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ class AuthenticationBloc
2727
/// {@macro authentication_bloc}
2828
AuthenticationBloc({required HtAuthRepository authenticationRepository})
2929
: _authenticationRepository = authenticationRepository,
30-
super(AuthenticationInitial()) {
30+
super(const AuthenticationState()) {
3131
// Listen to authentication state changes from the repository
3232
_userAuthSubscription = _authenticationRepository.authStateChanges.listen(
33-
(user) => add(_AuthenticationUserChanged(user: user)),
33+
(user) => add(_AuthenticationStatusChanged(user: user)),
3434
);
3535

36-
on<_AuthenticationUserChanged>(_onAuthenticationUserChanged);
36+
on<_AuthenticationStatusChanged>(_onAuthenticationStatusChanged);
3737
on<AuthenticationRequestSignInCodeRequested>(
3838
_onAuthenticationRequestSignInCodeRequested,
3939
);
@@ -44,15 +44,25 @@ class AuthenticationBloc
4444
final HtAuthRepository _authenticationRepository;
4545
late final StreamSubscription<User?> _userAuthSubscription;
4646

47-
/// Handles [_AuthenticationUserChanged] events.
48-
Future<void> _onAuthenticationUserChanged(
49-
_AuthenticationUserChanged event,
47+
/// Handles [_AuthenticationStatusChanged] events.
48+
Future<void> _onAuthenticationStatusChanged(
49+
_AuthenticationStatusChanged event,
5050
Emitter<AuthenticationState> emit,
5151
) async {
5252
if (event.user != null) {
53-
emit(AuthenticationAuthenticated(user: event.user!));
53+
emit(
54+
state.copyWith(
55+
status: AuthenticationStatus.authenticated,
56+
user: event.user,
57+
),
58+
);
5459
} else {
55-
emit(AuthenticationUnauthenticated());
60+
emit(
61+
state.copyWith(
62+
status: AuthenticationStatus.unauthenticated,
63+
user: null,
64+
),
65+
);
5666
}
5767
}
5868

@@ -63,37 +73,87 @@ class AuthenticationBloc
6373
) async {
6474
// Validate email format (basic check)
6575
if (event.email.isEmpty || !event.email.contains('@')) {
66-
emit(const AuthenticationFailure('Please enter a valid email address.'));
76+
emit(
77+
state.copyWith(
78+
status: AuthenticationStatus.failure,
79+
errorMessage: 'Please enter a valid email address.',
80+
),
81+
);
6782
return;
6883
}
69-
emit(AuthenticationRequestCodeLoading());
84+
emit(state.copyWith(status: AuthenticationStatus.requestCodeLoading));
7085
try {
7186
await _authenticationRepository.requestSignInCode(
7287
event.email,
7388
isDashboardLogin: true,
7489
);
75-
emit(AuthenticationCodeSentSuccess(email: event.email));
90+
emit(
91+
state.copyWith(
92+
status: AuthenticationStatus.codeSentSuccess,
93+
email: event.email,
94+
),
95+
);
7696
} on InvalidInputException catch (e) {
77-
emit(AuthenticationFailure('Invalid input: ${e.message}'));
97+
emit(
98+
state.copyWith(
99+
status: AuthenticationStatus.failure,
100+
errorMessage: 'Invalid input: ${e.message}',
101+
),
102+
);
78103
} on UnauthorizedException catch (e) {
79-
emit(AuthenticationFailure(e.message));
104+
emit(
105+
state.copyWith(
106+
status: AuthenticationStatus.failure,
107+
errorMessage: e.message,
108+
),
109+
);
80110
} on ForbiddenException catch (e) {
81-
emit(AuthenticationFailure(e.message));
111+
emit(
112+
state.copyWith(
113+
status: AuthenticationStatus.failure,
114+
errorMessage: e.message,
115+
),
116+
);
82117
} on NetworkException catch (_) {
83-
emit(const AuthenticationFailure('Network error occurred.'));
118+
emit(
119+
state.copyWith(
120+
status: AuthenticationStatus.failure,
121+
errorMessage: 'Network error occurred.',
122+
),
123+
);
84124
} on ServerException catch (e) {
85-
emit(AuthenticationFailure('Server error: ${e.message}'));
125+
emit(
126+
state.copyWith(
127+
status: AuthenticationStatus.failure,
128+
errorMessage: 'Server error: ${e.message}',
129+
),
130+
);
86131
} on OperationFailedException catch (e) {
87-
emit(AuthenticationFailure('Operation failed: ${e.message}'));
132+
emit(
133+
state.copyWith(
134+
status: AuthenticationStatus.failure,
135+
errorMessage: 'Operation failed: ${e.message}',
136+
),
137+
);
88138
} on HtHttpException catch (e) {
89139
// Catch any other HtHttpException subtypes
90140
final message = e.message.isNotEmpty
91141
? e.message
92142
: 'An unspecified HTTP error occurred.';
93-
emit(AuthenticationFailure('HTTP error: $message'));
143+
emit(
144+
state.copyWith(
145+
status: AuthenticationStatus.failure,
146+
errorMessage: 'HTTP error: $message',
147+
),
148+
);
94149
} catch (e) {
95150
// Catch any other unexpected errors
96-
emit(AuthenticationFailure('An unexpected error occurred: $e'));
151+
emit(
152+
state.copyWith(
153+
status: AuthenticationStatus.failure,
154+
errorMessage: 'An unexpected error occurred: $e',
155+
),
156+
);
97157
// Optionally log the stackTrace here
98158
}
99159
}
@@ -103,33 +163,73 @@ class AuthenticationBloc
103163
AuthenticationVerifyCodeRequested event,
104164
Emitter<AuthenticationState> emit,
105165
) async {
106-
emit(AuthenticationLoading());
166+
emit(state.copyWith(status: AuthenticationStatus.loading));
107167
try {
108168
await _authenticationRepository.verifySignInCode(
109169
event.email,
110170
event.code,
111171
isDashboardLogin: true,
112172
);
113-
// On success, the _AuthenticationUserChanged listener will handle
173+
// On success, the _AuthenticationStatusChanged listener will handle
114174
// emitting AuthenticationAuthenticated.
115175
} on InvalidInputException catch (e) {
116-
emit(AuthenticationFailure(e.message));
176+
emit(
177+
state.copyWith(
178+
status: AuthenticationStatus.failure,
179+
errorMessage: e.message,
180+
),
181+
);
117182
} on AuthenticationException catch (e) {
118-
emit(AuthenticationFailure(e.message));
183+
emit(
184+
state.copyWith(
185+
status: AuthenticationStatus.failure,
186+
errorMessage: e.message,
187+
),
188+
);
119189
} on NotFoundException catch (e) {
120-
emit(AuthenticationFailure(e.message));
190+
emit(
191+
state.copyWith(
192+
status: AuthenticationStatus.failure,
193+
errorMessage: e.message,
194+
),
195+
);
121196
} on NetworkException catch (_) {
122-
emit(const AuthenticationFailure('Network error occurred.'));
197+
emit(
198+
state.copyWith(
199+
status: AuthenticationStatus.failure,
200+
errorMessage: 'Network error occurred.',
201+
),
202+
);
123203
} on ServerException catch (e) {
124-
emit(AuthenticationFailure('Server error: ${e.message}'));
204+
emit(
205+
state.copyWith(
206+
status: AuthenticationStatus.failure,
207+
errorMessage: 'Server error: ${e.message}',
208+
),
209+
);
125210
} on OperationFailedException catch (e) {
126-
emit(AuthenticationFailure('Operation failed: ${e.message}'));
211+
emit(
212+
state.copyWith(
213+
status: AuthenticationStatus.failure,
214+
errorMessage: 'Operation failed: ${e.message}',
215+
),
216+
);
127217
} on HtHttpException catch (e) {
128218
// Catch any other HtHttpException subtypes
129-
emit(AuthenticationFailure('HTTP error: ${e.message}'));
219+
emit(
220+
state.copyWith(
221+
status: AuthenticationStatus.failure,
222+
errorMessage: 'HTTP error: ${e.message}',
223+
),
224+
);
130225
} catch (e) {
131226
// Catch any other unexpected errors
132-
emit(AuthenticationFailure('An unexpected error occurred: $e'));
227+
emit(
228+
state.copyWith(
229+
status: AuthenticationStatus.failure,
230+
errorMessage: 'An unexpected error occurred: $e',
231+
),
232+
);
133233
// Optionally log the stackTrace here
134234
}
135235
}
@@ -139,26 +239,47 @@ class AuthenticationBloc
139239
AuthenticationSignOutRequested event,
140240
Emitter<AuthenticationState> emit,
141241
) async {
142-
emit(AuthenticationLoading());
242+
emit(state.copyWith(status: AuthenticationStatus.loading));
143243
try {
144244
await _authenticationRepository.signOut();
145-
// On success, the _AuthenticationUserChanged listener will handle
245+
// On success, the _AuthenticationStatusChanged listener will handle
146246
// emitting AuthenticationUnauthenticated.
147-
// No need to emit AuthenticationLoading() before calling signOut if
148-
// the authStateChanges listener handles the subsequent state update.
149-
// However, if immediate feedback is desired, it can be kept.
150-
// For now, let's assume the listener is sufficient.
151247
} on NetworkException catch (_) {
152-
emit(const AuthenticationFailure('Network error occurred.'));
248+
emit(
249+
state.copyWith(
250+
status: AuthenticationStatus.failure,
251+
errorMessage: 'Network error occurred.',
252+
),
253+
);
153254
} on ServerException catch (e) {
154-
emit(AuthenticationFailure('Server error: ${e.message}'));
255+
emit(
256+
state.copyWith(
257+
status: AuthenticationStatus.failure,
258+
errorMessage: 'Server error: ${e.message}',
259+
),
260+
);
155261
} on OperationFailedException catch (e) {
156-
emit(AuthenticationFailure('Operation failed: ${e.message}'));
262+
emit(
263+
state.copyWith(
264+
status: AuthenticationStatus.failure,
265+
errorMessage: 'Operation failed: ${e.message}',
266+
),
267+
);
157268
} on HtHttpException catch (e) {
158269
// Catch any other HtHttpException subtypes
159-
emit(AuthenticationFailure('HTTP error: ${e.message}'));
270+
emit(
271+
state.copyWith(
272+
status: AuthenticationStatus.failure,
273+
errorMessage: 'HTTP error: ${e.message}',
274+
),
275+
);
160276
} catch (e) {
161-
emit(AuthenticationFailure('An unexpected error occurred: $e'));
277+
emit(
278+
state.copyWith(
279+
status: AuthenticationStatus.failure,
280+
errorMessage: 'An unexpected error occurred: $e',
281+
),
282+
);
162283
}
163284
}
164285

lib/authentication/bloc/authentication_event.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ final class AuthenticationSignOutRequested extends AuthenticationEvent {
5555
const AuthenticationSignOutRequested();
5656
}
5757

58-
/// {@template _authentication_user_changed}
59-
/// Internal event triggered when the authentication state changes.
58+
/// {@template _authentication_status_changed}
59+
/// Internal event triggered when the authentication status changes.
6060
/// {@endtemplate}
61-
final class _AuthenticationUserChanged extends AuthenticationEvent {
62-
/// {@macro _authentication_user_changed}
63-
const _AuthenticationUserChanged({required this.user});
61+
final class _AuthenticationStatusChanged extends AuthenticationEvent {
62+
/// {@macro _authentication_status_changed}
63+
const _AuthenticationStatusChanged({this.user});
6464

6565
/// The current authenticated user, or null if unauthenticated.
6666
final User? user;

0 commit comments

Comments
 (0)