feat:login page connected with backend
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
abstract class ApiConst {
|
abstract class ApiConst {
|
||||||
static const String baseUrl = "https://superapp.felixits.uz/api/v1";
|
static const String baseUrl = "https://superapp.felixits.uz/api/v1";
|
||||||
|
|
||||||
|
static const String login = "/auth/login";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import 'package:dio/dio.dart' as _i361;
|
|||||||
import 'package:get_it/get_it.dart' as _i174;
|
import 'package:get_it/get_it.dart' as _i174;
|
||||||
import 'package:injectable/injectable.dart' as _i526;
|
import 'package:injectable/injectable.dart' as _i526;
|
||||||
|
|
||||||
|
import '../../feature/auth/data/datasource/auth_datasource.dart' as _i246;
|
||||||
|
import '../../feature/auth/domain/repository/auth_repository.dart' as _i884;
|
||||||
|
import '../../feature/auth/domain/usecases/login_usecase.dart' as _i241;
|
||||||
import '../../feature/auth/presentation/blocs/login_bloc/login_bloc.dart'
|
import '../../feature/auth/presentation/blocs/login_bloc/login_bloc.dart'
|
||||||
as _i1065;
|
as _i1065;
|
||||||
import '../../feature/basket/presentation/blocs/basket_bloc.dart' as _i728;
|
import '../../feature/basket/presentation/blocs/basket_bloc.dart' as _i728;
|
||||||
@@ -42,7 +45,6 @@ extension GetItInjectableX on _i174.GetIt {
|
|||||||
final dioModule = _$DioModule();
|
final dioModule = _$DioModule();
|
||||||
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
|
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
|
||||||
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
|
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
|
||||||
gh.factory<_i1065.LoginBloc>(() => _i1065.LoginBloc());
|
|
||||||
gh.factory<_i991.BrowseBloc>(() => _i991.BrowseBloc());
|
gh.factory<_i991.BrowseBloc>(() => _i991.BrowseBloc());
|
||||||
gh.factory<_i580.MainBloc>(() => _i580.MainBloc());
|
gh.factory<_i580.MainBloc>(() => _i580.MainBloc());
|
||||||
gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc());
|
gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc());
|
||||||
@@ -56,6 +58,21 @@ extension GetItInjectableX on _i174.GetIt {
|
|||||||
gh.singleton<_i354.RequestHandlerService>(
|
gh.singleton<_i354.RequestHandlerService>(
|
||||||
() => _i354.RequestHandlerService(gh<_i361.Dio>()),
|
() => _i354.RequestHandlerService(gh<_i361.Dio>()),
|
||||||
);
|
);
|
||||||
|
gh.lazySingleton<_i246.AuthDatasource>(
|
||||||
|
() => _i246.AuthDatasourceImpl(gh<_i354.RequestHandlerService>()),
|
||||||
|
);
|
||||||
|
gh.lazySingleton<_i884.AuthRepository>(
|
||||||
|
() => _i884.AuthRepositoryImpl(
|
||||||
|
gh<_i354.RequestHandlerService>(),
|
||||||
|
gh<_i246.AuthDatasource>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
gh.factory<_i241.LoginUseCase>(
|
||||||
|
() => _i241.LoginUseCase(gh<_i884.AuthRepository>()),
|
||||||
|
);
|
||||||
|
gh.factory<_i1065.LoginBloc>(
|
||||||
|
() => _i1065.LoginBloc(gh<_i241.LoginUseCase>()),
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ class DioClient {
|
|||||||
responseBody: true,
|
responseBody: true,
|
||||||
error: true,
|
error: true,
|
||||||
request: true,
|
request: true,
|
||||||
logPrint: (object) {
|
|
||||||
if (kDebugMode) {
|
|
||||||
log('Error ${object.toString()}');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return dio;
|
return dio;
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import 'package:food_delivery_client/core/services/request_handler_service.dart';
|
||||||
|
import 'package:food_delivery_client/feature/auth/data/models/response/login_response.dart';
|
||||||
|
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||||
|
|
||||||
|
abstract class AuthDatasource {
|
||||||
|
Future<LoginResponseModel> login({
|
||||||
|
required String phoneNumber,
|
||||||
|
required String password,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@LazySingleton(as: AuthDatasource)
|
||||||
|
class AuthDatasourceImpl implements AuthDatasource {
|
||||||
|
final RequestHandlerService _requestHandlerService;
|
||||||
|
|
||||||
|
AuthDatasourceImpl(this._requestHandlerService);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoginResponseModel> login({
|
||||||
|
required String phoneNumber,
|
||||||
|
required String password,
|
||||||
|
}) async {
|
||||||
|
return _requestHandlerService.handleRequest(
|
||||||
|
path: ApiConst.login,
|
||||||
|
method: RequestMethodEnum.post,
|
||||||
|
data: {"password": password, "phoneNumber": phoneNumber},
|
||||||
|
fromJson: (response) async => LoginResponseModel.fromJson(response.data),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
26
lib/feature/auth/data/models/response/login_response.dart
Normal file
26
lib/feature/auth/data/models/response/login_response.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
class LoginResponseModel extends Equatable {
|
||||||
|
final String token;
|
||||||
|
|
||||||
|
const LoginResponseModel({required this.token});
|
||||||
|
|
||||||
|
factory LoginResponseModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return LoginResponseModel(
|
||||||
|
token: json['token'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'token': token,
|
||||||
|
};
|
||||||
|
|
||||||
|
LoginResponseModel copyWith({String? token}) {
|
||||||
|
return LoginResponseModel(
|
||||||
|
token: token ?? this.token,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [token];
|
||||||
|
}
|
||||||
35
lib/feature/auth/domain/repository/auth_repository.dart
Normal file
35
lib/feature/auth/domain/repository/auth_repository.dart
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:food_delivery_client/core/services/request_handler_service.dart';
|
||||||
|
import 'package:food_delivery_client/feature/auth/data/datasource/auth_datasource.dart';
|
||||||
|
import 'package:food_delivery_client/feature/auth/data/models/response/login_response.dart';
|
||||||
|
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||||
|
|
||||||
|
abstract class AuthRepository {
|
||||||
|
Future<Either<Failure, LoginResponseModel>> login({
|
||||||
|
required String phoneNumber,
|
||||||
|
required String password,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@LazySingleton(as: AuthRepository)
|
||||||
|
class AuthRepositoryImpl implements AuthRepository {
|
||||||
|
final RequestHandlerService _requestHandlerService;
|
||||||
|
final AuthDatasource _authDatasource;
|
||||||
|
|
||||||
|
AuthRepositoryImpl(this._requestHandlerService, this._authDatasource);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<Failure, LoginResponseModel>> login({
|
||||||
|
required String phoneNumber,
|
||||||
|
required String password,
|
||||||
|
}) async {
|
||||||
|
return _requestHandlerService.handleRequestInRepository(
|
||||||
|
onRequest: () async {
|
||||||
|
return _authDatasource.login(
|
||||||
|
phoneNumber: phoneNumber,
|
||||||
|
password: password,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
lib/feature/auth/domain/usecases/login_usecase.dart
Normal file
26
lib/feature/auth/domain/usecases/login_usecase.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:food_delivery_client/core/usecase/usecase.dart';
|
||||||
|
import 'package:food_delivery_client/feature/auth/data/models/response/login_response.dart';
|
||||||
|
import 'package:food_delivery_client/feature/auth/domain/repository/auth_repository.dart';
|
||||||
|
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||||
|
@injectable
|
||||||
|
class LoginUseCase implements UseCase<LoginResponseModel, LoginParams> {
|
||||||
|
final AuthRepository _authRepository;
|
||||||
|
|
||||||
|
LoginUseCase(this._authRepository);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Either<Failure, LoginResponseModel>> call(LoginParams params) async {
|
||||||
|
return _authRepository.login(
|
||||||
|
phoneNumber: params.phoneNumber,
|
||||||
|
password: params.password,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoginParams {
|
||||||
|
final String phoneNumber;
|
||||||
|
final String password;
|
||||||
|
|
||||||
|
LoginParams({required this.phoneNumber, required this.password});
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:food_delivery_client/feature/auth/domain/usecases/login_usecase.dart';
|
||||||
import 'package:food_delivery_client/food_delivery_client.dart';
|
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||||
|
|
||||||
part 'login_event.dart';
|
part 'login_event.dart';
|
||||||
@@ -8,11 +9,26 @@ part 'login_bloc.freezed.dart';
|
|||||||
|
|
||||||
@injectable
|
@injectable
|
||||||
class LoginBloc extends Bloc<LoginEvent, LoginState> {
|
class LoginBloc extends Bloc<LoginEvent, LoginState> {
|
||||||
LoginBloc() : super(const LoginState()) {
|
final LoginUseCase _loginUseCase;
|
||||||
|
|
||||||
|
LoginBloc(this._loginUseCase) : super(const LoginState()) {
|
||||||
on<_Login>(_onLogin);
|
on<_Login>(_onLogin);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onLogin(_Login event, Emitter<LoginState> emit) async {
|
Future<void> _onLogin(_Login event, Emitter<LoginState> emit) async {
|
||||||
emit(state.copyWith(status: RequestStatus.loading));
|
emit(state.copyWith(status: RequestStatus.loading));
|
||||||
|
|
||||||
|
final response = await _loginUseCase.call(event.params);
|
||||||
|
|
||||||
|
response.fold(
|
||||||
|
(l) {
|
||||||
|
log("${l.errorMessage}");
|
||||||
|
emit(state.copyWith(status: RequestStatus.error));
|
||||||
|
},
|
||||||
|
(r) {
|
||||||
|
log(r.token);
|
||||||
|
emit(state.copyWith(status: RequestStatus.loaded));
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,11 +122,11 @@ return login(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? checked,TResult Function()? login,required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? checked,TResult Function( LoginParams params)? login,required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _Checked() when checked != null:
|
case _Checked() when checked != null:
|
||||||
return checked();case _Login() when login != null:
|
return checked();case _Login() when login != null:
|
||||||
return login();case _:
|
return login(_that.params);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -144,11 +144,11 @@ return login();case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() checked,required TResult Function() login,}) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() checked,required TResult Function( LoginParams params) login,}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _Checked():
|
case _Checked():
|
||||||
return checked();case _Login():
|
return checked();case _Login():
|
||||||
return login();case _:
|
return login(_that.params);case _:
|
||||||
throw StateError('Unexpected subclass');
|
throw StateError('Unexpected subclass');
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -165,11 +165,11 @@ return login();case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? checked,TResult? Function()? login,}) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? checked,TResult? Function( LoginParams params)? login,}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _Checked() when checked != null:
|
case _Checked() when checked != null:
|
||||||
return checked();case _Login() when login != null:
|
return checked();case _Login() when login != null:
|
||||||
return login();case _:
|
return login(_that.params);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -213,34 +213,68 @@ String toString() {
|
|||||||
|
|
||||||
|
|
||||||
class _Login implements LoginEvent {
|
class _Login implements LoginEvent {
|
||||||
const _Login();
|
const _Login(this.params);
|
||||||
|
|
||||||
|
|
||||||
|
final LoginParams params;
|
||||||
|
|
||||||
|
/// Create a copy of LoginEvent
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$LoginCopyWith<_Login> get copyWith => __$LoginCopyWithImpl<_Login>(this, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Login);
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Login&&(identical(other.params, params) || other.params == params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => runtimeType.hashCode;
|
int get hashCode => Object.hash(runtimeType,params);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LoginEvent.login()';
|
return 'LoginEvent.login(params: $params)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$LoginCopyWith<$Res> implements $LoginEventCopyWith<$Res> {
|
||||||
|
factory _$LoginCopyWith(_Login value, $Res Function(_Login) _then) = __$LoginCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
LoginParams params
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$LoginCopyWithImpl<$Res>
|
||||||
|
implements _$LoginCopyWith<$Res> {
|
||||||
|
__$LoginCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _Login _self;
|
||||||
|
final $Res Function(_Login) _then;
|
||||||
|
|
||||||
|
/// Create a copy of LoginEvent
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') $Res call({Object? params = null,}) {
|
||||||
|
return _then(_Login(
|
||||||
|
null == params ? _self.params : params // ignore: cast_nullable_to_non_nullable
|
||||||
|
as LoginParams,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$LoginState {
|
mixin _$LoginState {
|
||||||
|
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ part of 'login_bloc.dart';
|
|||||||
class LoginEvent with _$LoginEvent {
|
class LoginEvent with _$LoginEvent {
|
||||||
const factory LoginEvent.checked() = _Checked;
|
const factory LoginEvent.checked() = _Checked;
|
||||||
|
|
||||||
const factory LoginEvent.login() = _Login;
|
const factory LoginEvent.login(LoginParams params) = _Login;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:food_delivery_client/core/helpers/formatters.dart';
|
import 'package:food_delivery_client/core/helpers/formatters.dart';
|
||||||
|
import 'package:food_delivery_client/feature/auth/domain/usecases/login_usecase.dart';
|
||||||
|
|
||||||
import '../../../../../../food_delivery_client.dart';
|
import '../../../../../../food_delivery_client.dart';
|
||||||
import '../../../blocs/login_bloc/login_bloc.dart';
|
import '../../../blocs/login_bloc/login_bloc.dart';
|
||||||
@@ -14,7 +15,7 @@ class WLoginBody extends StatefulWidget {
|
|||||||
class _WLoginBodyState extends State<WLoginBody> {
|
class _WLoginBodyState extends State<WLoginBody> {
|
||||||
late final TextEditingController _phoneController;
|
late final TextEditingController _phoneController;
|
||||||
late final TextEditingController _passwordController;
|
late final TextEditingController _passwordController;
|
||||||
final GlobalKey _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -98,7 +99,19 @@ class _WLoginBodyState extends State<WLoginBody> {
|
|||||||
AppButton(
|
AppButton(
|
||||||
name: "Continue",
|
name: "Continue",
|
||||||
isLoading: state.status.isLoading(),
|
isLoading: state.status.isLoading(),
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
if (_formKey.currentState?.validate() ?? false) {
|
||||||
|
context.read<LoginBloc>().add(
|
||||||
|
LoginEvent.login(
|
||||||
|
LoginParams(
|
||||||
|
phoneNumber:
|
||||||
|
"+998${_phoneController.text.trim().replaceAll(" ", "")}",
|
||||||
|
password: _passwordController.text.trim(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
borderRadius: 15,
|
borderRadius: 15,
|
||||||
backgroundColor: AppColors.c34A853,
|
backgroundColor: AppColors.c34A853,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ class ErrorModel extends ErrorEntity {
|
|||||||
return ErrorModel(detail: data['detail']);
|
return ErrorModel(detail: data['detail']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ErrorModel(detail: data['message']);
|
return ErrorModel(detail: data['error']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user