Skip to content

Commit

Permalink
Create user profile page with delete account function
Browse files Browse the repository at this point in the history
  • Loading branch information
banghuazhao committed Oct 30, 2024
1 parent a1ea9a1 commit 758c339
Show file tree
Hide file tree
Showing 34 changed files with 231 additions and 59 deletions.
10 changes: 10 additions & 0 deletions data/lib/repositories/user_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,14 @@ class UserRepositoryImpl implements UserRepository {
throw Exception('Failed to sign up. Status code: ${response.statusCode}');
}
}

@override
Future<void> deleteAccount() async {
final url = Uri.parse('http://localhost:3000/api/users/me');
final response = await authClient.delete(url);

if (response.statusCode != 200) {
throw Exception('Failed to delete account. Status code: ${response.statusCode}');
}
}
}
11 changes: 10 additions & 1 deletion domain/lib/entities/user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@ class User {
final String username;
final String email;
final String? name;
final String? description;
final String? avatarUrl;

User({required this.username, required this.email, this.name});
User(
{required this.username,
required this.email,
this.name,
this.description,
this.avatarUrl});

// Factory constructor to create a User instance from JSON
factory User.fromJson(Map<String, dynamic> json) {
return User(
username: json['username'] ?? '',
email: json['email'] ?? '',
name: json['name'],
description: json['description'],
avatarUrl: json['avatarUrl'],
);
}
}
1 change: 1 addition & 0 deletions domain/lib/repositories_abstract/user_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ import '../entities/user.dart';

abstract class UserRepository {
Future<User> fetchMe();
Future<void> deleteAccount();
}
1 change: 0 additions & 1 deletion domain/lib/usecases/auth_usecase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class AuthUseCase {
return;
}

@override
Future<bool> isLoggedIn() async {
final token = await tokenProvider.getToken();
return token != null;
Expand Down
9 changes: 8 additions & 1 deletion domain/lib/usecases/user_usercase.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import '../entities/user.dart';
import '../repositories_abstract/token_provider.dart';
import '../repositories_abstract/user_repository.dart';

class UserUseCase {
final UserRepository repository;
final TokenProvider tokenProvider;

UserUseCase({required this.repository});
UserUseCase({required this.repository, required this.tokenProvider});

Future<User> fetchMe() async {
return await repository.fetchMe();
}

Future<void> deleteAccount() async {
await repository.deleteAccount();
tokenProvider.deleteToken();
}
}
52 changes: 29 additions & 23 deletions lib/injection_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,65 +15,71 @@ import 'package:domain/usecases/function_tools_usecase.dart';
import 'package:domain/usecases/user_usercase.dart';
import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;
import 'package:swiftcomp/presentation/more/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/more/viewModels/feature_flag_view_model.dart';
import 'package:swiftcomp/presentation/more/viewModels/login_view_model.dart';
import 'package:swiftcomp/presentation/more/viewModels/settings_view_model.dart';
import 'package:swiftcomp/presentation/more/viewModels/signup_view_model.dart';
import 'package:swiftcomp/presentation/settings/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/settings/viewModels/feature_flag_view_model.dart';
import 'package:swiftcomp/presentation/settings/viewModels/login_view_model.dart';
import 'package:swiftcomp/presentation/settings/viewModels/settings_view_model.dart';
import 'package:swiftcomp/presentation/settings/viewModels/signup_view_model.dart';
import 'package:swiftcomp/presentation/settings/viewModels/user_profile_view_model.dart';
import 'presentation/chat/viewModels/chat_view_model.dart';

final sl = GetIt.instance;

void initInjection() {
// ViewModels
sl.registerFactory<ChatViewModel>(() => ChatViewModel(
chatUseCase: sl(),
chatSessionUseCase: sl(),
functionToolsUseCase: sl(),
authUseCase: sl()));
sl.registerFactory<ChatViewModel>(() =>
ChatViewModel(
chatUseCase: sl(),
chatSessionUseCase: sl(),
functionToolsUseCase: sl(),
authUseCase: sl()));
sl.registerFactory<LoginViewModel>(() => LoginViewModel(authUseCase: sl()));
sl.registerFactory<SignupViewModel>(() => SignupViewModel(authUseCase: sl()));
sl.registerFactory<SettingsViewModel>(() => SettingsViewModel(
authUseCase: sl(), userUserCase: sl(), featureFlagProvider: sl()));
sl.registerFactory<SettingsViewModel>(() =>
SettingsViewModel(
authUseCase: sl(), userUserCase: sl(), featureFlagProvider: sl()));
sl.registerFactory<FeatureFlagViewModel>(
() => FeatureFlagViewModel(featureFlagProvider: sl()));
() => FeatureFlagViewModel(featureFlagProvider: sl()));
sl.registerFactory<UserProfileViewModel>(() =>
UserProfileViewModel(authUseCase: sl(), userUseCase: sl()));

// Providers
sl.registerLazySingleton<TokenProvider>(() => TokenProviderImpl());
sl.registerLazySingleton<FeatureFlagProvider>(() => FeatureFlagProvider());

// Use Cases
sl.registerLazySingleton<ChatUseCase>(
() => ChatUseCase(chatRepository: sl()));
() => ChatUseCase(chatRepository: sl()));

