Skip to content

Commit f90017d

Browse files
authored
Merge pull request #19 from CoderJava/feature/buat-fitur-forgot-password
Feature - buat fitur forgot password
2 parents 3499026 + 9857b6d commit f90017d

File tree

41 files changed

+2875
-150
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2875
-150
lines changed

assets/translations/en-US.json

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@
3333
"user_not_found": "Sorry... We could not found your account",
3434
"wrong_password_login": "Incorrect email or password",
3535
"please_verify_your_email": "Please verify your email",
36-
"subtitle_reset_password": "No worries, we'll send you reset instructions",
36+
"subtitle_forgot_password": "No worries, we'll send you reset instructions",
3737
"reset_password": "Reset Password",
3838
"reset_password_failed": "Reset password failed",
3939
"reset_password_successfully": "Reset Password Successfully",
40-
"subtitle_reset_password_successfully": "We sent a password reset link to",
40+
"subtitle_reset_password_successfully": "Awesome. You've successfully reset your password.",
4141
"choose_project": "Choose project",
4242
"tasks": {
4343
"zero": "Task",
@@ -236,5 +236,15 @@
236236
"track_id_invalid": "Invalid track ID",
237237
"deleting_track": "Please wait a moment track data is\nbeing deleted",
238238
"dismiss": "Dismiss",
239-
"track_data_successfully_deleted": "Track data successfully deleted"
239+
"track_data_successfully_deleted": "Track data successfully deleted",
240+
"continue": "Continue",
241+
"verify": "Verify",
242+
"verify_forgot_password": "Verify Forgot Password",
243+
"subtitle_verify_forgot_password": "Enter the forgot password code we have sent to:",
244+
"code": "Code",
245+
"enter_a_code": "Enter a code",
246+
"new_password": "New Password",
247+
"subtitle_new_password": "Please create a new password that you don't use on any other site",
248+
"change": "Change",
249+
"create_new_password": "Create new password"
240250
}

lib/feature/data/datasource/auth/auth_remote_data_source.dart

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import 'package:dio/dio.dart';
22
import 'package:dipantau_desktop_client/config/flavor_config.dart';
33
import 'package:dipantau_desktop_client/core/util/enum/user_role.dart';
4+
import 'package:dipantau_desktop_client/feature/data/model/forgot_password/forgot_password_body.dart';
5+
import 'package:dipantau_desktop_client/feature/data/model/general/general_response.dart';
46
import 'package:dipantau_desktop_client/feature/data/model/login/login_body.dart';
57
import 'package:dipantau_desktop_client/feature/data/model/login/login_response.dart';
68
import 'package:dipantau_desktop_client/feature/data/model/refresh_token/refresh_token_body.dart';
9+
import 'package:dipantau_desktop_client/feature/data/model/reset_password/reset_password_body.dart';
710
import 'package:dipantau_desktop_client/feature/data/model/sign_up/sign_up_body.dart';
811
import 'package:dipantau_desktop_client/feature/data/model/sign_up/sign_up_response.dart';
12+
import 'package:dipantau_desktop_client/feature/data/model/verify_forgot_password/verify_forgot_password_body.dart';
913

