Skip to content

Commit

Permalink
Refactor user profile management: add update functionality and improv…
Browse files Browse the repository at this point in the history
…e error handling
  • Loading branch information
Mozart299 committed Mar 4, 2025
1 parent 72bbbed commit ee46901
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,12 @@ class DashboardAppBar extends StatelessWidget implements PreferredSizeWidget {
String lastName = userState.model.users[0].lastName[0].toUpperCase();
return GestureDetector(
onTap: () {
// Navigate to profile screen with user data
// Navigate to profile page
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ProfilePage(),
));
),
);
},
child: CircleAvatar(
radius: 24,
Expand Down
46 changes: 33 additions & 13 deletions src/mobile-v3/lib/src/app/profile/bloc/user_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,40 @@ part 'user_state.dart';

class UserBloc extends Bloc<UserEvent, UserState> {
final UserRepository repository;

UserBloc(this.repository) : super(UserInitial()) {
on<UserEvent>((event, emit) async {
if (event is LoadUser) {
emit(UserLoading());
on<LoadUser>(_onLoadUser);
on<UpdateUser>(_onUpdateUser);
}

Future<void> _onLoadUser(LoadUser event, Emitter<UserState> emit) async {
emit(UserLoading());

try {
ProfileResponseModel model = await repository.loadUserProfile();
emit(UserLoaded(model));
} catch (e) {
print(e.toString());
emit(UserLoadingError(e.toString()));
}
}

try {
ProfileResponseModel model = await this.repository.loadUserProfile();
Future<void> _onUpdateUser(UpdateUser event, Emitter<UserState> emit) async {
emit(UserUpdating());

emit(UserLoaded(model));
} catch (e) {
print(e.toString());
emit(UserLoadingError(e.toString()));
}
}
});
try {
ProfileResponseModel model = await repository.updateUserProfile(
firstName: event.firstName,
lastName: event.lastName,
email: event.email,
);

emit(UserUpdateSuccess(model));
// Also emit UserLoaded state to update the UI
emit(UserLoaded(model));
} catch (e) {
print(e.toString());
emit(UserUpdateError(e.toString()));
}
}
}
}
16 changes: 15 additions & 1 deletion src/mobile-v3/lib/src/app/profile/bloc/user_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,19 @@ sealed class UserEvent extends Equatable {
List<Object> get props => [];
}

final class LoadUser extends UserEvent {}

final class LoadUser extends UserEvent{}
final class UpdateUser extends UserEvent {
final String firstName;
final String lastName;
final String email;

const UpdateUser({
required this.firstName,
required this.lastName,
required this.email,
});

@override
List<Object> get props => [firstName, lastName, email];
}
26 changes: 26 additions & 0 deletions src/mobile-v3/lib/src/app/profile/bloc/user_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,36 @@ final class UserLoaded extends UserState {
final ProfileResponseModel model;

const UserLoaded(this.model);

@override
List<Object> get props => [model];
}

final class UserLoadingError extends UserState {
final String message;

const UserLoadingError(this.message);

@override
List<Object> get props => [message];
}

final class UserUpdating extends UserState {}

final class UserUpdateSuccess extends UserState {
final ProfileResponseModel model;

const UserUpdateSuccess(this.model);

@override
List<Object> get props => [model];
}

final class UserUpdateError extends UserState {
final String message;

const UserUpdateError(this.message);

@override
List<Object> get props => [message];
}
49 changes: 43 additions & 6 deletions src/mobile-v3/lib/src/app/profile/repository/user_repository.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,63 @@
import 'dart:convert';
import 'package:airqo/src/app/profile/models/profile_response_model.dart';
import 'package:airqo/src/app/shared/repository/base_repository.dart';
import 'package:airqo/src/app/shared/repository/base_repository_extension.dart';
import 'package:airqo/src/app/shared/repository/hive_repository.dart';
import 'package:http/http.dart';
import 'package:http/http.dart' as http;

abstract class UserRepository extends BaseRepository {
Future<ProfileResponseModel> loadUserProfile();
Future<ProfileResponseModel> updateUserProfile({
required String firstName,
required String lastName,
required String email,
});
}

class UserImpl extends UserRepository {
@override
Future<ProfileResponseModel> loadUserProfile() async {
final userId = await HiveRepository.getData("userId", HiveBoxNames.authBox);

if (userId == null) {
throw Exception("User ID not found");
}

Response profileResponse =
http.Response profileResponse =
await createAuthenticatedGetRequest("/api/v2/users/${userId}", {});

ProfileResponseModel model =
profileResponseModelFromJson(profileResponse.body);
return model;
}
}

@override
Future<ProfileResponseModel> updateUserProfile({
required String firstName,
required String lastName,
required String email,
}) async {
final userId = await HiveRepository.getData("userId", HiveBoxNames.authBox);
if (userId == null) {
throw Exception("User ID not found");
}

// Prepare the request body with the updated fields
final Map<String, dynamic> requestBody = {
"firstName": firstName,
"lastName": lastName,
"email": email,
};

// The extension should handle error responses
http.Response updateResponse = await createAuthenticatedPutRequest(
data: requestBody,
path: "/api/v2/users/$userId",
);

// Parse the updated user data
ProfileResponseModel model =
profileResponseModelFromJson(updateResponse.body);

return model;
}
}
35 changes: 35 additions & 0 deletions src/mobile-v3/lib/src/app/shared/repository/base_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,41 @@ class BaseRepository {
return _cachedToken;
}

Future<Response> createAuthenticatedPutRequest({
required String path,
required dynamic data
}) async {
String? token = await _getToken();
if (token == null) {
throw Exception('Authentication token not found');
}

String url = ApiUtils.baseUrl + path;
print(url);

Response response = await http.put(
Uri.parse(url),
body: json.encode(data),
headers: {
"Authorization": "Bearer ${token}",
"Accept": "*/*",
"Content-Type": "application/json"
}
);

print(response.statusCode);

if (response.statusCode != 200) {
final responseBody = json.decode(response.body);
final errorMessage = responseBody is Map && responseBody.containsKey('message')
? responseBody['message']
: 'An error occurred';
throw new Exception(errorMessage);
}

return response;
}

Future<Response> createPostRequest(
{required String path, dynamic data}) async {
final token = await _getToken();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'dart:convert';
import 'package:airqo/src/app/shared/repository/base_repository.dart';
import 'package:airqo/src/app/shared/repository/hive_repository.dart';
import 'package:airqo/src/meta/utils/api_utils.dart';
import 'package:http/http.dart' as http;

// Extension to add PUT request functionality to BaseRepository
extension BaseRepositoryExtension on BaseRepository {
// Method to create authenticated PUT requests
Future<http.Response> createAuthenticatedPutRequest({
required String path,
required dynamic data
}) async {
final token = await HiveRepository.getData("token", HiveBoxNames.authBox);
if (token == null) {
throw Exception('Authentication token not found');
}

String url = ApiUtils.baseUrl + path;
print(url);

http.Response response = await http.put(
Uri.parse(url),
body: json.encode(data),
headers: {
"Authorization": "Bearer ${token}",
"Accept": "*/*",
"Content-Type": "application/json"
}
);

print(response.statusCode);

if (response.statusCode != 200) {
final responseBody = json.decode(response.body);
final errorMessage = responseBody is Map && responseBody.containsKey('message')
? responseBody['message']
: 'An error occurred';
throw new Exception(errorMessage);
}

return response;
}
}

0 comments on commit ee46901

Please sign in to comment.