sl.registerLazySingleton<ChatSessionUseCase>(
() => ChatSessionUseCase(repository: sl()));
() => ChatSessionUseCase(repository: sl()));

sl.registerLazySingleton<FunctionToolsUseCase>(() => FunctionToolsUseCase());

sl.registerLazySingleton<AuthUseCase>(
() => AuthUseCase(repository: sl(), tokenProvider: sl()));
sl.registerLazySingleton<UserUseCase>(() => UserUseCase(repository: sl()));
() => AuthUseCase(repository: sl(), tokenProvider: sl()));
sl.registerLazySingleton<UserUseCase>(
() => UserUseCase(repository: sl(), tokenProvider: sl()));

// Repositories
sl.registerLazySingleton<ChatRepository>(() =>
ChatRepositoryImp(openAIDataSource: sl(), functionToolsDataSource: sl()));
sl.registerLazySingleton<ChatSessionRepository>(
() => ChatSessionRepositoryImpl());
() => ChatSessionRepositoryImpl());
sl.registerLazySingleton<AuthRepository>(
() => AuthRepositoryImpl(client: sl(), authClient: sl()));
() => AuthRepositoryImpl(client: sl(), authClient: sl()));
sl.registerLazySingleton<UserRepository>(
() => UserRepositoryImpl(authClient: sl()));
() => UserRepositoryImpl(authClient: sl()));

// Data Sources
sl.registerLazySingleton<OpenAIDataSource>(
() => ChatRemoteDataSourceImpl(client: sl()));
() => ChatRemoteDataSourceImpl(client: sl()));
sl.registerLazySingleton<FunctionToolsDataSource>(
() => FunctionToolsDataSourceImp());
() => FunctionToolsDataSourceImp());

// External
sl.registerLazySingleton(() => http.Client());
sl.registerLazySingleton<AuthenticatedHttpClient>(
() => AuthenticatedHttpClient(sl(), sl()));
() => AuthenticatedHttpClient(sl(), sl()));
;
}
4 changes: 2 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart';
import 'package:swiftcomp/generated/l10n.dart';
import 'package:swiftcomp/presentation/chat/viewModels/chat_view_model.dart';
import 'package:swiftcomp/presentation/more/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/more/viewModels/settings_view_model.dart';
import 'package:swiftcomp/presentation/settings/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/settings/viewModels/settings_view_model.dart';
import 'package:swiftcomp/util/NumberPrecisionHelper.dart';
import 'package:swiftcomp/util/in_app_reviewer_helper.dart';
import 'package:swiftcomp/util/others.dart';
Expand Down
4 changes: 2 additions & 2 deletions lib/presentation/bottom_navigator.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:swiftcomp/presentation/chat/viewModels/chat_view_model.dart';
import 'package:swiftcomp/presentation/more/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/settings/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/tools/page/tool_page.dart';

import 'chat/views/chat_screen.dart';
import 'more/views/settings_page.dart';
import 'settings/views/settings_page.dart';

