Xử lý login
This commit is contained in:
parent
9c67d123c8
commit
5d86cfa542
@ -1,5 +1,10 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:baseproject/core/common/index.dart';
|
||||
import 'package:baseproject/core/constants/index.dart';
|
||||
import 'package:baseproject/features/presentation/app/view/app.dart';
|
||||
import 'package:baseproject/features/route/route_goto.dart';
|
||||
import 'package:baseproject/features/usecases/index.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
@ -8,8 +13,8 @@ class CustomInterceptor extends InterceptorsWrapper {
|
||||
@override
|
||||
// ignore: avoid_void_async
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
|
||||
// final String token = LocalStoreManager.getString(UserSettings.tokenUser);
|
||||
// if (token.isNotEmpty) options.headers["Authorization"] = "Bearer $token";
|
||||
final String token = LocalStoreManager.getString(StorageKey.tokenUser);
|
||||
if (token.isNotEmpty) options.headers["Authorization"] = "Bearer $token";
|
||||
|
||||
final String method = options.method.toLowerCase();
|
||||
if (method == 'get' || method == 'put') {
|
||||
@ -44,35 +49,42 @@ class CustomInterceptor extends InterceptorsWrapper {
|
||||
|
||||
@override
|
||||
onError(DioError err, ErrorInterceptorHandler handler) async {
|
||||
if (retryCount >= 3) {
|
||||
return;
|
||||
}
|
||||
if (err.response?.statusCode == 403 || err.response?.statusCode == 401) {
|
||||
retryCount++;
|
||||
final Dio dio = GetIt.I();
|
||||
dio.lock();
|
||||
dio.interceptors.requestLock.lock();
|
||||
dio.interceptors.responseLock.lock();
|
||||
if (retryCount < 3) {
|
||||
await Future.delayed(Duration(milliseconds: retryCount * 500));
|
||||
if ((err.response?.statusCode == 403 || err.response?.statusCode == 401)) {
|
||||
retryCount++;
|
||||
final Dio dio = GetIt.I();
|
||||
final RequestOptions options = err.requestOptions;
|
||||
dio.lock();
|
||||
dio.interceptors.requestLock.lock();
|
||||
dio.interceptors.responseLock.lock();
|
||||
|
||||
//Refresh token
|
||||
// final CoreUserRepository sessionRepository = GetIt.I();
|
||||
// final Token? token = await sessionRepository.refreshToken(
|
||||
// clientId: UserSettings.oidcClientId, refreshToken: LocalStoreManager.getString(UserSettings.refreshToken));
|
||||
// if (token == null) {
|
||||
// // final AuthenticateApp authenticateApp = GetIt.I();
|
||||
// // await authenticateApp.authenticate(UserSettings.oidcClientId, <String>["profile", "email", "offline_access"]);
|
||||
// await Navigator.pushNamedAndRemoveUntil(
|
||||
// navigatorKey!.currentState!.context, vhs3LoginUser, (Route<dynamic> route) => false);
|
||||
// } else {
|
||||
// dio.unlock();
|
||||
// dio.interceptors.requestLock.unlock();
|
||||
// dio.interceptors.responseLock.unlock();
|
||||
// options.headers = <String, dynamic>{
|
||||
// "Content-type": "application/json",
|
||||
// "Authorization": "Bearer ${LocalStoreManager.getString(UserSettings.tokenUser)}"
|
||||
// };
|
||||
// await dio.fetch<dynamic>(options);
|
||||
// }
|
||||
// Refresh token
|
||||
final UserUseCases sessionRepository = GetIt.I();
|
||||
final bool token = await sessionRepository.tryRefreshToken();
|
||||
if (!token) {
|
||||
dio.unlock();
|
||||
dio.interceptors.requestLock.unlock();
|
||||
dio.interceptors.responseLock.unlock();
|
||||
// ignore: use_build_context_synchronously
|
||||
gotoLogin(navigatorKey.currentState!.context);
|
||||
} else {
|
||||
dio.unlock();
|
||||
dio.interceptors.requestLock.unlock();
|
||||
dio.interceptors.responseLock.unlock();
|
||||
options.headers = <String, dynamic>{
|
||||
"Content-type": "application/json",
|
||||
"Authorization": "Bearer ${LocalStoreManager.getString(StorageKey.tokenUser)}"
|
||||
};
|
||||
|
||||
try {
|
||||
final response = await dio.fetch<dynamic>(options);
|
||||
return handler.resolve(response);
|
||||
} catch (e) {
|
||||
return handler.next(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final dynamic errorData = err.response?.data;
|
||||
|
||||
@ -8,10 +8,12 @@
|
||||
import 'package:get_it/get_it.dart' as _i1;
|
||||
import 'package:injectable/injectable.dart' as _i2;
|
||||
|
||||
import '../../features/presentation/account/bloc/login_bloc.dart' as _i5;
|
||||
import '../../features/repositories/hra_repository.dart' as _i4;
|
||||
import '../../features/usecases/user_use_cases.dart'
|
||||
as _i3; // ignore_for_file: unnecessary_lambdas
|
||||
import '../../features/presentation/account/bloc/login_bloc.dart' as _i7;
|
||||
import '../../features/presentation/app/bloc/user_bloc.dart' as _i3;
|
||||
import '../../features/repositories/hra_repository.dart' as _i6;
|
||||
import '../../features/usecases/index.dart' as _i4;
|
||||
import '../../features/usecases/user/user_use_cases.dart'
|
||||
as _i5; // ignore_for_file: unnecessary_lambdas
|
||||
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
/// initializes the registration of provided dependencies inside of [GetIt]
|
||||
@ -25,8 +27,9 @@ _i1.GetIt $initGetIt(
|
||||
environment,
|
||||
environmentFilter,
|
||||
);
|
||||
gh.lazySingleton<_i3.UserUseCases>(
|
||||
() => _i3.UserUseCases(get<_i4.HraRepository>()));
|
||||
gh.factory<_i5.LoginBloc>(() => _i5.LoginBloc(get<_i3.UserUseCases>()));
|
||||
gh.factory<_i3.UserBloc>(() => _i3.UserBloc(get<_i4.UserUseCases>()));
|
||||
gh.lazySingleton<_i5.UserUseCases>(
|
||||
() => _i5.UserUseCases(get<_i6.HraRepository>()));
|
||||
gh.factory<_i7.LoginBloc>(() => _i7.LoginBloc(get<_i5.UserUseCases>()));
|
||||
return get;
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ import 'package:baseproject/core/common/custom_interceptor.dart';
|
||||
import 'package:baseproject/core/components/alice.dart';
|
||||
import 'package:baseproject/core/constants/index.dart';
|
||||
import 'package:baseproject/features/presentation/app/view/app.dart';
|
||||
import 'package:baseproject/features/repositories/account_repository.dart';
|
||||
import 'package:baseproject/features/repositories/hra_repository.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
@ -18,3 +18,5 @@ export 'date/date_time_picker.dart';
|
||||
export 'alice.dart';
|
||||
export 'tab/custom_tab.dart';
|
||||
export 'switch/custom_switch_list_tile.dart';
|
||||
export 'text_field/custom_textfield.dart';
|
||||
export 'text_field/text_field_password.dart';
|
||||
|
||||
225
lib/core/components/text_field/custom_textfield.dart
Normal file
225
lib/core/components/text_field/custom_textfield.dart
Normal file
@ -0,0 +1,225 @@
|
||||
import 'package:baseproject/core/components/form/form_builder_field.dart';
|
||||
import 'package:baseproject/core/components/form/form_control.dart';
|
||||
import 'package:baseproject/core/theme/custom_color.dart';
|
||||
import 'package:baseproject/core/theme/text_style.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
typedef ItemToString<T> = String Function(T item);
|
||||
typedef ItemFromString<T> = T? Function(String string);
|
||||
|
||||
class CustomTextField<T> extends FormBuilderField<T> {
|
||||
final FormFieldValidator<T?>? validator;
|
||||
final FormFieldSetter<T?>? onSaved;
|
||||
final TextEditingController? controller;
|
||||
final T? initialValue;
|
||||
final bool autofocus;
|
||||
final int? maxLines;
|
||||
final int? maxLength;
|
||||
final bool enabled;
|
||||
final ItemFromString<T?>? itemFromString;
|
||||
final ItemToString<T?>? itemToString;
|
||||
final bool isLabelTop;
|
||||
final String labelText;
|
||||
final TextStyle? labelTextStyle;
|
||||
final GestureTapCallback? onTap;
|
||||
final int? minLines;
|
||||
final double borderRadius;
|
||||
final InputDecoration decoration;
|
||||
final bool enableSuggestions;
|
||||
final TextInputType? textInputType;
|
||||
final TextStyle? style;
|
||||
final TextAlign textAlign;
|
||||
final bool readOnly;
|
||||
final ValueChanged<String>? onFieldSubmitted;
|
||||
List<TextInputFormatter>? inputFormatters;
|
||||
final TextInputAction? textInputAction;
|
||||
final bool obscureText;
|
||||
final bool autoCorrect;
|
||||
final TextCapitalization textCapitalization;
|
||||
final bool isShowTextRequire;
|
||||
final Color? cursorColor;
|
||||
final Color? borderColor;
|
||||
|
||||
CustomTextField({
|
||||
Key? key,
|
||||
String name = 'textField',
|
||||
this.validator,
|
||||
this.onSaved,
|
||||
ValueChanged<T?>? onChanged,
|
||||
this.initialValue,
|
||||
this.autofocus = false,
|
||||
this.maxLength,
|
||||
this.enabled = true,
|
||||
this.itemFromString,
|
||||
this.itemToString,
|
||||
this.isLabelTop = false,
|
||||
this.labelText = "",
|
||||
this.labelTextStyle,
|
||||
//TextFormField
|
||||
this.controller,
|
||||
AutovalidateMode autovalidateMode = AutovalidateMode.disabled,
|
||||
this.decoration = const InputDecoration(
|
||||
//border: OutlineInputBorder(),
|
||||
),
|
||||
this.maxLines,
|
||||
this.minLines,
|
||||
this.borderRadius = 16,
|
||||
this.onTap,
|
||||
this.enableSuggestions = false,
|
||||
this.textInputType,
|
||||
this.style,
|
||||
this.textAlign = TextAlign.start,
|
||||
this.readOnly = false,
|
||||
this.inputFormatters,
|
||||
FocusNode? focusNode,
|
||||
this.onFieldSubmitted,
|
||||
this.textInputAction,
|
||||
this.obscureText = false,
|
||||
this.autoCorrect = false,
|
||||
this.textCapitalization = TextCapitalization.sentences,
|
||||
this.isShowTextRequire = false,
|
||||
this.cursorColor,
|
||||
this.borderColor,
|
||||
}) :
|
||||
//: controller = controller ?? TextEditingController(text: _toString<T>(initialValue, itemToString)),
|
||||
// ??
|
||||
// InputDecoration(
|
||||
// border: OutlineInputBorder(borderRadius: BorderRadius.circular(borderRadius)),
|
||||
// focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(borderRadius)),
|
||||
// // enabledBorder: InputBorder.none,
|
||||
// // errorBorder: InputBorder.none,
|
||||
// // disabledBorder: InputBorder.none,
|
||||
// ),
|
||||
super(
|
||||
name: name,
|
||||
key: key,
|
||||
autovalidateMode: autovalidateMode,
|
||||
onChanged: onChanged,
|
||||
focusNode: focusNode,
|
||||
initialValue: initialValue,
|
||||
decoration: decoration,
|
||||
builder: (FormFieldState<T?> field) {
|
||||
final _TextFieldState<T> state = field as _TextFieldState<T>;
|
||||
//return state.build(state.context);
|
||||
if (isLabelTop) return state._buildFieldSet();
|
||||
|
||||
return state._buildTextFormField();
|
||||
});
|
||||
|
||||
@override
|
||||
_TextFieldState<T> createState() => _TextFieldState<T>();
|
||||
}
|
||||
|
||||
class _TextFieldState<T> extends FormBuilderFieldState<CustomTextField<T>, T> {
|
||||
late TextEditingController textController;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
textController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
textController = widget.controller ?? TextEditingController();
|
||||
textController.text = initialText;
|
||||
// widget.decoration = widget.decoration.copyWith(
|
||||
// border: OutlineInputBorder(
|
||||
// borderRadius: BorderRadius.all(
|
||||
// Radius.circular(widget.borderRadius),
|
||||
// )),
|
||||
// enabledBorder: OutlineInputBorder(
|
||||
// borderRadius: BorderRadius.all(
|
||||
// Radius.circular(widget.borderRadius),
|
||||
// )),
|
||||
//);
|
||||
}
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// if (widget.isLabelTop)
|
||||
// return _buildFieldSet();
|
||||
// else
|
||||
// return _buildTextFormField();
|
||||
// }
|
||||
|
||||
@override
|
||||
void reset() {
|
||||
super.reset();
|
||||
textController.text = initialText;
|
||||
}
|
||||
|
||||
String get initialText => widget.itemToString?.call(initialValue) ?? initialValue?.toString() ?? '';
|
||||
|
||||
Widget _buildTextFormField() {
|
||||
return TextFormField(
|
||||
autocorrect: widget.autoCorrect,
|
||||
onFieldSubmitted: widget.onFieldSubmitted,
|
||||
textInputAction: widget.textInputAction,
|
||||
focusNode: effectiveFocusNode,
|
||||
enableSuggestions: true,
|
||||
|
||||
//widget.enableSuggestions,
|
||||
textCapitalization: widget.textCapitalization,
|
||||
controller: textController,
|
||||
decoration: widget.decoration.copyWith(
|
||||
labelText: !widget.isLabelTop ? widget.labelText : (widget.decoration.labelText),
|
||||
labelStyle: !widget.isLabelTop ? labelTextStyle : null,
|
||||
// fillColor: widget.fillColor ?? CustomColor.bgGrayLight,
|
||||
// filled: true,
|
||||
),
|
||||
|
||||
keyboardType: widget.textInputType,
|
||||
style: widget.style,
|
||||
textAlign: widget.textAlign,
|
||||
autofocus: widget.autofocus,
|
||||
obscureText: widget.obscureText,
|
||||
|
||||
//autocorrect: widget.autocorrect,
|
||||
//maxLengthEnforcement: widget.maxLengthEnforcement,
|
||||
maxLines: widget.maxLines,
|
||||
maxLength: widget.maxLength,
|
||||
//scrollPadding: widget.scrollPadding,
|
||||
//textCapitalization: widget.textCapitalization,
|
||||
inputFormatters: widget.inputFormatters,
|
||||
minLines: widget.minLines,
|
||||
enabled: widget.enabled,
|
||||
readOnly: widget.readOnly,
|
||||
autovalidateMode: widget.autovalidateMode,
|
||||
cursorColor: widget.cursorColor,
|
||||
|
||||
//initialValue: widget.controller == null ? initialText : null,
|
||||
onChanged: (String value) {
|
||||
didChange(_toObject<T>(value, widget.itemFromString));
|
||||
},
|
||||
validator: (String? value) {
|
||||
if (widget.validator != null) {
|
||||
return widget.validator!(_toObject<T>(value, widget.itemFromString));
|
||||
}
|
||||
},
|
||||
onTap: widget.onTap,
|
||||
onSaved: (String? value) {
|
||||
if (widget.onSaved != null) {
|
||||
return widget.onSaved!(_toObject<T>(value, widget.itemFromString));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
TextStyle get labelTextStyle => textStyleBodySmall.copyWith(color: CustomColor.textGray);
|
||||
|
||||
Widget _buildFieldSet() {
|
||||
return FormControl(
|
||||
child: _buildTextFormField(),
|
||||
isShowTextRequire: widget.isShowTextRequire,
|
||||
labelText: widget.labelText,
|
||||
labelTextStyle: widget.labelTextStyle,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _toString<T>(T? value, ItemToString<T?>? fn) => (fn == null ? value?.toString() : fn(value)) ?? '';
|
||||
|
||||
T? _toObject<T>(String? s, ItemFromString<T?>? fn) => fn == null ? s as T : fn(s ?? '');
|
||||
56
lib/core/components/text_field/text_field_password.dart
Normal file
56
lib/core/components/text_field/text_field_password.dart
Normal file
@ -0,0 +1,56 @@
|
||||
import 'package:baseproject/core/components/index.dart';
|
||||
import 'package:baseproject/core/theme/form_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TextFieldPassword extends StatefulWidget {
|
||||
const TextFieldPassword({
|
||||
Key? key,
|
||||
this.labelText = "",
|
||||
this.name = "TextFieldPassword",
|
||||
this.validator,
|
||||
this.onChanged,
|
||||
}) : super(key: key);
|
||||
final String labelText;
|
||||
final String name;
|
||||
final FormFieldValidator<String?>? validator;
|
||||
final ValueChanged<String?>? onChanged;
|
||||
|
||||
@override
|
||||
State<TextFieldPassword> createState() => _TextFieldPasswordState();
|
||||
}
|
||||
|
||||
class _TextFieldPasswordState extends State<TextFieldPassword> {
|
||||
late bool _passwordVisible;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_passwordVisible = false;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomTextField(
|
||||
textCapitalization: TextCapitalization.none,
|
||||
isShowTextRequire: true,
|
||||
isLabelTop: true,
|
||||
name: widget.name,
|
||||
validator: widget.validator,
|
||||
labelText: widget.labelText,
|
||||
obscureText: !_passwordVisible,
|
||||
maxLines: 1,
|
||||
onChanged: widget.onChanged,
|
||||
decoration: FormTheme.getInputDecoration().copyWith(
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_passwordVisible ? Icons.visibility : Icons.visibility_off,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_passwordVisible = !_passwordVisible;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,6 @@
|
||||
class StorageKey {
|
||||
static const String libraryKeywordHistoryKey = 'libraryKeywordHistoryKey';
|
||||
static const String userInfo = 'USER_INFO';
|
||||
static const String tokenUser = 'TOKEN_USER';
|
||||
static const String refreshToken = 'REFRESH_TOKEN';
|
||||
}
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
import 'package:baseproject/core/common/bloc/bloc_index.dart';
|
||||
import 'package:baseproject/core/common/index.dart';
|
||||
import 'package:baseproject/features/presentation/app/bloc/user_bloc.dart';
|
||||
import 'package:baseproject/features/repositories/hra_repository.dart';
|
||||
import 'package:baseproject/features/usecases/user_use_cases.dart';
|
||||
import 'package:baseproject/features/route/route_goto.dart';
|
||||
import 'package:baseproject/features/usecases/user/user_use_cases.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoginViewModel {
|
||||
LoginViewModel({
|
||||
this.isLoading = false,
|
||||
this.errorMessage,
|
||||
this.loginResponse,
|
||||
this.captcha,
|
||||
});
|
||||
|
||||
final bool isLoading;
|
||||
final String? errorMessage;
|
||||
final LoginResponseDto? loginResponse;
|
||||
final DNTCaptchaApiResponse? captcha;
|
||||
|
||||
@ -24,7 +25,6 @@ class LoginViewModel {
|
||||
}) {
|
||||
return LoginViewModel(
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
errorMessage: errorMessage,
|
||||
loginResponse: loginResponse ?? this.loginResponse,
|
||||
captcha: captcha ?? this.captcha,
|
||||
);
|
||||
@ -33,7 +33,7 @@ class LoginViewModel {
|
||||
|
||||
class LoginBloc extends BaseCubit<BaseStateBloc<LoginViewModel>> {
|
||||
LoginBloc(this._userUseCases) : super(InitState<LoginViewModel>(LoginViewModel())) {
|
||||
loadCaptcha();
|
||||
// loadCaptcha();
|
||||
}
|
||||
|
||||
final UserUseCases _userUseCases;
|
||||
@ -61,7 +61,7 @@ class LoginBloc extends BaseCubit<BaseStateBloc<LoginViewModel>> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> login(LoginDto request) async {
|
||||
Future<void> login(LoginDto request, BuildContext context) async {
|
||||
final currentModel = state.model;
|
||||
|
||||
emit(
|
||||
@ -71,30 +71,22 @@ class LoginBloc extends BaseCubit<BaseStateBloc<LoginViewModel>> {
|
||||
);
|
||||
|
||||
final result = await _userUseCases.loginAccount(request);
|
||||
|
||||
emit(
|
||||
LoadedState<LoginViewModel>(
|
||||
currentModel.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
result.fold(
|
||||
(error) {
|
||||
showErrorMessage(error);
|
||||
emit(
|
||||
ErrorState<LoginViewModel>(
|
||||
currentModel.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: error,
|
||||
),
|
||||
),
|
||||
);
|
||||
loadCaptcha();
|
||||
// loadCaptcha();
|
||||
},
|
||||
(response) {
|
||||
emit(
|
||||
LoadedState<LoginViewModel>(
|
||||
currentModel.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: null,
|
||||
loginResponse: response,
|
||||
),
|
||||
),
|
||||
);
|
||||
BlocProvider.of<UserBloc>(context).updateUserInfo(response.userInfo ?? UserInfoDto());
|
||||
gotoHome(context);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:baseproject/core/common/index.dart';
|
||||
import 'package:baseproject/core/components/index.dart';
|
||||
import 'package:baseproject/features/presentation/account/bloc/login_bloc.dart';
|
||||
import 'package:baseproject/features/repositories/hra_repository.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
@ -36,7 +37,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
dto.captchaToken = captcha?.dntCaptchaTokenValue;
|
||||
dto.captchaInputText = "999999";
|
||||
|
||||
_loginBloc.login(dto);
|
||||
_loginBloc.login(dto, context);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -51,128 +52,40 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: FormBuilder(
|
||||
initialValue: kDebugMode
|
||||
? {
|
||||
'userName': 'quylx',
|
||||
'password': 'BearCMS0011002848238master',
|
||||
}
|
||||
: {},
|
||||
key: _formKey,
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
child: BlocBuilder<LoginBloc, BaseStateBloc<LoginViewModel>>(
|
||||
builder: (context, state) {
|
||||
final vm = state.model;
|
||||
final isLoading = state is LoadingState<LoginViewModel> || vm.isLoading;
|
||||
final error = vm.errorMessage;
|
||||
final captcha = vm.captcha;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
if (error != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Text(
|
||||
error,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
FormControl(
|
||||
CustomTextField(
|
||||
name: 'userName',
|
||||
labelText: 'Tên đăng nhập',
|
||||
isLabelTop: true,
|
||||
isShowTextRequire: true,
|
||||
child: TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
hintText: 'Nhập tên đăng nhập',
|
||||
),
|
||||
validator: FormBuilderValidators.required<String>(
|
||||
context,
|
||||
),
|
||||
onSaved: (value) {
|
||||
_formKey.currentState?.setInternalFieldValue(
|
||||
'userName',
|
||||
value,
|
||||
isUpdateState: false,
|
||||
);
|
||||
},
|
||||
validator: FormBuilderValidators.required<String>(
|
||||
context,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
FormControl(
|
||||
ConstantWidget.heightSpace16,
|
||||
TextFieldPassword(
|
||||
name: 'password',
|
||||
labelText: 'Mật khẩu',
|
||||
isShowTextRequire: true,
|
||||
child: TextFormField(
|
||||
obscureText: true,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
hintText: 'Nhập mật khẩu',
|
||||
),
|
||||
validator: FormBuilderValidators.required<String>(
|
||||
context,
|
||||
),
|
||||
onSaved: (value) {
|
||||
_formKey.currentState?.setInternalFieldValue(
|
||||
'password',
|
||||
value,
|
||||
isUpdateState: false,
|
||||
);
|
||||
},
|
||||
validator: FormBuilderValidators.required<String>(
|
||||
context,
|
||||
),
|
||||
),
|
||||
// const SizedBox(height: 8),
|
||||
// if (captcha != null) ...[
|
||||
// const SizedBox(height: 16),
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// _loginBloc.loadCaptcha();
|
||||
// },
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// const Text('Captcha'),
|
||||
// const SizedBox(height: 8),
|
||||
// Image.network(
|
||||
// captcha.dntCaptchaImgUrl ?? '',
|
||||
// height: 60,
|
||||
// errorBuilder: (_, __, ___) => Text(
|
||||
// captcha.dntCaptchaImgUrl ?? '',
|
||||
// style: const TextStyle(color: Colors.blue),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 8),
|
||||
// FormControl(
|
||||
// labelText: 'Nhập mã captcha',
|
||||
// isShowTextRequire: true,
|
||||
// child: TextFormField(
|
||||
// decoration: const InputDecoration(
|
||||
// border: OutlineInputBorder(),
|
||||
// hintText: 'Nhập mã captcha',
|
||||
// ),
|
||||
// validator: FormBuilderValidators.required<String>(
|
||||
// context,
|
||||
// ),
|
||||
// onSaved: (value) {
|
||||
// _formKey.currentState?.setInternalFieldValue(
|
||||
// 'captchaInput',
|
||||
// value,
|
||||
// isUpdateState: false,
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Checkbox(
|
||||
value: _rememberMe,
|
||||
onChanged: (v) {
|
||||
setState(() {
|
||||
_rememberMe = v ?? false;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Text('Ghi nhớ đăng nhập'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ConstantWidget.heightSpace24,
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: ConstantWidget.buildPrimaryButton(
|
||||
|
||||
30
lib/features/presentation/app/bloc/user_bloc.dart
Normal file
30
lib/features/presentation/app/bloc/user_bloc.dart
Normal file
@ -0,0 +1,30 @@
|
||||
import 'package:baseproject/core/common/index.dart';
|
||||
import 'package:baseproject/features/repositories/hra_repository.dart';
|
||||
import 'package:baseproject/features/usecases/index.dart';
|
||||
import 'package:baseproject/features/usecases/user/user_use_cases.dart';
|
||||
|
||||
class UserBloc extends BaseCubit<BaseStateBloc<UserInfoDto?>> {
|
||||
UserBloc(this._userUseCases) : super(InitState<UserInfoDto?>(null));
|
||||
|
||||
final UserUseCases _userUseCases;
|
||||
|
||||
Future<bool> getUserInfo() async {
|
||||
final resultRefreshToken = await _userUseCases.refreshToken();
|
||||
if (resultRefreshToken.isRight()) {
|
||||
final resultUserInfo = await _userUseCases.getUserInfoFromApi();
|
||||
emit(LoadedState<UserInfoDto>(resultUserInfo.fold((l) => UserInfoDto(), (r) => r)));
|
||||
} else {
|
||||
emit(LoadedState<UserInfoDto?>(null));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
updateUserInfo(UserInfoDto userInfo) {
|
||||
emit(LoadedState<UserInfoDto>(userInfo));
|
||||
}
|
||||
|
||||
logout() {
|
||||
emit(LoadedState<UserInfoDto?>(null));
|
||||
_userUseCases.clearData();
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
import 'package:baseproject/core/common/index.dart';
|
||||
import 'package:baseproject/core/components/alice.dart';
|
||||
import 'package:baseproject/core/language/app_localizations.dart';
|
||||
import 'package:baseproject/core/theme/custom_theme.dart';
|
||||
import 'package:baseproject/features/presentation/app/bloc/user_bloc.dart';
|
||||
import 'package:baseproject/features/route/route_const.dart';
|
||||
import 'package:baseproject/features/route/route_generator.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@ -18,55 +20,59 @@ class App extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _AppState extends State<App> {
|
||||
final UserBloc _userBloc = getItSuper<UserBloc>();
|
||||
String _getLanguage() {
|
||||
return 'vi';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
// navigatorObservers: [CustomNavigatorObserver()],
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: getTheme(context, true),
|
||||
// navigatorKey: navigatorKey,
|
||||
locale: Locale(_getLanguage()),
|
||||
supportedLocales: AppLocalizations.locales,
|
||||
localizationsDelegates: <LocalizationsDelegate<dynamic>>[
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate
|
||||
],
|
||||
navigatorKey: navigatorKey,
|
||||
localeResolutionCallback: AppLocalizations.localeResolutionCallback,
|
||||
initialRoute: appInitRouteName,
|
||||
onGenerateRoute: RouteGenerator.generatorRoute,
|
||||
builder: EasyLoading.init(builder: (BuildContext context, Widget? child) {
|
||||
EasyLoading.instance.userInteractions = false;
|
||||
return Container(
|
||||
child: kDebugMode
|
||||
? Stack(
|
||||
children: <Widget>[
|
||||
child!,
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
child: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: FloatingActionButton(
|
||||
onPressed: () {
|
||||
CustomAlice.showScreen();
|
||||
},
|
||||
backgroundColor: Colors.red,
|
||||
child: const Text("A"),
|
||||
return BlocProvider(
|
||||
create: (context) => _userBloc,
|
||||
child: MaterialApp(
|
||||
// navigatorObservers: [CustomNavigatorObserver()],
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: getTheme(context, true),
|
||||
// navigatorKey: navigatorKey,
|
||||
locale: Locale(_getLanguage()),
|
||||
supportedLocales: AppLocalizations.locales,
|
||||
localizationsDelegates: <LocalizationsDelegate<dynamic>>[
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate
|
||||
],
|
||||
navigatorKey: navigatorKey,
|
||||
localeResolutionCallback: AppLocalizations.localeResolutionCallback,
|
||||
initialRoute: appInitRouteName,
|
||||
onGenerateRoute: RouteGenerator.generatorRoute,
|
||||
builder: EasyLoading.init(builder: (BuildContext context, Widget? child) {
|
||||
EasyLoading.instance.userInteractions = false;
|
||||
return Container(
|
||||
child: kDebugMode
|
||||
? Stack(
|
||||
children: <Widget>[
|
||||
child!,
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
child: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: FloatingActionButton(
|
||||
onPressed: () {
|
||||
CustomAlice.showScreen();
|
||||
},
|
||||
backgroundColor: Colors.red,
|
||||
child: const Text("A"),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: child!,
|
||||
);
|
||||
}));
|
||||
],
|
||||
)
|
||||
: child!,
|
||||
);
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
38
lib/features/presentation/app/view/init_screen.dart
Normal file
38
lib/features/presentation/app/view/init_screen.dart
Normal file
@ -0,0 +1,38 @@
|
||||
import 'package:baseproject/core/common/index.dart';
|
||||
import 'package:baseproject/features/presentation/app/bloc/user_bloc.dart';
|
||||
import 'package:baseproject/features/route/route_goto.dart';
|
||||
import 'package:baseproject/features/usecases/index.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class InitScreen extends StatefulWidget {
|
||||
const InitScreen({super.key});
|
||||
|
||||
@override
|
||||
State<InitScreen> createState() => _InitScreenState();
|
||||
}
|
||||
|
||||
class _InitScreenState extends State<InitScreen> {
|
||||
UserBloc get _userBloc => BlocProvider.of<UserBloc>(context);
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initData();
|
||||
}
|
||||
|
||||
void initData() {
|
||||
_userBloc.getUserInfo().then((value) {
|
||||
if (value) {
|
||||
gotoHome(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
import 'package:baseproject/core/common/index.dart';
|
||||
import 'package:baseproject/core/components/constants_widget.dart';
|
||||
import 'package:baseproject/core/language/app_localizations.dart';
|
||||
import 'package:baseproject/features/model/index.dart';
|
||||
import 'package:baseproject/features/presentation/app/bloc/user_bloc.dart';
|
||||
import 'package:baseproject/features/route/route_goto.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@ -15,18 +18,39 @@ class _HomeState extends State<Home> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(AppLocalizations.of(context)!.translate("first_string")),
|
||||
ConstantWidget.buildPrimaryButton(
|
||||
onPressed: () {
|
||||
gotoLogin(context);
|
||||
},
|
||||
text: 'Đăng nhập',
|
||||
),
|
||||
],
|
||||
child: BlocBuilder<UserBloc, BaseStateBloc<UserInfoDto?>>(
|
||||
builder: (context, state) {
|
||||
final userInfo = state.model;
|
||||
if (userInfo != null) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text("Chào ${userInfo.fullName ?? ''}"),
|
||||
ConstantWidget.buildPrimaryButton(
|
||||
onPressed: () {
|
||||
BlocProvider.of<UserBloc>(context).logout();
|
||||
},
|
||||
text: 'Đăng xuất',
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(AppLocalizations.of(context)!.translate("first_string")),
|
||||
ConstantWidget.buildPrimaryButton(
|
||||
onPressed: () {
|
||||
gotoLogin(context);
|
||||
},
|
||||
text: 'Đăng nhập',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@ -69,7 +69,8 @@ abstract class HraRepository {
|
||||
|
||||
///
|
||||
@POST('/api/v1/account/refresh-token')
|
||||
Future<RefreshTokenResponseDtoApiResponse> accountRefreshToken();
|
||||
Future<RefreshTokenResponseDtoApiResponse> accountRefreshToken(
|
||||
@Body() RefreshTokenRequestDto body);
|
||||
|
||||
///
|
||||
@POST('/api/v1/account/login-with-2fa')
|
||||
|
||||
@ -254,11 +254,12 @@ class _HraRepository implements HraRepository {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<RefreshTokenResponseDtoApiResponse> accountRefreshToken() async {
|
||||
Future<RefreshTokenResponseDtoApiResponse> accountRefreshToken(body) async {
|
||||
const _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = <String, dynamic>{};
|
||||
_data.addAll(body.toJson());
|
||||
final _result = await _dio.fetch<Map<String, dynamic>>(
|
||||
_setStreamType<RefreshTokenResponseDtoApiResponse>(Options(
|
||||
method: 'POST',
|
||||
|
||||
@ -12641,6 +12641,22 @@ class RefreshTokenEntity {
|
||||
Map<String, dynamic> toJson() => _$RefreshTokenEntityToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class RefreshTokenRequestDto {
|
||||
RefreshTokenRequestDto({
|
||||
this.refreshToken,
|
||||
});
|
||||
|
||||
factory RefreshTokenRequestDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$RefreshTokenRequestDtoFromJson(json);
|
||||
|
||||
@JsonKey(name: 'refreshToken', includeIfNull: true)
|
||||
String? refreshToken;
|
||||
static const fromJsonFactory = _$RefreshTokenRequestDtoFromJson;
|
||||
static const toJsonFactory = _$RefreshTokenRequestDtoToJson;
|
||||
Map<String, dynamic> toJson() => _$RefreshTokenRequestDtoToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class RefreshTokenResponseDto {
|
||||
RefreshTokenResponseDto({
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,3 @@
|
||||
const String appInitRouteName = '/app_init';
|
||||
const String loginRouteName = '/login';
|
||||
const String homeApp = '/home_app';
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:baseproject/features/presentation/account/login_screen.dart';
|
||||
import 'package:baseproject/features/presentation/app/view/init_screen.dart';
|
||||
import 'package:baseproject/features/presentation/home/view/home.dart';
|
||||
import 'package:baseproject/features/route/route_const.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -9,6 +10,8 @@ class RouteGenerator {
|
||||
// tracking vào màn
|
||||
switch (setting.name) {
|
||||
case appInitRouteName:
|
||||
return MaterialPageRoute<void>(settings: setting, builder: (_) => const InitScreen());
|
||||
case homeApp:
|
||||
return MaterialPageRoute<void>(settings: setting, builder: (_) => const Home());
|
||||
case loginRouteName:
|
||||
return MaterialPageRoute<void>(settings: setting, builder: (_) => const LoginScreen());
|
||||
|
||||
@ -4,3 +4,11 @@ import 'route_const.dart';
|
||||
void gotoLogin(BuildContext context) {
|
||||
Navigator.pushNamed(context, loginRouteName);
|
||||
}
|
||||
|
||||
void gotoHome(BuildContext context) {
|
||||
try {
|
||||
Navigator.pushNamedAndRemoveUntil(context, homeApp, (Route<dynamic> route) => false);
|
||||
} catch (e) {
|
||||
Navigator.pushReplacementNamed(context, homeApp);
|
||||
}
|
||||
}
|
||||
|
||||
1
lib/features/usecases/index.dart
Normal file
1
lib/features/usecases/index.dart
Normal file
@ -0,0 +1 @@
|
||||
export 'user/user_use_cases.dart';
|
||||
115
lib/features/usecases/user/user_use_cases.dart
Normal file
115
lib/features/usecases/user/user_use_cases.dart
Normal file
@ -0,0 +1,115 @@
|
||||
import 'package:baseproject/core/common/index.dart';
|
||||
import 'package:baseproject/core/constants/index.dart';
|
||||
import 'package:baseproject/core/extension/string_extension.dart';
|
||||
import 'package:baseproject/features/repositories/hra_repository.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
@lazySingleton
|
||||
class UserUseCases {
|
||||
final HraRepository _hraRepository;
|
||||
|
||||
UserUseCases(this._hraRepository);
|
||||
|
||||
Future<Either<String, LoginResponseDto>> loginAccount(LoginDto request) async {
|
||||
try {
|
||||
final result = await _hraRepository.accountLoginMobile(request);
|
||||
|
||||
if (result.data == null || result.success == false) {
|
||||
return Left<String, LoginResponseDto>(result.message ?? 'Login failed');
|
||||
}
|
||||
|
||||
await saveToken(result.data?.token ?? '', refreshToken: result.data?.refreshToken ?? '');
|
||||
await saveUserInfo(result.data?.userInfo);
|
||||
|
||||
return Right<String, LoginResponseDto>(result.data!);
|
||||
} catch (ex) {
|
||||
return Left<String, LoginResponseDto>(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveToken(String token, {String? refreshToken}) async {
|
||||
await LocalStoreManager.setString(StorageKey.tokenUser, token);
|
||||
if (refreshToken != null) {
|
||||
await LocalStoreManager.setString(StorageKey.refreshToken, refreshToken);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveUserInfo(UserInfoDto? userInfo) async {
|
||||
if (userInfo != null) {
|
||||
await LocalStoreManager.setObject(StorageKey.userInfo, userInfo.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
UserInfoDto? getUserInfo() {
|
||||
final Map<String, dynamic>? temp = LocalStoreManager.getObject(StorageKey.userInfo);
|
||||
if (temp != null) return UserInfoDto.fromJson(temp);
|
||||
return null;
|
||||
}
|
||||
|
||||
int getCurrentUserId() {
|
||||
return getUserInfo()?.id?.toInt() ?? 0;
|
||||
}
|
||||
|
||||
Future<void> clearData() async {
|
||||
await LocalStoreManager.remove(StorageKey.refreshToken);
|
||||
await LocalStoreManager.remove(StorageKey.tokenUser);
|
||||
await LocalStoreManager.remove(StorageKey.userInfo);
|
||||
}
|
||||
|
||||
Future<Either<String, DNTCaptchaApiResponse>> getCaptcha() async {
|
||||
try {
|
||||
final result = await _hraRepository.accountCaptcha();
|
||||
|
||||
return Right<String, DNTCaptchaApiResponse>(result);
|
||||
} catch (ex) {
|
||||
return Left<String, DNTCaptchaApiResponse>(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<String, bool>> refreshToken() async {
|
||||
final refreshToken = LocalStoreManager.getString(StorageKey.refreshToken);
|
||||
if (refreshToken.isNullOrEmpty) {
|
||||
return const Left<String, bool>('Refresh token not found');
|
||||
}
|
||||
try {
|
||||
final result = await _hraRepository.accountRefreshToken(
|
||||
RefreshTokenRequestDto(refreshToken: LocalStoreManager.getString(StorageKey.refreshToken)));
|
||||
if (result.data != null) {
|
||||
await saveToken(result.data?.token ?? '');
|
||||
}
|
||||
return Right<String, bool>(result.success ?? false);
|
||||
} catch (ex) {
|
||||
await clearData();
|
||||
return Left<String, bool>(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<String, UserInfoDto>> getUserInfoFromApi() async {
|
||||
try {
|
||||
final result = await _hraRepository.accountUserInfo();
|
||||
await saveUserInfo(result);
|
||||
return Right<String, UserInfoDto>(result);
|
||||
} catch (ex) {
|
||||
await clearData();
|
||||
return Left<String, UserInfoDto>(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> tryRefreshToken() async {
|
||||
try {
|
||||
RefreshTokenRequestDto requestModel =
|
||||
RefreshTokenRequestDto(refreshToken: LocalStoreManager.getString(StorageKey.refreshToken));
|
||||
final RefreshTokenResponseDtoApiResponse? token =
|
||||
await HraRepository(Dio(), baseUrl: ApiPath.hra).accountRefreshToken(requestModel);
|
||||
if (token != null) {
|
||||
await saveToken(token.data?.token ?? '');
|
||||
}
|
||||
|
||||
return token != null;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
import 'package:baseproject/features/repositories/hra_repository.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
@lazySingleton
|
||||
class UserUseCases {
|
||||
final HraRepository _hraRepository;
|
||||
|
||||
UserUseCases(this._hraRepository);
|
||||
|
||||
Future<Either<String, LoginResponseDto>> loginAccount(LoginDto request) async {
|
||||
try {
|
||||
final result = await _hraRepository.accountLoginMobile(request);
|
||||
|
||||
if (result.data == null) {
|
||||
return Left<String, LoginResponseDto>(result.message ?? 'Login failed');
|
||||
}
|
||||
|
||||
return Right<String, LoginResponseDto>(result.data!);
|
||||
} catch (ex) {
|
||||
return Left<String, LoginResponseDto>(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<String, DNTCaptchaApiResponse>> getCaptcha() async {
|
||||
try {
|
||||
final result = await _hraRepository.accountCaptcha();
|
||||
|
||||
return Right<String, DNTCaptchaApiResponse>(result);
|
||||
} catch (ex) {
|
||||
return Left<String, DNTCaptchaApiResponse>(ex.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user