Feat: done implementation edit data for features change noId

This commit is contained in:
orangdeso 2025-05-26 01:00:30 +07:00
parent b0eb48cbfe
commit a44530f51d
8 changed files with 178 additions and 36 deletions

View File

@ -10,6 +10,14 @@ class SnackbarHelper {
message, message,
backgroundColor: GreenColors.green500, backgroundColor: GreenColors.green500,
colorText: Colors.white, colorText: Colors.white,
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
margin: EdgeInsets.all(10),
borderRadius: 8,
isDismissible: true,
forwardAnimationCurve: Curves.easeOutBack,
reverseAnimationCurve: Curves.easeInBack,
animationDuration: Duration(milliseconds: 800),
); );
} }
@ -19,6 +27,14 @@ class SnackbarHelper {
message, message,
backgroundColor: Colors.red, backgroundColor: Colors.red,
colorText: Colors.white, colorText: Colors.white,
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
margin: EdgeInsets.all(10),
borderRadius: 8,
isDismissible: true,
forwardAnimationCurve: Curves.easeOutBack,
reverseAnimationCurve: Curves.easeInBack,
animationDuration: Duration(milliseconds: 800),
); );
} }
@ -26,6 +42,14 @@ class SnackbarHelper {
Get.snackbar( Get.snackbar(
title, title,
message, message,
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
margin: EdgeInsets.all(10),
borderRadius: 8,
isDismissible: true,
forwardAnimationCurve: Curves.easeOutBack,
reverseAnimationCurve: Curves.easeInBack,
animationDuration: Duration(milliseconds: 800),
); );
} }
} }

View File

