fix: login id not registered
This commit is contained in:
parent
6adcb2e471
commit
e4ac170a21
|
@ -1,5 +1,7 @@
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||||
|
import 'package:get/get_state_manager/src/simple/get_controllers.dart';
|
||||||
import 'package:quiz_app/core/utils/logger.dart';
|
import 'package:quiz_app/core/utils/logger.dart';
|
||||||
|
import 'package:quiz_app/data/entity/user/user_entity.dart';
|
||||||
import 'package:quiz_app/data/services/user_storage_service.dart';
|
import 'package:quiz_app/data/services/user_storage_service.dart';
|
||||||
|
|
||||||
class UserController extends GetxController {
|
class UserController extends GetxController {
|
||||||
|
@ -10,7 +12,8 @@ class UserController extends GetxController {
|
||||||
Rx<String> userName = "".obs;
|
Rx<String> userName = "".obs;
|
||||||
Rx<String?> userImage = Rx<String?>(null);
|
Rx<String?> userImage = Rx<String?>(null);
|
||||||
Rx<String> email = "".obs;
|
Rx<String> email = "".obs;
|
||||||
String userId = "";
|
|
||||||
|
UserEntity? userData;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
|
@ -21,12 +24,19 @@ class UserController extends GetxController {
|
||||||
Future<void> loadUser() async {
|
Future<void> loadUser() async {
|
||||||
final data = await _userStorageService.loadUser();
|
final data = await _userStorageService.loadUser();
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
|
userData = data;
|
||||||
userName.value = data.name;
|
userName.value = data.name;
|
||||||
userImage.value = data.picUrl;
|
userImage.value = data.picUrl;
|
||||||
email.value = data.email;
|
email.value = data.email;
|
||||||
userId = data.id ?? "";
|
|
||||||
logC.i("user data $userId");
|
|
||||||
logC.i("Loaded user: ${data.toJson()}");
|
logC.i("Loaded user: ${data.toJson()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setUserFromEntity(UserEntity data) {
|
||||||
|
final userEntity = data;
|
||||||
|
userData = userEntity;
|
||||||
|
userName.value = userEntity.name;
|
||||||
|
userImage.value = userEntity.picUrl;
|
||||||
|
email.value = userEntity.email;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
class UserEntity {
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final String email;
|
||||||
|
final String? picUrl;
|
||||||
|
final String? locale;
|
||||||
|
|
||||||
|
UserEntity({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.email,
|
||||||
|
this.picUrl,
|
||||||
|
this.locale,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory UserEntity.fromJson(Map<String, dynamic> json) {
|
||||||
|
return UserEntity(
|
||||||
|
id: json['id'],
|
||||||
|
name: json['name'],
|
||||||
|
email: json['email'],
|
||||||
|
picUrl: json['pic_url'],
|
||||||
|
locale: json['locale'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'name': name,
|
||||||
|
'email': email,
|
||||||
|
'pic_url': picUrl,
|
||||||
|
'locale': locale,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ class LoginResponseModel {
|
||||||
|
|
||||||
factory LoginResponseModel.fromJson(Map<String, dynamic> json) {
|
factory LoginResponseModel.fromJson(Map<String, dynamic> json) {
|
||||||
return LoginResponseModel(
|
return LoginResponseModel(
|
||||||
id: json['_id'],
|
id: json['id'],
|
||||||
googleId: json['google_id'],
|
googleId: json['google_id'],
|
||||||
email: json['email'],
|
email: json['email'],
|
||||||
name: json['name'],
|
name: json['name'],
|
||||||
|
@ -40,7 +40,7 @@ class LoginResponseModel {
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'_id': id,
|
'id': id,
|
||||||
'google_id': googleId,
|
'google_id': googleId,
|
||||||
'email': email,
|
'email': email,
|
||||||
'name': name,
|
'name': name,
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:quiz_app/data/models/login/login_response_model.dart';
|
import 'package:quiz_app/data/entity/user/user_entity.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class UserStorageService {
|
class UserStorageService {
|
||||||
static const _userKey = 'user_data';
|
static const _userKey = 'user_data';
|
||||||
bool isLogged = false;
|
bool isLogged = false;
|
||||||
|
|
||||||
Future<void> saveUser(LoginResponseModel user) async {
|
Future<void> saveUser(UserEntity user) async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
await prefs.setString(_userKey, jsonEncode(user.toJson()));
|
await prefs.setString(_userKey, jsonEncode(user.toJson()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<LoginResponseModel?> loadUser() async {
|
Future<UserEntity?> loadUser() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
final jsonString = prefs.getString(_userKey);
|
final jsonString = prefs.getString(_userKey);
|
||||||
|
|
||||||
if (jsonString == null) return null;
|
if (jsonString == null) return null;
|
||||||
return LoginResponseModel.fromJson(jsonDecode(jsonString));
|
return UserEntity.fromJson(jsonDecode(jsonString));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> clearUser() async {
|
Future<void> clearUser() async {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:get/get_core/get_core.dart';
|
import 'package:get/get_core/get_core.dart';
|
||||||
import 'package:get/get_instance/get_instance.dart';
|
import 'package:get/get_instance/get_instance.dart';
|
||||||
|
import 'package:quiz_app/data/controllers/user_controller.dart';
|
||||||
import 'package:quiz_app/data/services/auth_service.dart';
|
import 'package:quiz_app/data/services/auth_service.dart';
|
||||||
import 'package:quiz_app/data/services/user_storage_service.dart';
|
import 'package:quiz_app/data/services/user_storage_service.dart';
|
||||||
import 'package:quiz_app/feature/login/controllers/login_controller.dart';
|
import 'package:quiz_app/feature/login/controllers/login_controller.dart';
|
||||||
|
@ -8,6 +9,6 @@ class LoginBinding extends Bindings {
|
||||||
@override
|
@override
|
||||||
void dependencies() {
|
void dependencies() {
|
||||||
Get.lazyPut(() => AuthService());
|
Get.lazyPut(() => AuthService());
|
||||||
Get.lazyPut(() => LoginController(Get.find<AuthService>(), Get.find<UserStorageService>()));
|
Get.lazyPut(() => LoginController(Get.find<AuthService>(), Get.find<UserStorageService>(), Get.find<UserController>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:google_sign_in/google_sign_in.dart';
|
import 'package:google_sign_in/google_sign_in.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:quiz_app/app/routes/app_pages.dart';
|
import 'package:quiz_app/app/routes/app_pages.dart';
|
||||||
import 'package:quiz_app/component/global_button.dart';
|
import 'package:quiz_app/component/global_button.dart';
|
||||||
import 'package:quiz_app/core/utils/logger.dart';
|
import 'package:quiz_app/core/utils/logger.dart';
|
||||||
|
import 'package:quiz_app/data/controllers/user_controller.dart';
|
||||||
|
import 'package:quiz_app/data/entity/user/user_entity.dart';
|
||||||
import 'package:quiz_app/data/models/login/login_request_model.dart';
|
import 'package:quiz_app/data/models/login/login_request_model.dart';
|
||||||
import 'package:quiz_app/data/models/login/login_response_model.dart';
|
import 'package:quiz_app/data/models/login/login_response_model.dart';
|
||||||
import 'package:quiz_app/data/services/auth_service.dart';
|
import 'package:quiz_app/data/services/auth_service.dart';
|
||||||
|
@ -12,16 +14,16 @@ import 'package:quiz_app/data/services/user_storage_service.dart';
|
||||||
class LoginController extends GetxController {
|
class LoginController extends GetxController {
|
||||||
final AuthService _authService;
|
final AuthService _authService;
|
||||||
final UserStorageService _userStorageService;
|
final UserStorageService _userStorageService;
|
||||||
|
final UserController _userController;
|
||||||
|
|
||||||
LoginController(this._authService, this._userStorageService);
|
LoginController(this._authService, this._userStorageService, this._userController);
|
||||||
|
|
||||||
final TextEditingController emailController = TextEditingController();
|
final TextEditingController emailController = TextEditingController();
|
||||||
final TextEditingController passwordController = TextEditingController();
|
final TextEditingController passwordController = TextEditingController();
|
||||||
|
|
||||||
final Rx<ButtonType> isButtonEnabled = ButtonType.disabled.obs;
|
final Rx<ButtonType> isButtonEnabled = ButtonType.disabled.obs;
|
||||||
|
final RxBool isPasswordHidden = true.obs;
|
||||||
var isPasswordHidden = true.obs;
|
final RxBool isLoading = false.obs;
|
||||||
var isLoading = false.obs;
|
|
||||||
|
|
||||||
final GoogleSignIn _googleSignIn = GoogleSignIn(
|
final GoogleSignIn _googleSignIn = GoogleSignIn(
|
||||||
scopes: ['email', 'profile', 'openid'],
|
scopes: ['email', 'profile', 'openid'],
|
||||||
|
@ -37,22 +39,17 @@ class LoginController extends GetxController {
|
||||||
void _validateFields() {
|
void _validateFields() {
|
||||||
final isEmailNotEmpty = emailController.text.trim().isNotEmpty;
|
final isEmailNotEmpty = emailController.text.trim().isNotEmpty;
|
||||||
final isPasswordNotEmpty = passwordController.text.trim().isNotEmpty;
|
final isPasswordNotEmpty = passwordController.text.trim().isNotEmpty;
|
||||||
print('its type');
|
isButtonEnabled.value = (isEmailNotEmpty && isPasswordNotEmpty) ? ButtonType.primary : ButtonType.disabled;
|
||||||
if (isEmailNotEmpty && isPasswordNotEmpty) {
|
|
||||||
isButtonEnabled.value = ButtonType.primary;
|
|
||||||
} else {
|
|
||||||
isButtonEnabled.value = ButtonType.disabled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void togglePasswordVisibility() {
|
void togglePasswordVisibility() {
|
||||||
isPasswordHidden.value = !isPasswordHidden.value;
|
isPasswordHidden.toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// **🔹 Login via Email & Password**
|
/// **🔹 Login via Email & Password**
|
||||||
Future<void> loginWithEmail() async {
|
Future<void> loginWithEmail() async {
|
||||||
String email = emailController.text.trim();
|
final email = emailController.text.trim();
|
||||||
String password = passwordController.text.trim();
|
final password = passwordController.text.trim();
|
||||||
|
|
||||||
if (email.isEmpty || password.isEmpty) {
|
if (email.isEmpty || password.isEmpty) {
|
||||||
Get.snackbar("Error", "Email and password are required");
|
Get.snackbar("Error", "Email and password are required");
|
||||||
|
@ -62,18 +59,17 @@ class LoginController extends GetxController {
|
||||||
try {
|
try {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
|
|
||||||
LoginResponseModel response = await _authService.loginWithEmail(
|
final LoginResponseModel response = await _authService.loginWithEmail(
|
||||||
LoginRequestModel(
|
LoginRequestModel(email: email, password: password),
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await _userStorageService.saveUser(response);
|
final userEntity = _convertLoginResponseToUserEntity(response);
|
||||||
|
|
||||||
|
await _userStorageService.saveUser(userEntity);
|
||||||
|
_userController.setUserFromEntity(userEntity);
|
||||||
_userStorageService.isLogged = true;
|
_userStorageService.isLogged = true;
|
||||||
|
|
||||||
Get.toNamed(AppRoutes.mainPage);
|
Get.offAllNamed(AppRoutes.mainPage);
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
logC.e(e, stackTrace: stackTrace);
|
logC.e(e, stackTrace: stackTrace);
|
||||||
Get.snackbar("Error", "Failed to connect to server");
|
Get.snackbar("Error", "Failed to connect to server");
|
||||||
|
@ -82,6 +78,7 @@ class LoginController extends GetxController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// **🔹 Login via Google**
|
||||||
Future<void> loginWithGoogle() async {
|
Future<void> loginWithGoogle() async {
|
||||||
try {
|
try {
|
||||||
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
|
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
|
||||||
|
@ -91,25 +88,39 @@ class LoginController extends GetxController {
|
||||||
}
|
}
|
||||||
|
|
||||||
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
|
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
|
||||||
|
final idToken = googleAuth.idToken;
|
||||||
|
|
||||||
if (googleAuth.idToken == null || googleAuth.idToken!.isEmpty) {
|
if (idToken == null || idToken.isEmpty) {
|
||||||
Get.snackbar("Error", "Google sign-in failed. No ID Token received.");
|
Get.snackbar("Error", "Google sign-in failed. No ID Token received.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String idToken = googleAuth.idToken!;
|
final LoginResponseModel response = await _authService.loginWithGoogle(idToken);
|
||||||
|
|
||||||
final response = await _authService.loginWithGoogle(idToken);
|
final userEntity = _convertLoginResponseToUserEntity(response);
|
||||||
await _userStorageService.saveUser(response);
|
|
||||||
|
|
||||||
|
await _userStorageService.saveUser(userEntity);
|
||||||
|
_userController.setUserFromEntity(userEntity);
|
||||||
_userStorageService.isLogged = true;
|
_userStorageService.isLogged = true;
|
||||||
|
|
||||||
Get.toNamed(AppRoutes.mainPage);
|
Get.offAllNamed(AppRoutes.mainPage);
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
logC.e("Google Sign-In Error: $e", stackTrace: stackTrace);
|
logC.e("Google Sign-In Error: $e", stackTrace: stackTrace);
|
||||||
Get.snackbar("Error", "Google sign-in error");
|
Get.snackbar("Error", "Google sign-in error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void goToRegsPage() => Get.toNamed(AppRoutes.mainPage);
|
void goToRegsPage() => Get.toNamed(AppRoutes.registerPage);
|
||||||
|
|
||||||
|
/// Helper untuk convert LoginResponseModel ke UserEntity
|
||||||
|
UserEntity _convertLoginResponseToUserEntity(LoginResponseModel response) {
|
||||||
|
logC.i("user id : ${response.id}");
|
||||||
|
return UserEntity(
|
||||||
|
id: response.id ?? '',
|
||||||
|
name: response.name,
|
||||||
|
email: response.email,
|
||||||
|
picUrl: response.picUrl,
|
||||||
|
locale: response.locale,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class ProfileView extends GetView<ProfileController> {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Obx(() {
|
child: Obx(() {
|
||||||
return ListView(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildAvatar(),
|
_buildAvatar(),
|
||||||
|
|
|
@ -57,7 +57,7 @@ class QuizPreviewController extends GetxController {
|
||||||
date: formattedDate,
|
date: formattedDate,
|
||||||
totalQuiz: data.length,
|
totalQuiz: data.length,
|
||||||
limitDuration: data.length * 30,
|
limitDuration: data.length * 30,
|
||||||
authorId: _userController.userId,
|
authorId: _userController.userData!.id,
|
||||||
questionListings: _mapQuestionsToListings(data),
|
questionListings: _mapQuestionsToListings(data),
|
||||||
);
|
);
|
||||||
final success = await _quizService.createQuiz(quizRequest);
|
final success = await _quizService.createQuiz(quizRequest);
|
||||||
|
|
Loading…
Reference in New Issue