diff --git a/lib/core/routes/app_routes.dart b/lib/core/routes/app_routes.dart index 69d63be..778407b 100644 --- a/lib/core/routes/app_routes.dart +++ b/lib/core/routes/app_routes.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:tm_app/views/completion_of_documents/pages/m_completion_of_documents_page.dart'; import 'package:tm_app/views/detail/pages/detail_screen.dart'; +import 'package:tm_app/views/forget_password_otp.dart/pages/forgot_password_otp_screen.dart'; import 'package:tm_app/views/home/pages/home_screen.dart'; import 'package:tm_app/views/liked_tenders/pages/liked_tenders_screen.dart'; import 'package:tm_app/views/login/pages/login_screen.dart'; @@ -231,3 +232,14 @@ class ForgotPasswordRouteData extends GoRouteData return const ForgotPasswordScreen(); } } + +@TypedGoRoute(path: '/forgot-password-otp') +class ForgotPasswordOtpRouteData extends GoRouteData + with _$ForgotPasswordOtpRouteData { + const ForgotPasswordOtpRouteData(); + + @override + Widget build(BuildContext context, GoRouterState state) { + return const ForgotPasswordOtpScreen(); + } +} diff --git a/lib/core/routes/app_routes.g.dart b/lib/core/routes/app_routes.g.dart index 8511a54..96e3482 100644 --- a/lib/core/routes/app_routes.g.dart +++ b/lib/core/routes/app_routes.g.dart @@ -15,6 +15,7 @@ List get $appRoutes => [ $completionOfDocumentsMobileRouteData, $tenderDetailRouteData, $forgotPasswordRouteData, + $forgotPasswordOtpRouteData, ]; RouteBase get $loginScreenRoute => @@ -343,3 +344,30 @@ mixin _$ForgotPasswordRouteData on GoRouteData { @override void replace(BuildContext context) => context.replace(location); } + +RouteBase get $forgotPasswordOtpRouteData => GoRouteData.$route( + path: '/forgot-password-otp', + + factory: _$ForgotPasswordOtpRouteData._fromState, +); + +mixin _$ForgotPasswordOtpRouteData on GoRouteData { + static ForgotPasswordOtpRouteData _fromState(GoRouterState state) => + const ForgotPasswordOtpRouteData(); + + @override + String get location => GoRouteData.$location('/forgot-password-otp'); + + @override + void go(BuildContext context) => context.go(location); + + @override + Future push(BuildContext context) => context.push(location); + + @override + void pushReplacement(BuildContext context) => + context.pushReplacement(location); + + @override + void replace(BuildContext context) => context.replace(location); +} diff --git a/lib/data/repositories/auth_repository.dart b/lib/data/repositories/auth_repository.dart index 2a36e11..ff0d644 100644 --- a/lib/data/repositories/auth_repository.dart +++ b/lib/data/repositories/auth_repository.dart @@ -1,5 +1,6 @@ import 'package:tm_app/data/services/model/forgot_password_response/forgot_password_response_model.dart'; import 'package:tm_app/data/services/model/login_response/login_response_model.dart'; +import 'package:tm_app/data/services/model/verify_otp_response/verify_otp_response_model.dart'; import '../../core/utils/result.dart'; import '../services/auth_service.dart'; @@ -31,4 +32,11 @@ class AuthRepository { }) async { return _authService.forgotPassword(email: email); } + + Future> verifyOtp({ + required String code, + required String email, + }) async { + return _authService.verifyOtp(code: code, email: email); + } } diff --git a/lib/data/services/auth_service.dart b/lib/data/services/auth_service.dart index 76e705d..87ca9a5 100644 --- a/lib/data/services/auth_service.dart +++ b/lib/data/services/auth_service.dart @@ -8,6 +8,7 @@ import 'package:tm_app/data/services/api/auth_api.dart'; import 'package:tm_app/data/services/model/forgot_password_response/forgot_password_response_model.dart'; import 'package:tm_app/data/services/model/login_response/login_response_model.dart'; import 'package:tm_app/data/services/model/logout_response/logout_response.dart'; +import 'package:tm_app/data/services/model/verify_otp_response/verify_otp_response_model.dart'; import '../../core/network/network_manager.dart'; import '../../core/utils/result.dart'; @@ -72,4 +73,21 @@ class AuthService { return result; } + + Future> verifyOtp({ + required String code, + required String email, +}) async { + final data = jsonEncode({"code": code, "email": email}); + + final result = await _networkManager.makeRequest( + "/api/v1/profile/verify-otp", + method: 'POST', + (json) => VerifyOtpResponseModel.fromJson(json), + data: data, + ); + + return result; +} + } diff --git a/lib/data/services/model/verify_otp_data/verify_otp_data.dart b/lib/data/services/model/verify_otp_data/verify_otp_data.dart new file mode 100644 index 0000000..e9a09e2 --- /dev/null +++ b/lib/data/services/model/verify_otp_data/verify_otp_data.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'verify_otp_data.freezed.dart'; +part 'verify_otp_data.g.dart'; + +@freezed +abstract class VerifyOtpData with _$VerifyOtpData { + const factory VerifyOtpData({ + required String message, + required bool success, + required String token, + }) = _VerifyOtpData; + + factory VerifyOtpData.fromJson(Map json) => + _$VerifyOtpDataFromJson(json); +} diff --git a/lib/data/services/model/verify_otp_data/verify_otp_data.freezed.dart b/lib/data/services/model/verify_otp_data/verify_otp_data.freezed.dart new file mode 100644 index 0000000..448fde5 --- /dev/null +++ b/lib/data/services/model/verify_otp_data/verify_otp_data.freezed.dart @@ -0,0 +1,283 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'verify_otp_data.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$VerifyOtpData { + + String get message; bool get success; String get token; +/// Create a copy of VerifyOtpData +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$VerifyOtpDataCopyWith get copyWith => _$VerifyOtpDataCopyWithImpl(this as VerifyOtpData, _$identity); + + /// Serializes this VerifyOtpData to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is VerifyOtpData&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success)&&(identical(other.token, token) || other.token == token)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,message,success,token); + +@override +String toString() { + return 'VerifyOtpData(message: $message, success: $success, token: $token)'; +} + + +} + +/// @nodoc +abstract mixin class $VerifyOtpDataCopyWith<$Res> { + factory $VerifyOtpDataCopyWith(VerifyOtpData value, $Res Function(VerifyOtpData) _then) = _$VerifyOtpDataCopyWithImpl; +@useResult +$Res call({ + String message, bool success, String token +}); + + + + +} +/// @nodoc +class _$VerifyOtpDataCopyWithImpl<$Res> + implements $VerifyOtpDataCopyWith<$Res> { + _$VerifyOtpDataCopyWithImpl(this._self, this._then); + + final VerifyOtpData _self; + final $Res Function(VerifyOtpData) _then; + +/// Create a copy of VerifyOtpData +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? message = null,Object? success = null,Object? token = null,}) { + return _then(_self.copyWith( +message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String,success: null == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as bool,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [VerifyOtpData]. +extension VerifyOtpDataPatterns on VerifyOtpData { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _VerifyOtpData value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _VerifyOtpData() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _VerifyOtpData value) $default,){ +final _that = this; +switch (_that) { +case _VerifyOtpData(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _VerifyOtpData value)? $default,){ +final _that = this; +switch (_that) { +case _VerifyOtpData() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String message, bool success, String token)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _VerifyOtpData() when $default != null: +return $default(_that.message,_that.success,_that.token);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String message, bool success, String token) $default,) {final _that = this; +switch (_that) { +case _VerifyOtpData(): +return $default(_that.message,_that.success,_that.token);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String message, bool success, String token)? $default,) {final _that = this; +switch (_that) { +case _VerifyOtpData() when $default != null: +return $default(_that.message,_that.success,_that.token);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _VerifyOtpData implements VerifyOtpData { + const _VerifyOtpData({required this.message, required this.success, required this.token}); + factory _VerifyOtpData.fromJson(Map json) => _$VerifyOtpDataFromJson(json); + +@override final String message; +@override final bool success; +@override final String token; + +/// Create a copy of VerifyOtpData +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$VerifyOtpDataCopyWith<_VerifyOtpData> get copyWith => __$VerifyOtpDataCopyWithImpl<_VerifyOtpData>(this, _$identity); + +@override +Map toJson() { + return _$VerifyOtpDataToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _VerifyOtpData&&(identical(other.message, message) || other.message == message)&&(identical(other.success, success) || other.success == success)&&(identical(other.token, token) || other.token == token)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,message,success,token); + +@override +String toString() { + return 'VerifyOtpData(message: $message, success: $success, token: $token)'; +} + + +} + +/// @nodoc +abstract mixin class _$VerifyOtpDataCopyWith<$Res> implements $VerifyOtpDataCopyWith<$Res> { + factory _$VerifyOtpDataCopyWith(_VerifyOtpData value, $Res Function(_VerifyOtpData) _then) = __$VerifyOtpDataCopyWithImpl; +@override @useResult +$Res call({ + String message, bool success, String token +}); + + + + +} +/// @nodoc +class __$VerifyOtpDataCopyWithImpl<$Res> + implements _$VerifyOtpDataCopyWith<$Res> { + __$VerifyOtpDataCopyWithImpl(this._self, this._then); + + final _VerifyOtpData _self; + final $Res Function(_VerifyOtpData) _then; + +/// Create a copy of VerifyOtpData +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? message = null,Object? success = null,Object? token = null,}) { + return _then(_VerifyOtpData( +message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String,success: null == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as bool,token: null == token ? _self.token : token // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + +// dart format on diff --git a/lib/data/services/model/verify_otp_data/verify_otp_data.g.dart b/lib/data/services/model/verify_otp_data/verify_otp_data.g.dart new file mode 100644 index 0000000..7d5dd89 --- /dev/null +++ b/lib/data/services/model/verify_otp_data/verify_otp_data.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'verify_otp_data.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_VerifyOtpData _$VerifyOtpDataFromJson(Map json) => + _VerifyOtpData( + message: json['message'] as String, + success: json['success'] as bool, + token: json['token'] as String, + ); + +Map _$VerifyOtpDataToJson(_VerifyOtpData instance) => + { + 'message': instance.message, + 'success': instance.success, + 'token': instance.token, + }; diff --git a/lib/data/services/model/verify_otp_response/verify_otp_response_model.dart b/lib/data/services/model/verify_otp_response/verify_otp_response_model.dart new file mode 100644 index 0000000..9b29835 --- /dev/null +++ b/lib/data/services/model/verify_otp_response/verify_otp_response_model.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:tm_app/data/services/model/verify_otp_data/verify_otp_data.dart'; + +part 'verify_otp_response_model.freezed.dart'; +part 'verify_otp_response_model.g.dart'; + +@freezed +abstract class VerifyOtpResponseModel with _$VerifyOtpResponseModel { + const factory VerifyOtpResponseModel({ + required bool success, + required String message, + required VerifyOtpData data, + }) = _VerifyOtpResponseModel; + + factory VerifyOtpResponseModel.fromJson(Map json) => + _$VerifyOtpResponseModelFromJson(json); +} + diff --git a/lib/data/services/model/verify_otp_response/verify_otp_response_model.freezed.dart b/lib/data/services/model/verify_otp_response/verify_otp_response_model.freezed.dart new file mode 100644 index 0000000..a03c377 --- /dev/null +++ b/lib/data/services/model/verify_otp_response/verify_otp_response_model.freezed.dart @@ -0,0 +1,301 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'verify_otp_response_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$VerifyOtpResponseModel { + + bool get success; String get message; VerifyOtpData get data; +/// Create a copy of VerifyOtpResponseModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$VerifyOtpResponseModelCopyWith get copyWith => _$VerifyOtpResponseModelCopyWithImpl(this as VerifyOtpResponseModel, _$identity); + + /// Serializes this VerifyOtpResponseModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is VerifyOtpResponseModel&&(identical(other.success, success) || other.success == success)&&(identical(other.message, message) || other.message == message)&&(identical(other.data, data) || other.data == data)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,success,message,data); + +@override +String toString() { + return 'VerifyOtpResponseModel(success: $success, message: $message, data: $data)'; +} + + +} + +/// @nodoc +abstract mixin class $VerifyOtpResponseModelCopyWith<$Res> { + factory $VerifyOtpResponseModelCopyWith(VerifyOtpResponseModel value, $Res Function(VerifyOtpResponseModel) _then) = _$VerifyOtpResponseModelCopyWithImpl; +@useResult +$Res call({ + bool success, String message, VerifyOtpData data +}); + + +$VerifyOtpDataCopyWith<$Res> get data; + +} +/// @nodoc +class _$VerifyOtpResponseModelCopyWithImpl<$Res> + implements $VerifyOtpResponseModelCopyWith<$Res> { + _$VerifyOtpResponseModelCopyWithImpl(this._self, this._then); + + final VerifyOtpResponseModel _self; + final $Res Function(VerifyOtpResponseModel) _then; + +/// Create a copy of VerifyOtpResponseModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? success = null,Object? message = null,Object? data = null,}) { + return _then(_self.copyWith( +success: null == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as bool,message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String,data: null == data ? _self.data : data // ignore: cast_nullable_to_non_nullable +as VerifyOtpData, + )); +} +/// Create a copy of VerifyOtpResponseModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$VerifyOtpDataCopyWith<$Res> get data { + + return $VerifyOtpDataCopyWith<$Res>(_self.data, (value) { + return _then(_self.copyWith(data: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [VerifyOtpResponseModel]. +extension VerifyOtpResponseModelPatterns on VerifyOtpResponseModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _VerifyOtpResponseModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _VerifyOtpResponseModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _VerifyOtpResponseModel value) $default,){ +final _that = this; +switch (_that) { +case _VerifyOtpResponseModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _VerifyOtpResponseModel value)? $default,){ +final _that = this; +switch (_that) { +case _VerifyOtpResponseModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( bool success, String message, VerifyOtpData data)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _VerifyOtpResponseModel() when $default != null: +return $default(_that.success,_that.message,_that.data);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( bool success, String message, VerifyOtpData data) $default,) {final _that = this; +switch (_that) { +case _VerifyOtpResponseModel(): +return $default(_that.success,_that.message,_that.data);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( bool success, String message, VerifyOtpData data)? $default,) {final _that = this; +switch (_that) { +case _VerifyOtpResponseModel() when $default != null: +return $default(_that.success,_that.message,_that.data);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _VerifyOtpResponseModel implements VerifyOtpResponseModel { + const _VerifyOtpResponseModel({required this.success, required this.message, required this.data}); + factory _VerifyOtpResponseModel.fromJson(Map json) => _$VerifyOtpResponseModelFromJson(json); + +@override final bool success; +@override final String message; +@override final VerifyOtpData data; + +/// Create a copy of VerifyOtpResponseModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$VerifyOtpResponseModelCopyWith<_VerifyOtpResponseModel> get copyWith => __$VerifyOtpResponseModelCopyWithImpl<_VerifyOtpResponseModel>(this, _$identity); + +@override +Map toJson() { + return _$VerifyOtpResponseModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _VerifyOtpResponseModel&&(identical(other.success, success) || other.success == success)&&(identical(other.message, message) || other.message == message)&&(identical(other.data, data) || other.data == data)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,success,message,data); + +@override +String toString() { + return 'VerifyOtpResponseModel(success: $success, message: $message, data: $data)'; +} + + +} + +/// @nodoc +abstract mixin class _$VerifyOtpResponseModelCopyWith<$Res> implements $VerifyOtpResponseModelCopyWith<$Res> { + factory _$VerifyOtpResponseModelCopyWith(_VerifyOtpResponseModel value, $Res Function(_VerifyOtpResponseModel) _then) = __$VerifyOtpResponseModelCopyWithImpl; +@override @useResult +$Res call({ + bool success, String message, VerifyOtpData data +}); + + +@override $VerifyOtpDataCopyWith<$Res> get data; + +} +/// @nodoc +class __$VerifyOtpResponseModelCopyWithImpl<$Res> + implements _$VerifyOtpResponseModelCopyWith<$Res> { + __$VerifyOtpResponseModelCopyWithImpl(this._self, this._then); + + final _VerifyOtpResponseModel _self; + final $Res Function(_VerifyOtpResponseModel) _then; + +/// Create a copy of VerifyOtpResponseModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? success = null,Object? message = null,Object? data = null,}) { + return _then(_VerifyOtpResponseModel( +success: null == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as bool,message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String,data: null == data ? _self.data : data // ignore: cast_nullable_to_non_nullable +as VerifyOtpData, + )); +} + +/// Create a copy of VerifyOtpResponseModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$VerifyOtpDataCopyWith<$Res> get data { + + return $VerifyOtpDataCopyWith<$Res>(_self.data, (value) { + return _then(_self.copyWith(data: value)); + }); +} +} + +// dart format on diff --git a/lib/data/services/model/verify_otp_response/verify_otp_response_model.g.dart b/lib/data/services/model/verify_otp_response/verify_otp_response_model.g.dart new file mode 100644 index 0000000..1de8a53 --- /dev/null +++ b/lib/data/services/model/verify_otp_response/verify_otp_response_model.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'verify_otp_response_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_VerifyOtpResponseModel _$VerifyOtpResponseModelFromJson( + Map json, +) => _VerifyOtpResponseModel( + success: json['success'] as bool, + message: json['message'] as String, + data: VerifyOtpData.fromJson(json['data'] as Map), +); + +Map _$VerifyOtpResponseModelToJson( + _VerifyOtpResponseModel instance, +) => { + 'success': instance.success, + 'message': instance.message, + 'data': instance.data, +}; diff --git a/lib/view_models/auth_view_model.dart b/lib/view_models/auth_view_model.dart index ecc6e4f..3b49dee 100644 --- a/lib/view_models/auth_view_model.dart +++ b/lib/view_models/auth_view_model.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:tm_app/data/services/model/customer/customer.dart'; import 'package:tm_app/data/services/model/forgot_password_response/forgot_password_response_model.dart'; +import 'package:tm_app/data/services/model/verify_otp_response/verify_otp_response_model.dart'; +import 'package:tm_app/views/forget_password_create/pages/forgot_password_create_screen.dart'; import '../core/utils/result.dart'; import '../data/repositories/auth_repository.dart'; @@ -11,7 +13,7 @@ class AuthViewModel with ChangeNotifier { final AuthRepository _authRepository; AuthViewModel({required AuthRepository authRepository}) - : _authRepository = authRepository { + : _authRepository = authRepository { usernameController.addListener(_onTextChanged); passwordController.addListener(_onTextChanged); emailController.addListener(_onTextChanged); @@ -38,8 +40,7 @@ class AuthViewModel with ChangeNotifier { bool get obscureForgotPassword => _obscureForgotPassword; bool get isLoginEnabled => - usernameController.text.isNotEmpty && - passwordController.text.isNotEmpty; + usernameController.text.isNotEmpty && passwordController.text.isNotEmpty; // Auth state bool _isLoading = false; @@ -52,6 +53,7 @@ class AuthViewModel with ChangeNotifier { String? get errorMessage => _errorMessage; Customer? get loggedInUser => _loggedInUser; String? get forgotPasswordMessage => _forgotPasswordMessage; + String? resetToken; void togglePasswordVisibility() { _obscurePassword = !_obscurePassword; @@ -75,7 +77,7 @@ class AuthViewModel with ChangeNotifier { } bool get canSubmitOtpPage { - return isEmailValid && isOtpValid; + return isOtpValid; } bool get isNewPasswordValid { @@ -147,7 +149,6 @@ class AuthViewModel with ChangeNotifier { notifyListeners(); - // reset error after notify _errorMessage = null; notifyListeners(); } @@ -168,7 +169,6 @@ class AuthViewModel with ChangeNotifier { successMessage = result.value.message; notifyListeners(); - // پاک شدن بعد از یک بار مصرف Future.microtask(() { successMessage = null; }); @@ -186,6 +186,37 @@ class AuthViewModel with ChangeNotifier { } } + Future verifyOtp(BuildContext context) async { + _isLoading = true; + _errorMessage = null; + notifyListeners(); + + final result = await _authRepository.verifyOtp( + code: otpController.text.trim(), + email: emailController.text.trim(), + ); + + switch (result) { + case Ok(): + _isLoading = false; + resetToken = result.value.data.token; + + Navigator.push( + context, + MaterialPageRoute(builder: (_) => const ForgotPasswordCreateScreen()), + ); + break; + + case Error(): + _isLoading = false; + _errorMessage = result.error.toString(); + break; + } + notifyListeners(); + _errorMessage = null; + notifyListeners(); + } + @override void dispose() { usernameController.dispose(); diff --git a/lib/views/forget_password_otp.dart/pages/d_forget_password_otp.dart_page.dart b/lib/views/forget_password_otp.dart/pages/d_forget_password_otp.dart_page.dart index 1ff166c..ca5b90b 100644 --- a/lib/views/forget_password_otp.dart/pages/d_forget_password_otp.dart_page.dart +++ b/lib/views/forget_password_otp.dart/pages/d_forget_password_otp.dart_page.dart @@ -4,7 +4,6 @@ import 'package:go_router/go_router.dart'; import 'package:pinput/pinput.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/utils/size_config.dart'; -import 'package:tm_app/views/forget_password_create/pages/forgot_password_create_screen.dart'; import '../../../core/constants/assets.dart'; import '../../../core/theme/colors.dart'; @@ -88,20 +87,12 @@ class DesktopForgotPasswordOtpPage extends StatelessWidget { onPressed: null, ) : BaseButton( - isEnabled: - viewModel.canSubmitOtpPage, // 👈 شرط جدید + isEnabled: viewModel.canSubmitOtpPage, text: ForgotPasswordOtpStrings.resetLink, onPressed: viewModel.canSubmitOtpPage ? () async { - Navigator.push( - context, - MaterialPageRoute( - builder: - (context) => - const ForgotPasswordCreateScreen(), - ), - ); + await viewModel.verifyOtp(context); } : null, ), diff --git a/lib/views/forget_password_otp.dart/pages/m_forget_password_otp.dart_page.dart b/lib/views/forget_password_otp.dart/pages/m_forget_password_otp.dart_page.dart index 964a5f3..3f18524 100644 --- a/lib/views/forget_password_otp.dart/pages/m_forget_password_otp.dart_page.dart +++ b/lib/views/forget_password_otp.dart/pages/m_forget_password_otp.dart_page.dart @@ -4,7 +4,6 @@ import 'package:go_router/go_router.dart'; import 'package:pinput/pinput.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/utils/size_config.dart'; -import 'package:tm_app/views/forget_password_create/pages/forgot_password_create_screen.dart'; import '../../../core/constants/assets.dart'; import '../../../core/theme/colors.dart'; @@ -89,14 +88,7 @@ class MobileForgotPasswordOtpPage extends StatelessWidget { onPressed: viewModel.canSubmitOtpPage ? () async { - Navigator.push( - context, - MaterialPageRoute( - builder: - (context) => - const ForgotPasswordCreateScreen(), - ), - ); + await viewModel.verifyOtp(context); } : null, ), diff --git a/lib/views/forget_password_otp.dart/pages/t_forget_password_otp.dart_page.dart b/lib/views/forget_password_otp.dart/pages/t_forget_password_otp.dart_page.dart index 7e503ac..bcb183a 100644 --- a/lib/views/forget_password_otp.dart/pages/t_forget_password_otp.dart_page.dart +++ b/lib/views/forget_password_otp.dart/pages/t_forget_password_otp.dart_page.dart @@ -4,7 +4,6 @@ import 'package:go_router/go_router.dart'; import 'package:pinput/pinput.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/utils/size_config.dart'; -import 'package:tm_app/views/forget_password_create/pages/forgot_password_create_screen.dart'; import '../../../core/constants/assets.dart'; import '../../../core/theme/colors.dart'; @@ -88,20 +87,12 @@ class TabletForgotPasswordOtpPage extends StatelessWidget { onPressed: null, ) : BaseButton( - isEnabled: - viewModel.canSubmitOtpPage, // 👈 شرط جدید + isEnabled: viewModel.canSubmitOtpPage, text: ForgotPasswordOtpStrings.resetLink, onPressed: viewModel.canSubmitOtpPage ? () async { - Navigator.push( - context, - MaterialPageRoute( - builder: - (context) => - const ForgotPasswordCreateScreen(), - ), - ); + await viewModel.verifyOtp(context); } : null, ), diff --git a/lib/views/forgot_password/pages/d_forgot_apssword_page.dart b/lib/views/forgot_password/pages/d_forgot_apssword_page.dart index 0b6f2cd..cd1a46c 100644 --- a/lib/views/forgot_password/pages/d_forgot_apssword_page.dart +++ b/lib/views/forgot_password/pages/d_forgot_apssword_page.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; +import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/utils/size_config.dart'; -import 'package:tm_app/views/forget_password_otp.dart/pages/forgot_password_otp_screen.dart'; + import '../../../core/constants/assets.dart'; import '../../../core/theme/colors.dart'; import '../../../core/utils/app_toast.dart'; @@ -24,12 +25,7 @@ class DesktopForgotPasswordPage extends StatelessWidget { if (viewModel.successMessage != null) { WidgetsBinding.instance.addPostFrameCallback((_) { AppToast.success(context, viewModel.successMessage!); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const ForgotPasswordOtpScreen(), - ), - ); + const ForgotPasswordOtpRouteData().push(context); }); } else if (viewModel.errorMessage != null) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -84,19 +80,20 @@ class DesktopForgotPasswordPage extends StatelessWidget { SizedBox(height: 70.0.h()), viewModel.isLoading ? const BaseButton( - isEnabled: false, - text: ForgotPasswordStrings.resetLink, - onPressed: null, - ) + isEnabled: false, + text: ForgotPasswordStrings.resetLink, + onPressed: null, + ) : BaseButton( - isEnabled: viewModel.isEmailValid, - text: ForgotPasswordStrings.resetLink, - onPressed: viewModel.isEmailValid - ? () async { + isEnabled: viewModel.isEmailValid, + text: ForgotPasswordStrings.resetLink, + onPressed: + viewModel.isEmailValid + ? () async { await viewModel.forgotPassword(context); } - : null, - ), + : null, + ), const SizedBox(height: 12), TextButton( onPressed: () { diff --git a/lib/views/forgot_password/pages/m_forgot_password_page.dart b/lib/views/forgot_password/pages/m_forgot_password_page.dart index c1f4fdb..65498f7 100644 --- a/lib/views/forgot_password/pages/m_forgot_password_page.dart +++ b/lib/views/forgot_password/pages/m_forgot_password_page.dart @@ -2,11 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/constants/assets.dart'; +import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/app_toast.dart'; import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/view_models/auth_view_model.dart'; -import 'package:tm_app/views/forget_password_otp.dart/pages/forgot_password_otp_screen.dart'; import '../../login/widgets/login_textfield.dart'; import '../../shared/base_button.dart'; @@ -24,15 +24,10 @@ class MobileForgotPasswordPage extends StatelessWidget { padding: EdgeInsets.symmetric(horizontal: 24.0.w()), child: Consumer( builder: (context, viewModel, _) { - if (viewModel.successMessage == null) { + if (viewModel.successMessage != null) { WidgetsBinding.instance.addPostFrameCallback((_) { AppToast.success(context, viewModel.successMessage!); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const ForgotPasswordOtpScreen(), - ), - ); + const ForgotPasswordOtpRouteData().push(context); }); } else if (viewModel.errorMessage != null) { WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/lib/views/forgot_password/pages/t_forgot_password_page.dart b/lib/views/forgot_password/pages/t_forgot_password_page.dart index 94f2ee4..24a29dd 100644 --- a/lib/views/forgot_password/pages/t_forgot_password_page.dart +++ b/lib/views/forgot_password/pages/t_forgot_password_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; +import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/utils/size_config.dart'; -import 'package:tm_app/views/forget_password_otp.dart/pages/forgot_password_otp_screen.dart'; import '../../../core/constants/assets.dart'; import '../../../core/theme/colors.dart'; @@ -23,12 +23,7 @@ class TabletForgotPasswordPage extends StatelessWidget { if (viewModel.successMessage != null) { WidgetsBinding.instance.addPostFrameCallback((_) { AppToast.success(context, viewModel.successMessage!); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const ForgotPasswordOtpScreen(), - ), - ); + const ForgotPasswordOtpRouteData().push(context); }); } else if (viewModel.errorMessage != null) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -79,19 +74,20 @@ class TabletForgotPasswordPage extends StatelessWidget { SizedBox(height: 24.0.h()), viewModel.isLoading ? const BaseButton( - isEnabled: false, - text: ForgotPasswordStrings.resetLink, - onPressed: null, - ) + isEnabled: false, + text: ForgotPasswordStrings.resetLink, + onPressed: null, + ) : BaseButton( - isEnabled: viewModel.isEmailValid, - text: ForgotPasswordStrings.resetLink, - onPressed: viewModel.isEmailValid - ? () async { + isEnabled: viewModel.isEmailValid, + text: ForgotPasswordStrings.resetLink, + onPressed: + viewModel.isEmailValid + ? () async { await viewModel.forgotPassword(context); } - : null, - ), + : null, + ), const SizedBox(height: 12), TextButton( onPressed: () {