diff --git a/lib/core/endpoint/api_endpoint.dart b/lib/core/endpoint/api_endpoint.dart index cab3205..6da5d84 100644 --- a/lib/core/endpoint/api_endpoint.dart +++ b/lib/core/endpoint/api_endpoint.dart @@ -22,4 +22,7 @@ class APIEndpoint { static const String subject = "/subject"; static const String session = "/session"; + + static const String userData = "/user"; + static const String userUpdate = "/user/update"; } diff --git a/lib/data/entity/user/user_entity.dart b/lib/data/entity/user/user_entity.dart index 7528448..733ad60 100644 --- a/lib/data/entity/user/user_entity.dart +++ b/lib/data/entity/user/user_entity.dart @@ -3,23 +3,29 @@ class UserEntity { final String name; final String email; final String? picUrl; + final String? birthDate; final String? locale; + final String? phone; -UserEntity({ + UserEntity({ required this.id, required this.name, required this.email, this.picUrl, + this.birthDate, this.locale, + this.phone, }); factory UserEntity.fromJson(Map json) { return UserEntity( - id: json['id'], - name: json['name'], - email: json['email'], + id: json['id'] ?? '', + name: json['name'] ?? '', + email: json['email'] ?? '', picUrl: json['pic_url'], + birthDate: json['birth_date'], locale: json['locale'], + phone: json['phone'], ); } @@ -29,6 +35,7 @@ UserEntity({ 'name': name, 'email': email, 'pic_url': picUrl, + 'birth_date': birthDate, 'locale': locale, }; } diff --git a/lib/data/models/user/user_full_model.dart b/lib/data/models/user/user_full_model.dart new file mode 100644 index 0000000..46f6ad6 --- /dev/null +++ b/lib/data/models/user/user_full_model.dart @@ -0,0 +1,55 @@ +class UserFullModel { + final String id; + final String googleId; + final String email; + final String name; + final String birthDate; + final String picUrl; + final String phone; + final String locale; + final String createdAt; + final String updatedAt; + + UserFullModel({ + required this.id, + required this.googleId, + required this.email, + required this.name, + required this.birthDate, + required this.picUrl, + required this.phone, + required this.locale, + required this.createdAt, + required this.updatedAt, + }); + + factory UserFullModel.fromJson(Map json) { + return UserFullModel( + id: json['id'] ?? '', + googleId: json['google_id'] ?? '', + email: json['email'] ?? '', + name: json['name'] ?? '', + birthDate: json['birth_date'] ?? '', + picUrl: json['pic_url'] ?? '', + phone: json['phone'] ?? '', + locale: json['locale'] ?? '', + createdAt: json['created_at'] ?? '', + updatedAt: json['updated_at'] ?? '', + ); + } + + Map toJson() { + return { + 'id': id, + 'google_id': googleId, + 'email': email, + 'name': name, + 'birth_date': birthDate, + 'pic_url': picUrl, + 'phone': phone, + 'locale': locale, + 'created_at': createdAt, + 'updated_at': updatedAt, + }; + } +} diff --git a/lib/data/services/user_service.dart b/lib/data/services/user_service.dart new file mode 100644 index 0000000..6c5e9e3 --- /dev/null +++ b/lib/data/services/user_service.dart @@ -0,0 +1,57 @@ +import 'package:dio/dio.dart'; +import 'package:get/get.dart'; +import 'package:quiz_app/core/endpoint/api_endpoint.dart'; +import 'package:quiz_app/core/utils/logger.dart'; +import 'package:quiz_app/data/models/base/base_model.dart'; +import 'package:quiz_app/data/models/user/user_full_model.dart'; +import 'package:quiz_app/data/providers/dio_client.dart'; + +class UserService extends GetxService { + late final Dio _dio; + + @override + void onInit() { + _dio = Get.find().dio; + super.onInit(); + } + + Future updateProfileData(String id, String name, {String? birthDate, String? locale, String? phone}) async { + try { + final response = await _dio.post(APIEndpoint.userUpdate, data: { + "id": id, + "name": name, + "birth_date": birthDate, + "locale": locale, + "phone": phone, + }); + + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } catch (e) { + logC.e("update profile error: $e"); + return false; + } + } + + Future?> getUserData(String id) async { + try { + final response = await _dio.get("${APIEndpoint.userData}/$id"); + + if (response.statusCode == 200) { + final parsedResponse = BaseResponseModel.fromJson( + response.data, + (data) => UserFullModel.fromJson(data), + ); + return parsedResponse; + } else { + return null; + } + } catch (e) { + logC.e("get user data error: $e"); + return null; + } + } +} diff --git a/lib/feature/profile/binding/update_profile_binding.dart b/lib/feature/profile/binding/update_profile_binding.dart index 505a59d..db18f20 100644 --- a/lib/feature/profile/binding/update_profile_binding.dart +++ b/lib/feature/profile/binding/update_profile_binding.dart @@ -1,9 +1,17 @@ import 'package:get/get.dart'; +import 'package:quiz_app/data/controllers/user_controller.dart'; +import 'package:quiz_app/data/services/user_service.dart'; +import 'package:quiz_app/data/services/user_storage_service.dart'; import 'package:quiz_app/feature/profile/controller/update_profile_controller.dart'; class UpdateProfileBinding extends Bindings { @override void dependencies() { - Get.lazyPut(() => UpdateProfileController()); + Get.lazyPut(() => UserService()); + Get.lazyPut(() => UpdateProfileController( + Get.find(), + Get.find(), + Get.find(), + )); } } diff --git a/lib/feature/profile/controller/update_profile_controller.dart b/lib/feature/profile/controller/update_profile_controller.dart index 2684083..8f4ce8b 100644 --- a/lib/feature/profile/controller/update_profile_controller.dart +++ b/lib/feature/profile/controller/update_profile_controller.dart @@ -1,20 +1,108 @@ import 'package:flutter/material.dart'; - import 'package:get/get.dart'; +import 'package:quiz_app/core/utils/custom_floating_loading.dart'; +import 'package:quiz_app/core/utils/custom_notification.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/services/user_service.dart'; +import 'package:quiz_app/data/services/user_storage_service.dart'; class UpdateProfileController extends GetxController { + final UserController _userController; + final UserStorageService _userStorageService; + final UserService _userService; + + UpdateProfileController( + this._userService, + this._userController, + this._userStorageService, + ); + final nameController = TextEditingController(); final phoneController = TextEditingController(); final birthDateController = TextEditingController(); var selectedLocale = 'en-US'.obs; + final Map localeMap = { 'English': 'en-US', 'Indonesian': 'id-ID', 'French': 'fr-FR', 'Spanish': 'es-ES', }; - void saveProfile() { - Get.snackbar('Success', 'Profile updated successfully'); + + @override + void onInit() { + final userData = _userController.userData!; + nameController.text = userData.name; + phoneController.text = userData.phone ?? ''; + birthDateController.text = userData.birthDate ?? ''; + super.onInit(); + } + + bool _validateInputs() { + final name = nameController.text.trim(); + final phone = phoneController.text.trim(); + final birthDate = birthDateController.text.trim(); + print(birthDate); + + if (name.isEmpty || phone.isEmpty || birthDate.isEmpty) { + Get.snackbar('Validation Error', 'All fields must be filled.', snackPosition: SnackPosition.TOP); + return false; + } + + if (!_isValidDateFormat(birthDate)) { + Get.snackbar('Validation Error', 'birth date must valid.', snackPosition: SnackPosition.TOP); + return false; + } + return true; + } + + Future saveProfile() async { + if (!_validateInputs()) return; + + CustomFloatingLoading.showLoadingDialog(Get.context!); + + final isSuccessUpdate = await _userService.updateProfileData( + _userController.userData!.id, + nameController.text.trim(), + birthDate: birthDateController.text.trim(), + phone: phoneController.text.trim(), + locale: selectedLocale.value, + ); + + if (isSuccessUpdate) { + final response = await _userService.getUserData(_userController.userData!.id); + + if (response?.data != null) { + final userNew = response!.data!; + final newUser = UserEntity( + id: userNew.id, + email: userNew.email, + name: userNew.name, + birthDate: userNew.birthDate, + locale: userNew.locale, + picUrl: userNew.picUrl, + phone: userNew.phone, + ); + + _userStorageService.saveUser(newUser); + _userController.userData = newUser; + + _userController.email.value = userNew.email; + _userController.userName.value = userNew.name; + _userController.userImage.value = userNew.picUrl; + } + } + + Get.back(); + + CustomNotification.success(title: "Success", message: "Profile updated successfully"); + CustomFloatingLoading.hideLoadingDialog(Get.context!); + } + + bool _isValidDateFormat(String date) { + final regex = RegExp(r'^([0-2][0-9]|(3)[0-1])\-((0[1-9])|(1[0-2]))\-\d{4}$'); + return regex.hasMatch(date); } }