feat: done working on the profile update

This commit is contained in:
akhdanre 2025-05-18 21:20:20 +07:00
parent 175f4e6668
commit 1c6ce0d023
6 changed files with 226 additions and 8 deletions

View File

@ -22,4 +22,7 @@ class APIEndpoint {
static const String subject = "/subject"; static const String subject = "/subject";
static const String session = "/session"; static const String session = "/session";
static const String userData = "/user";
static const String userUpdate = "/user/update";
} }

View File

@ -3,23 +3,29 @@ class UserEntity {
final String name; final String name;
final String email; final String email;
final String? picUrl; final String? picUrl;
final String? birthDate;
final String? locale; final String? locale;
final String? phone;
UserEntity({ UserEntity({
required this.id, required this.id,
required this.name, required this.name,
required this.email, required this.email,
this.picUrl, this.picUrl,
this.birthDate,
this.locale, this.locale,
this.phone,
}); });
factory UserEntity.fromJson(Map<String, dynamic> json) { factory UserEntity.fromJson(Map<String, dynamic> json) {
return UserEntity( return UserEntity(
id: json['id'], id: json['id'] ?? '',
name: json['name'], name: json['name'] ?? '',
email: json['email'], email: json['email'] ?? '',
picUrl: json['pic_url'], picUrl: json['pic_url'],
birthDate: json['birth_date'],
locale: json['locale'], locale: json['locale'],
phone: json['phone'],
); );
} }
@ -29,6 +35,7 @@ UserEntity({
'name': name, 'name': name,
'email': email, 'email': email,
'pic_url': picUrl, 'pic_url': picUrl,
'birth_date': birthDate,
'locale': locale, 'locale': locale,
}; };
} }

View File

@ -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<String, dynamic> 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<String, dynamic> 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,
};
}
}

View File

@ -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<ApiClient>().dio;
super.onInit();
}
Future<bool> 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<BaseResponseModel<UserFullModel>?> getUserData(String id) async {
try {
final response = await _dio.get("${APIEndpoint.userData}/$id");
if (response.statusCode == 200) {
final parsedResponse = BaseResponseModel<UserFullModel>.fromJson(
response.data,
(data) => UserFullModel.fromJson(data),
);
return parsedResponse;
} else {
return null;
}
} catch (e) {
logC.e("get user data error: $e");
return null;
}
}
}

View File

@ -1,9 +1,17 @@
import 'package:get/get.dart'; 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'; import 'package:quiz_app/feature/profile/controller/update_profile_controller.dart';
class UpdateProfileBinding extends Bindings { class UpdateProfileBinding extends Bindings {
@override @override
void dependencies() { void dependencies() {
Get.lazyPut(() => UpdateProfileController()); Get.lazyPut(() => UserService());
Get.lazyPut(() => UpdateProfileController(
Get.find<UserService>(),
Get.find<UserController>(),
Get.find<UserStorageService>(),
));
} }
} }

View File

@ -1,20 +1,108 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.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 { class UpdateProfileController extends GetxController {
final UserController _userController;
final UserStorageService _userStorageService;
final UserService _userService;
UpdateProfileController(
this._userService,
this._userController,
this._userStorageService,
);
final nameController = TextEditingController(); final nameController = TextEditingController();
final phoneController = TextEditingController(); final phoneController = TextEditingController();
final birthDateController = TextEditingController(); final birthDateController = TextEditingController();
var selectedLocale = 'en-US'.obs; var selectedLocale = 'en-US'.obs;
final Map<String, String> localeMap = { final Map<String, String> localeMap = {
'English': 'en-US', 'English': 'en-US',
'Indonesian': 'id-ID', 'Indonesian': 'id-ID',
'French': 'fr-FR', 'French': 'fr-FR',
'Spanish': 'es-ES', '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<void> 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);
} }
} }