class BottomNavigator extends StatefulWidget {
const BottomNavigator({Key? key}) : super(key: key);
Expand Down
4 changes: 2 additions & 2 deletions lib/presentation/chat/views/chat_screen.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:swiftcomp/presentation/more/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/settings/providers/feature_flag_provider.dart';

import '../../../injection_container.dart';
import '../../../main.dart';
import '../../more/views/login_page.dart';
import '../../settings/views/login_page.dart';
import '../viewModels/chat_view_model.dart';
import 'chat_message_list.dart';
import 'chat_session_drawer.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:swiftcomp/presentation/more/login/login_button.dart';
import 'package:swiftcomp/presentation/settings/login/login_button.dart';

class EmailConfirmationScreen extends StatelessWidget {
final String email;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:swiftcomp/presentation/more/login/login_button.dart';
import 'package:swiftcomp/presentation/more/login/login_input.dart';
import 'package:swiftcomp/presentation/settings/login/login_button.dart';
import 'package:swiftcomp/presentation/settings/login/login_input.dart';
import 'package:swiftcomp/util/string_util.dart';

class ForgetPasswordPage extends StatefulWidget {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:swiftcomp/presentation/more/login/login_button.dart';
import 'package:swiftcomp/presentation/more/login/login_input.dart';
import 'package:swiftcomp/presentation/more/login/registration_page.dart';
import 'package:swiftcomp/presentation/settings/login/login_button.dart';
import 'package:swiftcomp/presentation/settings/login/login_input.dart';
import 'package:swiftcomp/presentation/settings/login/registration_page.dart';
import 'package:swiftcomp/util/string_util.dart';

import 'email_confimation_screen.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:swiftcomp/presentation/more/login/login_button.dart';
import 'package:swiftcomp/presentation/more/login/login_input.dart';
import 'package:swiftcomp/presentation/settings/login/login_button.dart';
import 'package:swiftcomp/presentation/settings/login/login_input.dart';
import 'package:swiftcomp/util/string_util.dart';

import 'email_confimation_screen.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:swiftcomp/presentation/more/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/settings/providers/feature_flag_provider.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:launch_review/launch_review.dart';
import 'package:share/share.dart';
Expand Down
52 changes: 52 additions & 0 deletions lib/presentation/settings/viewModels/user_profile_view_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'package:domain/entities/user.dart';
import 'package:domain/usecases/user_usercase.dart';
import 'package:flutter/material.dart';
import 'package:domain/usecases/auth_usecase.dart'; // Assuming your use cases are here

class UserProfileViewModel extends ChangeNotifier {
final AuthUseCase authUseCase;
final UserUseCase userUseCase;

bool isLoading = false;
User? user;

UserProfileViewModel({required this.authUseCase, required this.userUseCase}) {
fetchUserDetails();
}

Future<void> fetchUserDetails() async {
setLoading(true);
try {
user = await userUseCase.fetchMe(); // Assuming a getUser method
} catch (e) {
print("Failed to fetch user details: $e");
}
setLoading(false);
}

Future<void> logoutUser() async {
setLoading(true);
try {
await authUseCase.logout();
} catch (e) {
print("Logout failed: $e");
}
setLoading(false);
}

Future<void> deleteUser() async {
setLoading(true);
try {
await userUseCase.deleteAccount();
print("Account deleted successfully");
} catch (e) {
print("Account deletion failed: $e");
}
setLoading(false);
}

void setLoading(bool value) {
isLoading = value;
notifyListeners();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:swiftcomp/presentation/more/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/settings/providers/feature_flag_provider.dart';

import '../../../injection_container.dart';
import '../viewModels/feature_flag_view_model.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:domain/entities/user.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:swiftcomp/presentation/more/views/sigup_page.dart';
import 'package:swiftcomp/presentation/settings/views/sigup_page.dart';

import '../../../../injection_container.dart';
import '../viewModels/login_view_model.dart';
Expand All @@ -27,7 +27,7 @@ class _LoginPageState extends State<NewLoginPage> {
if (accessToken != null) {
// Login successful
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Login Successful!')),
SnackBar(content: Text('Login Successful!'), duration: Duration(seconds: 2),),
);
Navigator.pop(context, "Log in Success");
} else if (viewModel.errorMessage != null) {
Expand All @@ -54,6 +54,7 @@ class _LoginPageState extends State<NewLoginPage> {
children: [
// Username Field
TextFormField(
controller: _usernameController,
decoration: InputDecoration(labelText: 'Username'),
onChanged: (value) => username = value.trim(),
validator: (value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:swiftcomp/presentation/settings/views/user_profile_page.dart';
import '../login/old_login_page.dart';
import '../viewModels/settings_view_model.dart';
import 'feature_flag_page.dart';
Expand Down Expand Up @@ -58,14 +59,15 @@ class _SettingsPageState extends State<SettingsPage> {
),
subtitle: Text(viewModel.user?.email ?? ""),
onTap: () {
// Optional: Navigate to Profile Page or Show Profile Options
Navigator.push(context,
MaterialPageRoute(builder: (context) => UserProfilePage()))
.then((value) {
if (value == 'refresh') {
viewModel.fetchAuthSessionNew();
}
});
},
),
if (viewModel.isNewLoginEnabled && viewModel.isLoggedIn)
MoreRow(
title: "New Logout",
leadingIcon: Icons.person_rounded,
onTap: () async => viewModel.newLogout(context)),
MoreRow(
title: viewModel.isSignedIn ? "Logout" : "Login",
leadingIcon: Icons.person_rounded,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ class _SignupFormState extends State<SignupForm> {
if (user != null) {
// Show success message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Signup successful!")),
SnackBar(content: Text("Signup successful!"), duration: Duration(seconds: 2),),
);

// Wait for a short delay before popping the screen
await Future.delayed(Duration(seconds: 1));
Navigator.pop(context, user);
} else if (viewModel.errorMessage != null) {
// Display an error message
Expand Down
Loading

0 comments on commit 758c339

Please sign in to comment.