1014
abstract class AuthRemoteDataSource {
1115
/// Panggil endpoint [host]/auth/login
@@ -28,6 +32,21 @@ abstract class AuthRemoteDataSource {
2832
late String pathRefreshToken;
2933

3034
Future<LoginResponse> refreshToken(RefreshTokenBody body);
35+
36+
/// Panggil endpoint [host]/auth/forgot-password
37+
late String pathForgotPassword;
38+
39+
Future<GeneralResponse> forgotPassword(ForgotPasswordBody body);
40+
41+
/// Panggil endpoint [host]/auth/forgot-password/verify
42+
late String pathVerifyForgotPassword;
43+
44+
Future<GeneralResponse> verifyForgotPassword(VerifyForgotPasswordBody body);
45+
46+
/// Panggil endpoint [host]/auth/reset-password
47+
late String pathResetPassword;
48+
49+
Future<GeneralResponse> resetPassword(ResetPasswordBody body);
3150
}
3251

3352
class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
@@ -103,4 +122,55 @@ class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
103122
throw DioException(requestOptions: RequestOptions(path: pathRefreshToken));
104123
}
105124
}
125+
126+
@override
127+
String pathForgotPassword = '';
128+
129+
@override
130+
Future<GeneralResponse> forgotPassword(ForgotPasswordBody body) async {
131+
pathForgotPassword = '$baseUrl/forgot-password';
132+
final response = await dio.post(
133+
pathForgotPassword,
134+
data: body.toJson(),
135+
);
136+
if (response.statusCode.toString().startsWith('2')) {
137+
return GeneralResponse.fromJson(response.data);
138+
} else {
139+
throw DioException(requestOptions: RequestOptions(path: pathForgotPassword));
140+
}
141+
}
142+
143+
@override
144+
String pathVerifyForgotPassword = '';
145+
146+
@override
147+
Future<GeneralResponse> verifyForgotPassword(VerifyForgotPasswordBody body) async {
148+
pathVerifyForgotPassword = '$baseUrl/forgot-password/verify';
149+
final response = await dio.post(
150+
pathVerifyForgotPassword,
151+
data: body.toJson(),
152+
);
153+
if (response.statusCode.toString().startsWith('2')) {
154+
return GeneralResponse.fromJson(response.data);
155+
} else {
156+
throw DioException(requestOptions: RequestOptions(path: pathVerifyForgotPassword));
157+
}
158+
}
159+
160+
@override
161+
String pathResetPassword = '';
162+
163+
@override
164+
Future<GeneralResponse> resetPassword(ResetPasswordBody body) async {
165+
pathResetPassword = '$baseUrl/reset-password';
166+
final response = await dio.post(
167+
pathResetPassword,
168+
data: body.toJson(),
169+
);
170+
if (response.statusCode.toString().startsWith('2')) {
171+
return GeneralResponse.fromJson(response.data);
172+
} else {
173+
throw DioException(requestOptions: RequestOptions(path: pathResetPassword));
174+
}
175+
}
106176
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import 'package:equatable/equatable.dart';
2+
import 'package:json_annotation/json_annotation.dart';
3+
4+
part 'forgot_password_body.g.dart';
5+
6+
@JsonSerializable()
7+
class ForgotPasswordBody extends Equatable {
8+
@JsonKey(name: 'email')
9+
final String email;
10+
11+
ForgotPasswordBody({required this.email});
12+
13+
factory ForgotPasswordBody.fromJson(Map<String, dynamic> json) => _$ForgotPasswordBodyFromJson(json);
14+
15+
Map<String, dynamic> toJson() => _$ForgotPasswordBodyToJson(this);
16+
17+
@override
18+
List<Object?> get props => [
19+
email,
20+
];
21+
22+
@override
23+
String toString() {
24+
return 'ForgotPasswordBody{email: $email}';
25+
}
26+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'package:equatable/equatable.dart';
2+
import 'package:json_annotation/json_annotation.dart';
3+
4+
part 'reset_password_body.g.dart';
5+
6+
@JsonSerializable()
7+
class ResetPasswordBody extends Equatable {
8+
@JsonKey(name: 'code')
9+
final String code;
10+
@JsonKey(name: 'password')
11+
final String password;
12+
13+
ResetPasswordBody({
14+
required this.code,
15+
required this.password,
16+
});
17+
18+
factory ResetPasswordBody.fromJson(Map<String, dynamic> json) => _$ResetPasswordBodyFromJson(json);
19+
20+
Map<String, dynamic> toJson() => _$ResetPasswordBodyToJson(this);
21+
22+
@override
23+
List<Object?> get props => [
24+
code,
25+
password,
26+
];
27+
28+
@override
29+
String toString() {
30+
return 'ResetPasswordBody{code: $code, password: $password}';
31+
}
32+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import 'package:equatable/equatable.dart';
2+
import 'package:json_annotation/json_annotation.dart';
3+
4+
part 'verify_forgot_password_body.g.dart';
5+
6+
@JsonSerializable()
7+
class VerifyForgotPasswordBody extends Equatable {
8+
@JsonKey(name: 'code')
9+
final String code;
10+
11+
VerifyForgotPasswordBody({required this.code});
12+
13+
factory VerifyForgotPasswordBody.fromJson(Map<String, dynamic> json) => _$VerifyForgotPasswordBodyFromJson(json);
14+
15+
Map<String, dynamic> toJson() => _$VerifyForgotPasswordBodyToJson(this);
16+
17+
@override
18+
List<Object?> get props => [
19+
code,
20+
];
21+
22+
@override
23+
String toString() {
24+
return 'VerifyForgotPasswordBody{code: $code}';
25+
}
26+
}

lib/feature/data/repository/auth/auth_repository_impl.dart

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ import 'package:dio/dio.dart';
33
import 'package:dipantau_desktop_client/core/error/failure.dart';
44
import 'package:dipantau_desktop_client/core/network/network_info.dart';
55
import 'package:dipantau_desktop_client/feature/data/datasource/auth/auth_remote_data_source.dart';
6+
import 'package:dipantau_desktop_client/feature/data/model/forgot_password/forgot_password_body.dart';
7+
import 'package:dipantau_desktop_client/feature/data/model/general/general_response.dart';
68
import 'package:dipantau_desktop_client/feature/data/model/login/login_body.dart';
79
import 'package:dipantau_desktop_client/feature/data/model/login/login_response.dart';
810
import 'package:dipantau_desktop_client/feature/data/model/refresh_token/refresh_token_body.dart';
11+
import 'package:dipantau_desktop_client/feature/data/model/reset_password/reset_password_body.dart';
912
import 'package:dipantau_desktop_client/feature/data/model/sign_up/sign_up_body.dart';
1013
import 'package:dipantau_desktop_client/feature/data/model/sign_up/sign_up_response.dart';
14+
import 'package:dipantau_desktop_client/feature/data/model/verify_forgot_password/verify_forgot_password_body.dart';
1115
import 'package:dipantau_desktop_client/feature/domain/repository/auth/auth_repository.dart';
1216

1317
class AuthRepositoryImpl implements AuthRepository {
@@ -109,4 +113,94 @@ class AuthRepositoryImpl implements AuthRepository {
109113
return Left(ConnectionFailure());
110114
}
111115
}
116+
117+
@override
118+
Future<({Failure? failure, GeneralResponse? response})> forgotPassword(ForgotPasswordBody body) async {
119+
Failure? failure;
120+
GeneralResponse? response;
121+
final isConnected = await networkInfo.isConnected;
122+
if (isConnected) {
123+
try {
124+
response = await remoteDataSource.forgotPassword(body);
125+
} on DioException catch (error) {
126+
final message = error.message ?? error.toString();
127+
if (error.response == null) {
128+
failure = ServerFailure(message);
129+
} else {
130+
final errorMessage = getErrorMessageFromEndpoint(
131+
error.response?.data,
132+
message,
133+
error.response?.statusCode,
134+
);
135+
failure = ServerFailure(errorMessage);
136+
}
137+
} on TypeError catch (error) {
138+
final errorMessage = error.toString();
139+
failure = ParsingFailure(errorMessage);
140+
}
141+
} else {
142+
failure = ConnectionFailure();
143+
}
144+
return (failure: failure, response: response);
145+
}
146+
147+
@override
148+
Future<({Failure? failure, GeneralResponse? response})> verifyForgotPassword(VerifyForgotPasswordBody body) async {
149+
Failure? failure;
150+
GeneralResponse? response;
151+
final isConnected = await networkInfo.isConnected;
152+
if (isConnected) {
153+
try {
154+
response = await remoteDataSource.verifyForgotPassword(body);
155+
} on DioException catch (error) {
156+
final message = error.message ?? error.toString();
157+
if (error.response == null) {
158+
failure = ServerFailure(message);
159+
} else {
160+
final errorMessage = getErrorMessageFromEndpoint(
161+
error.response?.data,
162+
message,
163+
error.response?.statusCode,
164+
);
165+
failure = ServerFailure(errorMessage);
166+
}
167+
} on TypeError catch (error) {
168+
final errorMessage = error.toString();
169+
failure = ParsingFailure(errorMessage);
170+
}
171+
} else {
172+
failure = ConnectionFailure();
173+
}
174+
return (failure: failure, response: response);
175+
}
176+
177+
@override
178+
Future<({Failure? failure, GeneralResponse? response})> resetPassword(ResetPasswordBody body) async {
179+
Failure? failure;
180+
GeneralResponse? response;
181+
final isConnected = await networkInfo.isConnected;
182+
if (isConnected) {
183+
try {
184+
response = await remoteDataSource.resetPassword(body);
185+
} on DioException catch (error) {
186+
final message = error.message ?? error.toString();
187+
if (error.response == null) {
188+
failure = ServerFailure(message);
189+
} else {
190+
final errorMessage = getErrorMessageFromEndpoint(
191+
error.response?.data,
192+
message,
193+
error.response?.statusCode,
194+
);
195+
failure = ServerFailure(errorMessage);
196+
}
197+
} on TypeError catch (error) {
198+
final errorMessage = error.toString();
199+
failure = ParsingFailure(errorMessage);
200+
}
201+
} else {
202+
failure = ConnectionFailure();
203+
}
204+
return (failure: failure, response: response);
205+
}
112206
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
import 'package:dartz/dartz.dart';
22
import 'package:dipantau_desktop_client/core/error/failure.dart';
3+
import 'package:dipantau_desktop_client/feature/data/model/forgot_password/forgot_password_body.dart';
4+
import 'package:dipantau_desktop_client/feature/data/model/general/general_response.dart';
35
import 'package:dipantau_desktop_client/feature/data/model/login/login_body.dart';
46
import 'package:dipantau_desktop_client/feature/data/model/login/login_response.dart';
57
import 'package:dipantau_desktop_client/feature/data/model/refresh_token/refresh_token_body.dart';
8+
import 'package:dipantau_desktop_client/feature/data/model/reset_password/reset_password_body.dart';
69
import 'package:dipantau_desktop_client/feature/data/model/sign_up/sign_up_body.dart';
710
import 'package:dipantau_desktop_client/feature/data/model/sign_up/sign_up_response.dart';
11+
import 'package:dipantau_desktop_client/feature/data/model/verify_forgot_password/verify_forgot_password_body.dart';
812

913
abstract class AuthRepository {
1014
Future<Either<Failure, LoginResponse>> login(LoginBody body);
1115

1216
Future<Either<Failure, SignUpResponse>> signUp(SignUpBody body);
1317

1418
Future<Either<Failure, LoginResponse>> refreshToken(RefreshTokenBody body);
19+
20+
Future<({Failure? failure, GeneralResponse? response})> forgotPassword(ForgotPasswordBody body);
21+
22+
Future<({Failure? failure, GeneralResponse? response})> verifyForgotPassword(VerifyForgotPasswordBody body);
23+
24+
Future<({Failure? failure, GeneralResponse? response})> resetPassword(ResetPasswordBody body);
1525
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import 'package:dipantau_desktop_client/core/error/failure.dart';
2+
import 'package:dipantau_desktop_client/core/usecase/usecase.dart';
3+
import 'package:dipantau_desktop_client/feature/data/model/forgot_password/forgot_password_body.dart';
4+
import 'package:dipantau_desktop_client/feature/data/model/general/general_response.dart';
5+
import 'package:dipantau_desktop_client/feature/domain/repository/auth/auth_repository.dart';
6+
import 'package:equatable/equatable.dart';
7+
8+
class ForgotPassword implements UseCaseRecords<GeneralResponse, ParamsForgotPassword> {
9+
final AuthRepository repository;
10+
11+
ForgotPassword({required this.repository});
12+
13+
@override
14+
Future<({Failure? failure, GeneralResponse? response})> call(ParamsForgotPassword params) {
15+
return repository.forgotPassword(params.body);
16+
}
17+
}
18+
19+
class ParamsForgotPassword extends Equatable {
20+
final ForgotPasswordBody body;
21+
22+
ParamsForgotPassword({required this.body});
23+
24+
@override
25+
List<Object?> get props => [
26+
body,
27+
];
28+
29+
@override
30+
String toString() {
31+
return 'ParamsForgotPassword{body: $body}';
32+
}
33+
}

0 commit comments

Comments
 (0)