@ -27,10 +27,7 @@ class ProfilRepositoryImpl implements ProfilRepository {
try { try {
QuerySnapshot querySnapshot = await _firestore.collection('users').doc(userId).collection('passenger').get(); QuerySnapshot querySnapshot = await _firestore.collection('users').doc(userId).collection('passenger').get();
return querySnapshot.docs return querySnapshot.docs
.map((doc) => PassengerModel.fromMap({ .map((doc) => PassengerModel.fromMap({'id': doc.id, ...doc.data() as Map<String, dynamic>}))
'id': doc.id,
...doc.data() as Map<String, dynamic>
}))
.toList(); .toList();
} catch (e) { } catch (e) {
rethrow; rethrow;
@ -50,6 +47,7 @@ class ProfilRepositoryImpl implements ProfilRepository {
rethrow; rethrow;
} }
} }
@override @override
Future<UserData> getUserById(String userId) async { Future<UserData> getUserById(String userId) async {
try { try {
@ -119,6 +117,52 @@ class ProfilRepositoryImpl implements ProfilRepository {
await _firestore.collection('users').doc(user.uid).update({'phone': newPhone}); await _firestore.collection('users').doc(user.uid).update({'phone': newPhone});
} }
@override
Future<void> changeNoId({
required String oldPassword,
required String typeId,
required String noId,
}) async {
final user = FirebaseAuth.instance.currentUser;
if (user == null) {
throw Exception("User belum login");
}
final existingUserQuery =
await _firestore.collection('users').where('typeId', isEqualTo: typeId).where('noId', isEqualTo: noId).get();
if (existingUserQuery.docs.isNotEmpty) {
final isCurrentUser = existingUserQuery.docs.any((doc) => doc.id == user.uid);
if (!isCurrentUser) {
throw Exception("Nomor ID sudah digunakan oleh pengguna lain");
}
}
final allUsersQuery = await _firestore.collection('users').get();
for (final userDoc in allUsersQuery.docs) {
final passengerQuery = await _firestore
.collection('users')
.doc(userDoc.id)
.collection('passenger')
.where('typeId', isEqualTo: typeId)
.where('noId', isEqualTo: noId)
.get();
if (passengerQuery.docs.isNotEmpty) {
throw Exception("Nomor ID sudah digunakan oleh pengguna lain");
}
}
final cred = EmailAuthProvider.credential(
email: user.email!,
password: oldPassword,
);
await user.reauthenticateWithCredential(cred);
await _firestore.collection('users').doc(user.uid).update({
'typeId': typeId,
'noId': noId,
});
}
// @override // @override
// Future<void> changeEmail({ // Future<void> changeEmail({
// required String oldPassword, // required String oldPassword,

View File

@ -15,6 +15,7 @@ class ProfilBinding extends Bindings {
Get.lazyPut(() => GetUserByIdUseCase(Get.find())); Get.lazyPut(() => GetUserByIdUseCase(Get.find()));
Get.lazyPut(() => ChangePasswordUseCase(Get.find())); Get.lazyPut(() => ChangePasswordUseCase(Get.find()));
Get.lazyPut(() => ChangePhoneUseCase(Get.find())); Get.lazyPut(() => ChangePhoneUseCase(Get.find()));
Get.lazyPut(() => ChangeNoIdUseCase(Get.find()));
Get.lazyPut(() => DeletePassengerUseCase(Get.find())); Get.lazyPut(() => DeletePassengerUseCase(Get.find()));
Get.lazyPut(() => UpdatePassengerUseCase(Get.find())); Get.lazyPut(() => UpdatePassengerUseCase(Get.find()));
// Get.lazyPut(() => ChangeEmailUseCase(Get.find())); // Get.lazyPut(() => ChangeEmailUseCase(Get.find()));
@ -26,6 +27,7 @@ class ProfilBinding extends Bindings {
getUserByIdUseCase: Get.find(), getUserByIdUseCase: Get.find(),
changePasswordUseCase: Get.find(), changePasswordUseCase: Get.find(),
changePhoneUseCase: Get.find(), changePhoneUseCase: Get.find(),
changeNoIdUseCase: Get.find(),
deletePassengerUseCase: Get.find(), deletePassengerUseCase: Get.find(),
updatePassengerUseCase: Get.find(), updatePassengerUseCase: Get.find(),
), ),

View File

@ -31,6 +31,12 @@ abstract class ProfilRepository {
required String newPhone, required String newPhone,
}); });
Future<void> changeNoId({
required String oldPassword,
required String typeId,
required String noId,
});
// Future<void> changeEmail({ // Future<void> changeEmail({
// required String oldPassword, // required String oldPassword,
// required String newEmail, // required String newEmail,

View File

