Tambahkan fungsionalitas pendaftaran donatur baru tanpa konfirmasi email di AuthProvider. Perbarui model DonaturModel untuk menyertakan properti isManual. Modifikasi tampilan dan controller untuk mendukung registrasi donatur, termasuk validasi form dan navigasi ke halaman pendaftaran. Perbarui rute aplikasi untuk menambahkan halaman pendaftaran donatur. Selain itu, perbarui beberapa file konfigurasi dan dependensi untuk mendukung perubahan ini.

This commit is contained in:
Khafidh Fuadi
2025-03-26 14:39:12 +07:00
parent eede5ebd4d
commit f74c058c71
31 changed files with 2454 additions and 960 deletions

View File

@ -77,6 +77,12 @@ class AuthController extends GetxController {
void onClose() {
// Pastikan semua controller dibersihkan sebelum dilepaskan
clearAndDisposeControllers();
// Dispose controller registrasi donatur
confirmPasswordController.dispose();
namaController.dispose();
alamatController.dispose();
noHpController.dispose();
jenisController.dispose();
super.onClose();
}
@ -361,21 +367,13 @@ class AuthController extends GetxController {
// Validasi konfirmasi password
String? validateConfirmPassword(String? value) {
try {
if (value == null || value.isEmpty) {
return 'Konfirmasi password tidak boleh kosong';
}
// Ambil nilai password dari controller jika tersedia
final password = passwordController.text;
if (value != password) {
return 'Password dan konfirmasi password tidak sama';
}
return null;
} catch (e) {
print('Error validating confirm password: $e');
return 'Terjadi kesalahan saat validasi';
if (value == null || value.isEmpty) {
return 'Konfirmasi password tidak boleh kosong';
}
if (value != passwordController.text) {
return 'Password dan konfirmasi password tidak sama';
}
return null;
}
// Metode untuk refresh data user setelah update profil
@ -419,4 +417,130 @@ class AuthController extends GetxController {
return Routes.home;
}
}
// Metode untuk validasi form registrasi donatur
String? validateDonaturNama(String? value) {
if (value == null || value.isEmpty) {
return 'Nama lengkap tidak boleh kosong';
}
return null;
}
String? validateDonaturNoHp(String? value) {
if (value == null || value.isEmpty) {
return 'Nomor HP tidak boleh kosong';
}
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
return 'Nomor HP hanya boleh berisi angka';
}
return null;
}
String? validateDonaturAlamat(String? value) {
if (value == null || value.isEmpty) {
return 'Alamat tidak boleh kosong';
}
return null;
}
// Form controller untuk registrasi donatur
final TextEditingController namaController = TextEditingController();
final TextEditingController alamatController = TextEditingController();
final TextEditingController noHpController = TextEditingController();
final TextEditingController jenisController = TextEditingController();
// Form key untuk registrasi donatur
final GlobalKey<FormState> registerDonaturFormKey = GlobalKey<FormState>();
// Metode untuk registrasi donatur
Future<void> registerDonatur() async {
print('DEBUG: Memulai proses registrasi donatur');
if (registerDonaturFormKey.currentState == null) {
print('Error: registerDonaturFormKey.currentState adalah null');
Get.snackbar(
'Error',
'Terjadi kesalahan pada form registrasi. Silakan coba lagi.',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
return;
}
if (!registerDonaturFormKey.currentState!.validate()) {
print('DEBUG: Validasi form gagal');
return;
}
isLoading.value = true;
try {
// Proses registrasi donatur dengan role_id 3
await _authProvider.signUpDonatur(
email: emailController.text,
password: passwordController.text,
namaLengkap: namaController.text,
alamat: alamatController.text,
noHp: noHpController.text,
jenis: jenisController.text.isEmpty ? 'Individu' : jenisController.text,
);
Get.snackbar(
'Sukses',
'Registrasi donatur berhasil! Silakan login dengan akun Anda.',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.green,
colorText: Colors.white,
duration: const Duration(seconds: 5),
);
// Bersihkan form
clearDonaturRegistrationForm();
// Arahkan ke halaman login
Get.offAllNamed(Routes.login);
} catch (e) {
print('Error registrasi donatur: $e');
String errorMessage = 'Gagal melakukan registrasi';
// Tangani error sesuai jenisnya
if (e.toString().contains('email konfirmasi')) {
errorMessage =
'Gagal mengirim email konfirmasi. Mohon periksa alamat email Anda dan coba lagi nanti.';
} else if (e.toString().contains('Email sudah terdaftar')) {
errorMessage =
'Email sudah terdaftar. Silakan gunakan email lain atau login dengan email tersebut.';
} else if (e.toString().contains('weak-password')) {
errorMessage =
'Password terlalu lemah. Gunakan kombinasi huruf, angka, dan simbol.';
} else if (e.toString().contains('invalid-email')) {
errorMessage = 'Format email tidak valid.';
} else {
errorMessage = 'Gagal melakukan registrasi: ${e.toString()}';
}
Get.snackbar(
'Error',
errorMessage,
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
duration: const Duration(seconds: 5),
);
} finally {
isLoading.value = false;
}
}
// Metode untuk membersihkan form registrasi donatur
void clearDonaturRegistrationForm() {
emailController.clear();
passwordController.clear();
confirmPasswordController.clear();
namaController.clear();
alamatController.clear();
noHpController.clear();
jenisController.clear();
}
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart';
import 'package:penyaluran_app/app/routes/app_pages.dart';
class LoginView extends GetView<AuthController> {
const LoginView({super.key});
@ -109,6 +110,39 @@ class LoginView extends GetView<AuthController> {
),
)),
const SizedBox(height: 20),
// Divider
const Row(
children: [
Expanded(child: Divider()),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child:
Text('ATAU', style: TextStyle(color: Colors.grey)),
),
Expanded(child: Divider()),
],
),
const SizedBox(height: 20),
// Register Donatur Button
OutlinedButton(
onPressed: () => Get.toNamed(Routes.registerDonatur),
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
side: const BorderSide(color: Colors.blue),
),
child: const Text(
'DAFTAR SEBAGAI DONATUR',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
],
),
),

