Skip to content

Commit

Permalink
Create forget and reset password page
Browse files Browse the repository at this point in the history
  • Loading branch information
banghuazhao committed Nov 4, 2024
1 parent 758c339 commit a2cbebb
Show file tree
Hide file tree
Showing 21 changed files with 543 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,61 @@ class AuthRepositoryImpl implements AuthRepository {
'Logout failed with status code: ${response.statusCode}');
}
}

Future<void> forgetPassword(String email) async {
final url = Uri.parse('http://localhost:3000/api/auth/forget-password');
try {
final response = await client.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'email': email}),
);

if (response.statusCode != 200) {
// Handle error responses from the server
final responseData = jsonDecode(response.body);
final errorMessage =
responseData['message'] ?? 'Failed to send reset email';
throw ServerException(errorMessage);
}
// If statusCode is 200, assume the request was successful
} catch (error) {
// Re-throw network or parsing errors as custom exceptions
throw Exception('An error occurred. Please try again.');
}
}

Future<String> resetPasswordVerify(String token) async {
final url = Uri.parse(
'http://localhost:3000/api/auth/reset-password-verify/$token');
final response = await client.get(
url,
headers: {'Content-Type': 'application/json'},
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['message'];
} else {
throw ServerException(
'Password reset verification failed with status code: ${response.statusCode}');
}
}

Future<String> resetPassword(String token, String newPassword) async {
final url =
Uri.parse('http://localhost:3000/api/auth/reset-password/$token');
final response = await client.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'password': newPassword}),
);

if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['message'];
} else {
throw ServerException(
'Password reset failed with status code: ${response.statusCode}');
}
}
}
3 changes: 3 additions & 0 deletions domain/lib/repositories_abstract/auth_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ abstract class AuthRepository {
Future<User> signup(String username, String email, String password);
Future<String> login(String username, String password);
Future<void> logout();
Future<void> forgetPassword(String email);
Future<String> resetPasswordVerify(String token);
Future<String> resetPassword(String token, String newPassword);
}
12 changes: 12 additions & 0 deletions domain/lib/usecases/auth_usecase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@ class AuthUseCase {
final token = await tokenProvider.getToken();
return token != null;
}

Future<void> forgetPassword(String email) async {
return await repository.forgetPassword(email);
}

Future<String> resetPasswordVerify(String token) async {
return await repository.resetPasswordVerify(token);
}

