Skip to content

Commit

Permalink
fix: better error messages on login
Browse files Browse the repository at this point in the history
  • Loading branch information
IamMuuo committed Dec 14, 2024
1 parent 1536b80 commit 9cfc5e7
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 18 deletions.
18 changes: 17 additions & 1 deletion lib/features/auth/cubit/auth_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,23 @@ class AuthCubit extends Cubit<AuthState> {
}, (users) {
if (users.isEmpty) {
emit(AuthFirstAppLaunch());
return;
} else if (users.length == 1) {
return fetchUserCredsFromCache(users.first).then((result) {
result.fold((error) {
emit(AuthErrorState(error));
return;
}, (creds) {
authenticate(creds).then((auth) {
auth.fold((error) {
emit(AuthErrorState(error));
return;
}, (r) {
AuthenticatedState(user: users.first);
return;
});
});
});
});
}
emit(AuthCachedUsersRetrieved(cachedUsers: users));
});
Expand Down
6 changes: 3 additions & 3 deletions lib/features/auth/repository/user_remote_repository.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'package:academia/database/database.dart';
import 'package:academia/utils/network/dio_client.dart';
import 'package:academia/utils/network/network.dart';
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';

final class UserRemoteRepository {
final class UserRemoteRepository with DioErrorHandler {
final DioClient _client = DioClient();

/// The function attempts to authenticate a users [credentials] with
Expand All @@ -24,7 +24,7 @@ final class UserRemoteRepository {

return left(response.data["error"] ?? response.statusMessage);
} on DioException catch (de) {
return left(de.response?.data["error"] ?? de.response!.statusMessage);
return handleDioError(de);
} catch (e) {
return left("Please check your internet connection and try that again!");
}
Expand Down
9 changes: 8 additions & 1 deletion lib/features/auth/views/user_selection_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:icons_plus/icons_plus.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:sliver_tools/sliver_tools.dart';

class UserSelectionPage extends StatefulWidget {
Expand Down Expand Up @@ -77,11 +78,17 @@ class _UserSelectionPageState extends State<UserSelectionPage> {
),

// Sliverlist

BlocBuilder<AuthCubit, AuthState>(
buildWhen: (previous, current) {
if (current is AuthCachedUsersRetrieved) {
return true;
}
return false;
},
builder: (context, state) {
final List<UserData> users =
(state as AuthCachedUsersRetrieved).cachedUsers;

return SliverList.builder(
itemCount: users.length,
itemBuilder: (context, index) {
Expand Down
10 changes: 4 additions & 6 deletions lib/features/auth/views/widgets/user_selection_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class UserSelectionTile extends StatefulWidget {
}

class _UserSelectionTileState extends State<UserSelectionTile> {
bool _isLoading = true;
late AuthCubit _authCubit = BlocProvider.of<AuthCubit>(context);

UserProfileData? profile;
Expand Down Expand Up @@ -76,7 +75,9 @@ class _UserSelectionTileState extends State<UserSelectionTile> {
onTap: () async {
final result = await _authCubit.authenticate(creds!);
result.fold((l) {
_showMessageDialog("Authentication Error", l);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(l),
));
}, (r) {
if (!context.mounted) return;
GoRouter.of(context)
Expand All @@ -96,12 +97,9 @@ class _UserSelectionTileState extends State<UserSelectionTile> {
BlocBuilder<AuthCubit, AuthState>(builder: (context, state) {
if (state is AuthLoadingState) {
return const LinearProgressIndicator();
} else if (state is AuthErrorState) {
return Text(state.message);
}
return Text(
profile?.bio ??
"${widget.user.firstname} ${widget.user.othernames}",
profile?.bio ?? "No bio yet",
);
}),
trailing: const Icon(Bootstrap.arrow_right),
Expand Down
23 changes: 23 additions & 0 deletions lib/utils/network/dio_error_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';

mixin DioErrorHandler {
Either<String, T> handleDioError<T>(DioException de) {
switch (de.type) {
case DioExceptionType.connectionError:
return left("Connection refused by server, please try again later");
case DioExceptionType.connectionTimeout:
return left(
"Server took too long to respond, please retry later or check your connection");
case DioExceptionType.receiveTimeout:
return left(
"Server did not send a response in time, please try again later.");
case DioExceptionType.sendTimeout:
return left("Sending request took too long, please try again later.");
default:
return left(de.response?.data["error"] ??
de.response?.statusMessage ??
"An unexpected error occurred. Please try again later.");
}
}
}
1 change: 1 addition & 0 deletions lib/utils/network/network.dart
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export 'dio_client.dart';
export 'dio_error_handler.dart';
17 changes: 10 additions & 7 deletions lib/utils/router/default_route.dart
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import 'package:academia/features/auth/cubit/auth_cubit.dart';
import 'package:academia/features/auth/cubit/auth_states.dart';
import 'package:academia/features/features.dart';
import 'package:academia/utils/router/router.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';

class DefaultRoute extends StatelessWidget {
const DefaultRoute({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocBuilder<AuthCubit, AuthState>(
builder: (context, state) {
if (state is AuthenticatedState) {
return const Layout();
} else if (state is AuthCachedUsersRetrieved) {
return const UserSelectionPage();
body: BlocListener<AuthCubit, AuthState>(
listener: (context, state) {
if (state is AuthCachedUsersRetrieved) {
GoRouter.of(context)
.pushReplacementNamed(AcademiaRouter.userSelection);
} else if (state is AuthenticatedState) {
GoRouter.of(context).pushReplacementNamed(AcademiaRouter.home);
}
return const OnboardingPage();
},
child: const OnboardingPage(),
),
);
}
Expand Down

0 comments on commit 9cfc5e7

Please sign in to comment.