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:
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
214
lib/app/modules/auth/views/register_donatur_view.dart
Normal file
214
lib/app/modules/auth/views/register_donatur_view.dart
Normal 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'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user