@ -64,6 +64,23 @@ class ChangePhoneUseCase {
} }
} }
class ChangeNoIdUseCase {
final ProfilRepository profilRepository;
ChangeNoIdUseCase(this.profilRepository);
Future<void> call({
required String oldPassword,
required String typeId,
required String noId,
}) {
return profilRepository.changeNoId(
oldPassword: oldPassword,
typeId: typeId,
noId: noId,
);
}
}
class DeletePassengerUseCase { class DeletePassengerUseCase {
final ProfilRepository profilRepository; final ProfilRepository profilRepository;
DeletePassengerUseCase(this.profilRepository); DeletePassengerUseCase(this.profilRepository);

View File

@ -3,7 +3,6 @@ import 'package:e_porter/_core/service/preferences_service.dart';
import 'package:e_porter/_core/utils/snackbar/snackbar_helper.dart'; import 'package:e_porter/_core/utils/snackbar/snackbar_helper.dart';
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../domain/models/user_entity.dart'; import '../../domain/models/user_entity.dart';
import '../../domain/usecases/profil_usecase.dart'; import '../../domain/usecases/profil_usecase.dart';
@ -13,6 +12,7 @@ class ProfilController extends GetxController {
final GetUserByIdUseCase getUserByIdUseCase; final GetUserByIdUseCase getUserByIdUseCase;
final ChangePasswordUseCase changePasswordUseCase; final ChangePasswordUseCase changePasswordUseCase;
final ChangePhoneUseCase changePhoneUseCase; final ChangePhoneUseCase changePhoneUseCase;
final ChangeNoIdUseCase changeNoIdUseCase;
final DeletePassengerUseCase deletePassengerUseCase; final DeletePassengerUseCase deletePassengerUseCase;
final UpdatePassengerUseCase updatePassengerUseCase; final UpdatePassengerUseCase updatePassengerUseCase;
// final ChangeEmailUseCase changeEmailUseCase; // final ChangeEmailUseCase changeEmailUseCase;
@ -22,6 +22,7 @@ class ProfilController extends GetxController {
var isLoading = false.obs; var isLoading = false.obs;
var isChangingPassword = false.obs; var isChangingPassword = false.obs;
var isChangingPhone = false.obs; var isChangingPhone = false.obs;
var isChangingNoId = false.obs;
var isDeletingPassenger = false.obs; var isDeletingPassenger = false.obs;
var isUpdatingPassenger = false.obs; var isUpdatingPassenger = false.obs;
// var isChangingEmail = false.obs; // var isChangingEmail = false.obs;
@ -32,6 +33,7 @@ class ProfilController extends GetxController {
required this.getUserByIdUseCase, required this.getUserByIdUseCase,
required this.changePasswordUseCase, required this.changePasswordUseCase,
required this.changePhoneUseCase, required this.changePhoneUseCase,
required this.changeNoIdUseCase,
required this.deletePassengerUseCase, required this.deletePassengerUseCase,
required this.updatePassengerUseCase, required this.updatePassengerUseCase,
// required this.changeEmailUseCase, // required this.changeEmailUseCase,
@ -206,6 +208,42 @@ class ProfilController extends GetxController {
} }
} }
Future<bool> changeNoId({
required String oldPassword,
required String typeId,
required String noId,
}) async {
isChangingNoId.value = true;
try {
await changeNoIdUseCase(
oldPassword: oldPassword,
typeId: typeId,
noId: noId,
);
await _loadProfile();
SnackbarHelper.showSuccess("Berhasil", "Nomor ID berhasil diperbarui.");
return true;
} on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password' || e.code == 'invalid-credential') {
SnackbarHelper.showError("Gagal", "Password lama salah.");
} else {
SnackbarHelper.showError("Gagal", e.message ?? "Terjadi kesalahan.");
}
return false;
} catch (e) {
if (e.toString().contains("Nomor ID sudah digunakan oleh pengguna lain")) {
SnackbarHelper.showError("Gagal", "Nomor ID sudah digunakan oleh pengguna lain.");
} else {
SnackbarHelper.showError("Gagal", "Terjadi kesalahan: $e");
}
return false;
} finally {
isChangingNoId.value = false;
}
}
// Future<bool> changeEmail({ // Future<bool> changeEmail({
// required String oldPassword, // required String oldPassword,
// required String newEmail, // required String newEmail,

View File