Future<String> resetPassword(String token, String newPassword) async {
return await repository.resetPassword(token, newPassword);
}
}
17 changes: 17 additions & 0 deletions firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@
"ignore": [
"firebase.json",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{
"source": "/apple-app-site-association",
"headers": [
{
"key": "Content-Type",
"value": "application/json"
}
]
}
]
}
}
6 changes: 6 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ PODS:
- FlutterMacOS
- amplify_secure_storage (0.0.1):
- Flutter
- app_links (0.0.2):
- Flutter
- app_tracking_transparency (0.0.1):
- Flutter
- device_info (0.0.1):
Expand Down Expand Up @@ -37,6 +39,7 @@ PODS:
DEPENDENCIES:
- amplify_auth_cognito (from `.symlinks/plugins/amplify_auth_cognito/darwin`)
- amplify_secure_storage (from `.symlinks/plugins/amplify_secure_storage/ios`)
- app_links (from `.symlinks/plugins/app_links/ios`)
- app_tracking_transparency (from `.symlinks/plugins/app_tracking_transparency/ios`)
- device_info (from `.symlinks/plugins/device_info/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
Expand All @@ -60,6 +63,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/amplify_auth_cognito/darwin"
amplify_secure_storage:
:path: ".symlinks/plugins/amplify_secure_storage/ios"
app_links:
:path: ".symlinks/plugins/app_links/ios"
app_tracking_transparency:
:path: ".symlinks/plugins/app_tracking_transparency/ios"
device_info:
Expand Down Expand Up @@ -90,6 +95,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
amplify_auth_cognito: 76b5a54f05f66f69966b468b8121a0dd33a32c70
amplify_secure_storage: be403397a8ba39f5e0f2a05303b3ca03b53b9ee9
app_links: e7a6750a915a9e161c58d91bc610e8cd1d4d0ad0
app_tracking_transparency: e169b653478da7bb15a6c61209015378ca73e375
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
Expand Down
5 changes: 5 additions & 0 deletions ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
99A3D7612CD6FBC600B93DAF /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
D51570C31D4B8C71E4A0A233 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
F0101E625D9607551D7077EF /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -112,6 +113,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
99A3D7612CD6FBC600B93DAF /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
Expand Down Expand Up @@ -357,6 +359,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2410201826;
Expand Down Expand Up @@ -490,6 +493,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2410201826;
Expand Down Expand Up @@ -517,6 +521,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2410201826;
Expand Down
11 changes: 11 additions & 0 deletions ios/Runner/Runner.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:compositesai.com</string>
<string>webcredentials:compositesai.com</string>
</array>
</dict>
</plist>
6 changes: 5 additions & 1 deletion lib/injection_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:data/data_sources/authenticated_http_client.dart';
import 'package:data/data_sources/function_tools_data_source.dart';
import 'package:data/data_sources/open_ai_data_source.dart';
import 'package:data/providers/token_provider_impl.dart';
import 'package:data/repositories/auth_repository.dart';
import 'package:data/repositories/auth_repository_impl.dart';
import 'package:data/repositories/chat_repository_impl.dart';
import 'package:data/repositories/chat_session_repository_imp.dart';
import 'package:data/repositories/user_repository.dart';
Expand All @@ -17,7 +17,9 @@ import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;
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/forget_password_view_model.dart';
import 'package:swiftcomp/presentation/settings/viewModels/login_view_model.dart';
import 'package:swiftcomp/presentation/settings/viewModels/reset_password_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';
Expand All @@ -42,6 +44,8 @@ void initInjection() {
() => FeatureFlagViewModel(featureFlagProvider: sl()));
sl.registerFactory<UserProfileViewModel>(() =>
UserProfileViewModel(authUseCase: sl(), userUseCase: sl()));
sl.registerFactory<ResetPasswordViewModel>(() => ResetPasswordViewModel(authUseCase: sl()));
sl.registerFactory<ForgetPasswordViewModel>(() => ForgetPasswordViewModel(authUseCase: sl()));

// Providers
sl.registerLazySingleton<TokenProvider>(() => TokenProviderImpl());
Expand Down
4 changes: 3 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import 'dart:async';

import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
Expand Down Expand Up @@ -59,7 +62,6 @@ class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();

_configureAmplify();
}

Expand Down
61 changes: 60 additions & 1 deletion lib/presentation/bottom_navigator.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import 'package:app_links/app_links.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:swiftcomp/presentation/chat/viewModels/chat_view_model.dart';
import 'package:swiftcomp/presentation/settings/providers/feature_flag_provider.dart';
import 'package:swiftcomp/presentation/settings/views/reset_password_page.dart';
import 'package:swiftcomp/presentation/tools/page/tool_page.dart';

import 'chat/views/chat_screen.dart';
Expand All @@ -15,6 +18,7 @@ class BottomNavigator extends StatefulWidget {
}

class _BottomNavigatorState extends State<BottomNavigator> {
late final AppLinks _appLinks;
final PageController _controller = PageController(
initialPage: 0,
);
Expand All @@ -26,6 +30,11 @@ class _BottomNavigatorState extends State<BottomNavigator> {
@override
void initState() {
super.initState();
if (kIsWeb) {
_handleWebLink();
} else {
_setupAppLinks();
}
}

@override
Expand All @@ -41,7 +50,11 @@ class _BottomNavigatorState extends State<BottomNavigator> {
body: PageView(
controller: _controller,
physics: const NeverScrollableScrollPhysics(),
children: [if (isChatEnabled) ChatScreen(), ToolPage(), SettingsPage()],
children: [
if (isChatEnabled) ChatScreen(),
ToolPage(),
SettingsPage()
],
),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Color.fromRGBO(51, 66, 78, 1),
Expand Down Expand Up @@ -78,4 +91,50 @@ class _BottomNavigatorState extends State<BottomNavigator> {
),
label: title);
}

void _handleWebLink() {
final uri = Uri.base;
final pathSegments = uri.pathSegments;
if (uri.host == 'compositesai.com' || uri.host == 'localhost') {
if (uri.pathSegments.isNotEmpty && pathSegments[0] == 'reset-password') {
final token = pathSegments[1];
WidgetsBinding.instance.addPostFrameCallback((_) {
_navigateToResetPasswordPage(token);
});
}
}
}

void _setupAppLinks() async {
_appLinks = AppLinks();

_appLinks.getInitialLink().then((uri) {
if (uri != null) {
print(uri);
}
});

_appLinks.uriLinkStream.listen((uri) {
print(uri);
final token =
uri.pathSegments.length > 1 && uri.pathSegments[0] == 'reset-password'
? uri.pathSegments[1]
: uri.queryParameters['token'];
print(token);
if (token != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_navigateToResetPasswordPage(token);
});
}
});
}

void _navigateToResetPasswordPage(String token) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResetPasswordPage(token: token),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ 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 {
const ForgetPasswordPage({Key? key}) : super(key: key);
class ForgetPasswordPageOld extends StatefulWidget {
const ForgetPasswordPageOld({Key? key}) : super(key: key);

@override
_ForgetPasswordPageState createState() => _ForgetPasswordPageState();
_ForgetPasswordPageOldState createState() => _ForgetPasswordPageOldState();
}

class _ForgetPasswordPageState extends State<ForgetPasswordPage> {
class _ForgetPasswordPageOldState extends State<ForgetPasswordPageOld> {
bool confirmEnable = false;
bool resetEnable = false;
String? email;
Expand Down
4 changes: 2 additions & 2 deletions lib/presentation/settings/login/old_login_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:swiftcomp/presentation/settings/login/registration_page.dart';
import 'package:swiftcomp/util/string_util.dart';

import 'email_confimation_screen.dart';
import 'forget_password_page.dart';
import 'forget_password_page_old.dart';

class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
Expand Down Expand Up @@ -80,7 +80,7 @@ class _LoginPageState extends State<LoginPage> {
enable: true,
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const ForgetPasswordPage()));
MaterialPageRoute(builder: (context) => const ForgetPasswordPageOld()));
},
)),
],
Expand Down
Loading

0 comments on commit a2cbebb

Please sign in to comment.