View File

@ -0,0 +1,214 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart';
import 'package:penyaluran_app/app/routes/app_pages.dart';
class RegisterDonaturView extends GetView<AuthController> {
const RegisterDonaturView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Daftar Sebagai Donatur'),
elevation: 0,
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
child: Form(
key: controller.registerDonaturFormKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 20),
// Logo atau Judul
const Center(
child: Text(
'Daftar Donatur',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
),
const SizedBox(height: 10),
const Center(
child: Text(
'Isi data untuk mendaftar sebagai donatur',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
),
const SizedBox(height: 30),
// Nama Lengkap
TextFormField(
controller: controller.namaController,
keyboardType: TextInputType.name,
decoration: InputDecoration(
labelText: 'Nama Lengkap',
prefixIcon: const Icon(Icons.person),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
validator: controller.validateDonaturNama,
),
const SizedBox(height: 15),
// Email
TextFormField(
controller: controller.emailController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: const Icon(Icons.email),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
validator: controller.validateEmail,
),
const SizedBox(height: 15),
// Password
TextFormField(
controller: controller.passwordController,
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: const Icon(Icons.lock),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
validator: controller.validatePassword,
),
const SizedBox(height: 15),
// Confirm Password
TextFormField(
controller: controller.confirmPasswordController,
obscureText: true,
decoration: InputDecoration(
labelText: 'Konfirmasi Password',
prefixIcon: const Icon(Icons.lock_outline),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
validator: controller.validateConfirmPassword,
),
const SizedBox(height: 15),
// No HP
TextFormField(
controller: controller.noHpController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: 'Nomor HP',
prefixIcon: const Icon(Icons.phone),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
validator: controller.validateDonaturNoHp,
),
const SizedBox(height: 15),
// Alamat
TextFormField(
controller: controller.alamatController,
keyboardType: TextInputType.streetAddress,
maxLines: 2,
decoration: InputDecoration(
labelText: 'Alamat',
prefixIcon: const Icon(Icons.home),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
validator: controller.validateDonaturAlamat,
),
const SizedBox(height: 15),
// Jenis Donatur (Dropdown)
DropdownButtonFormField<String>(
value: controller.jenisController.text.isEmpty
? 'Individu'
: controller.jenisController.text,
decoration: InputDecoration(
labelText: 'Jenis Donatur',
prefixIcon: const Icon(Icons.category),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
items: const [
DropdownMenuItem(
value: 'Individu', child: Text('Individu')),
DropdownMenuItem(
value: 'Organisasi', child: Text('Organisasi')),
DropdownMenuItem(
value: 'Perusahaan', child: Text('Perusahaan')),
DropdownMenuItem(
value: 'Lainnya', child: Text('Lainnya')),
],
onChanged: (value) {
controller.jenisController.text = value ?? 'Individu';
},
),
const SizedBox(height: 15),
// Register Button
Obx(() => ElevatedButton(
onPressed: controller.isLoading.value
? null
: controller.registerDonatur,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: controller.isLoading.value
? const SpinKitThreeBounce(
color: Colors.white,
size: 24,
)
: const Text(
'DAFTAR',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
)),
const SizedBox(height: 20),
// Login Link
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Sudah punya akun?'),
TextButton(
onPressed: () => Get.offAllNamed(Routes.login),
child: const Text('Masuk'),
),
],
),
],
),
),
),
),
),
);
}
}