@ -1,4 +1,6 @@
import 'package:e_porter/_core/component/appbar/appbar_component.dart'; import 'package:e_porter/_core/component/appbar/appbar_component.dart';
import 'package:e_porter/_core/component/button/button_fill.dart';
import 'package:e_porter/_core/component/card/custome_shadow_cotainner.dart';
import 'package:e_porter/_core/component/text/custom_text.dart'; import 'package:e_porter/_core/component/text/custom_text.dart';
import 'package:e_porter/_core/component/text_field/dropdown/dropdown_component.dart'; import 'package:e_porter/_core/component/text_field/dropdown/dropdown_component.dart';
import 'package:e_porter/_core/component/text_field/text_input/text_field_component.dart'; import 'package:e_porter/_core/component/text_field/text_input/text_field_component.dart';
@ -7,6 +9,7 @@ import 'package:e_porter/_core/constants/typography.dart';
import 'package:e_porter/_core/validators/validators.dart'; import 'package:e_porter/_core/validators/validators.dart';
import 'package:e_porter/presentation/screens/auth/component/Input_password.dart'; import 'package:e_porter/presentation/screens/auth/component/Input_password.dart';
import 'package:e_porter/presentation/screens/profile/component/header_information.dart'; import 'package:e_porter/presentation/screens/profile/component/header_information.dart';
import 'package:e_porter/presentation/controllers/profil_controller.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -23,6 +26,7 @@ class _ChangeNoIdState extends State<ChangeNoId> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _oldPassword = TextEditingController(); final _oldPassword = TextEditingController();
final _noIdController = TextEditingController(); final _noIdController = TextEditingController();
final ProfilController _profilController = Get.find<ProfilController>();
String selectedTypeId = 'KTP'; String selectedTypeId = 'KTP';
@override @override
@ -109,31 +113,38 @@ class _ChangeNoIdState extends State<ChangeNoId> {
), ),
), ),
), ),
// bottomNavigationBar: Obx( bottomNavigationBar: Obx(() {
// () { return CustomeShadowCotainner(
// return CustomeShadowCotainner( child: _profilController.isChangingNoId.value
// child: _authController.isChangingPhone.value ? Center(
// ? Center( child: CircularProgressIndicator(color: PrimaryColors.primary800),
// child: CircularProgressIndicator(color: PrimaryColors.primary800), )
// ) : ButtonFill(
// : ButtonFill( text: 'Simpan',
// text: 'Simpan', textColor: Colors.white,
// textColor: Colors.white, onTap: () async {
// onTap: () async { if (!_formKey.currentState!.validate()) return;
// if (!_formKey.currentState!.validate()) return; final result = await _profilController.changeNoId(
// final result = await _authController.changePhone( oldPassword: _oldPassword.text.trim(),
// oldPassword: _oldPassword.text.trim(), noId: _noIdController.text.trim(),
// newPhone: _phoneNumber.text.trim(), typeId: selectedTypeId);
// );
// if (result) { if (result) {
// _oldPassword.clear(); _oldPassword.clear();
// _phoneNumber.clear(); _noIdController.clear();
// }
// }, await Future.delayed(Duration(milliseconds: 1500));
// ),
// ); if (Get.isSnackbarOpen) {
// }, Get.closeAllSnackbars();
// ), await Future.delayed(Duration(milliseconds: 300));
}
Get.back();
}
},
),
);
}),
); );
} }
} }

View File

@ -20,7 +20,7 @@ class ChangeNumberScreen extends StatefulWidget {
} }
class _ChangeNumberScreenState extends State<ChangeNumberScreen> { class _ChangeNumberScreenState extends State<ChangeNumberScreen> {
final _authController = Get.find<ProfilController>(); final _profilController = Get.find<ProfilController>();
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _oldPassword = TextEditingController(); final _oldPassword = TextEditingController();
final _phoneNumber = TextEditingController(); final _phoneNumber = TextEditingController();
@ -78,7 +78,7 @@ class _ChangeNumberScreenState extends State<ChangeNumberScreen> {
bottomNavigationBar: Obx( bottomNavigationBar: Obx(
() { () {
return CustomeShadowCotainner( return CustomeShadowCotainner(
child: _authController.isChangingPhone.value child: _profilController.isChangingPhone.value
? Center( ? Center(
child: CircularProgressIndicator(color: PrimaryColors.primary800), child: CircularProgressIndicator(color: PrimaryColors.primary800),
) )
@ -87,7 +87,7 @@ class _ChangeNumberScreenState extends State<ChangeNumberScreen> {
textColor: Colors.white, textColor: Colors.white,
onTap: () async { onTap: () async {
if (!_formKey.currentState!.validate()) return; if (!_formKey.currentState!.validate()) return;
final result = await _authController.changePhone( final result = await _profilController.changePhone(
oldPassword: _oldPassword.text.trim(), oldPassword: _oldPassword.text.trim(),
newPhone: _phoneNumber.text.trim(), newPhone: _phoneNumber.text.trim(),
); );