Perbarui model Pengaduan dengan menambahkan getter isUang untuk memeriksa jenis bantuan. Modifikasi tampilan dan controller di modul donatur dan petugas desa untuk meningkatkan pengalaman pengguna, termasuk penggantian ikon dan penyesuaian format tampilan jumlah bantuan. Hapus kode yang tidak diperlukan untuk menjaga kebersihan kode.
This commit is contained in:
@ -537,62 +537,114 @@ class AuthController extends GetxController {
|
||||
}
|
||||
|
||||
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),
|
||||
);
|
||||
// Kita akan mencoba maksimal 2 kali jika terjadi error
|
||||
int maxAttempts = 2;
|
||||
int attempt = 0;
|
||||
bool success = false;
|
||||
Exception? lastError;
|
||||
|
||||
// Bersihkan form
|
||||
clearDonaturRegistrationForm();
|
||||
while (attempt < maxAttempts && !success) {
|
||||
attempt++;
|
||||
print(
|
||||
'DEBUG: Mencoba pendaftaran donatur (percobaan ke-$attempt dari $maxAttempts)');
|
||||
|
||||
// Arahkan ke halaman login
|
||||
Get.offAllNamed(Routes.login);
|
||||
} catch (e) {
|
||||
print('Error registrasi donatur: $e');
|
||||
try {
|
||||
print('DEBUG: Validasi form berhasil, melanjutkan proses registrasi');
|
||||
print('DEBUG: Email: ${emailController.text}');
|
||||
print('DEBUG: Nama: ${namaController.text}');
|
||||
print('DEBUG: Alamat: ${alamatController.text}');
|
||||
print('DEBUG: No HP: ${noHpController.text}');
|
||||
print(
|
||||
'DEBUG: Jenis: ${jenisController.text.isEmpty ? 'Individu' : jenisController.text}');
|
||||
|
||||
String errorMessage = 'Gagal melakukan registrasi';
|
||||
// Proses registrasi donatur
|
||||
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,
|
||||
);
|
||||
|
||||
// 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()}';
|
||||
print('DEBUG: Registrasi donatur berhasil');
|
||||
success = true;
|
||||
|
||||
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) {
|
||||
lastError = e is Exception ? e : Exception(e.toString());
|
||||
print('ERROR: Error registrasi donatur (percobaan ke-$attempt): $e');
|
||||
print('ERROR Detail: ${e.runtimeType} - ${e.toString()}');
|
||||
|
||||
// Cek apakah bisa dicoba lagi atau tidak
|
||||
bool canRetry = false;
|
||||
if (e.toString().contains('Database error saving new user')) {
|
||||
canRetry = true; // Error database bisa dicoba lagi
|
||||
print('DEBUG: Error database, akan mencoba lagi');
|
||||
// Delay sedikit sebelum mencoba lagi
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
} else if (e.toString().contains('User already registered')) {
|
||||
// Jangan coba lagi jika email sudah terdaftar
|
||||
canRetry = false;
|
||||
}
|
||||
|
||||
if (!canRetry || attempt >= maxAttempts) {
|
||||
// Jika tidak bisa retry atau sudah maksimal, tampilkan error
|
||||
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 if (e.toString().contains('Database error')) {
|
||||
errorMessage =
|
||||
'Terjadi kesalahan pada database. Silakan coba lagi nanti atau hubungi administrator.';
|
||||
} else {
|
||||
errorMessage = 'Gagal melakukan registrasi: ${e.toString()}';
|
||||
}
|
||||
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
errorMessage,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
duration: const Duration(seconds: 7),
|
||||
);
|
||||
break; // Keluar dari loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
errorMessage,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
duration: const Duration(seconds: 5),
|
||||
);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
isLoading.value = false;
|
||||
|
||||
// Jika gagal setelah mencoba beberapa kali
|
||||
if (!success && lastError != null) {
|
||||
print('ERROR: Pendaftaran gagal setelah $attempt percobaan');
|
||||
// Error sudah ditampilkan di dalam loop
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ 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';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
|
||||
class RegisterDonaturView extends GetView<AuthController> {
|
||||
const RegisterDonaturView({super.key});
|
||||
@ -13,7 +14,7 @@ class RegisterDonaturView extends GetView<AuthController> {
|
||||
appBar: AppBar(
|
||||
title: const Text('Daftar Donatur'),
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.blue,
|
||||
backgroundColor: AppTheme.primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
shape: const RoundedRectangleBorder(
|
||||
@ -22,436 +23,469 @@ class RegisterDonaturView extends GetView<AuthController> {
|
||||
),
|
||||
),
|
||||
),
|
||||
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: 10),
|
||||
// Header dengan icon dan judul
|
||||
Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/logo-disalurkita.png',
|
||||
width: 120,
|
||||
height: 120,
|
||||
),
|
||||
const Text(
|
||||
'Daftar Sebagai Donatur',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue,
|
||||
body: Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFFE3F2FD), Colors.white],
|
||||
),
|
||||
),
|
||||
child: 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: 10),
|
||||
// Header dengan icon dan judul
|
||||
Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppTheme.primaryColor.withOpacity(0.2),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const Text(
|
||||
'Bergabunglah dengan kami untuk membantu mereka yang membutuhkan',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.blueGrey,
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/logo-disalurkita.png',
|
||||
width: 120,
|
||||
height: 120,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
// Step indicator
|
||||
const Row(
|
||||
children: [
|
||||
Icon(Icons.person_add, color: Colors.blue),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
'Informasi Akun',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
const Divider(),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// Nama Lengkap
|
||||
TextFormField(
|
||||
controller: controller.namaController,
|
||||
keyboardType: TextInputType.name,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Nama Lengkap',
|
||||
hintText: 'Masukkan nama lengkap Anda',
|
||||
prefixIcon: const Icon(Icons.person, color: Colors.blue),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade100,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.blue, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateDonaturNama,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Email
|
||||
TextFormField(
|
||||
controller: controller.emailController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Email',
|
||||
hintText: 'contoh@email.com',
|
||||
prefixIcon: const Icon(Icons.email, color: Colors.blue),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade100,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.blue, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateEmail,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Password
|
||||
Obx(() => TextFormField(
|
||||
controller: controller.passwordController,
|
||||
obscureText: controller.isPasswordHidden.value,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Password',
|
||||
hintText: 'Minimal 8 karakter',
|
||||
prefixIcon:
|
||||
const Icon(Icons.lock, color: Colors.blue),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
controller.isPasswordHidden.value
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
Text(
|
||||
'Daftar Sebagai Donatur',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppTheme.primaryColor,
|
||||
),
|
||||
onPressed: () =>
|
||||
controller.togglePasswordVisibility(),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade100,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.blue, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validatePassword,
|
||||
)),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Confirm Password
|
||||
Obx(() => TextFormField(
|
||||
controller: controller.confirmPasswordController,
|
||||
obscureText: controller.isConfirmPasswordHidden.value,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Konfirmasi Password',
|
||||
hintText: 'Masukkan password yang sama',
|
||||
prefixIcon: const Icon(Icons.lock_outline,
|
||||
color: Colors.blue),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
controller.isConfirmPasswordHidden.value
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Bergabunglah dengan kami untuk membantu mereka yang membutuhkan',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: const Color(0xFF546E7A),
|
||||
),
|
||||
onPressed: () =>
|
||||
controller.toggleConfirmPasswordVisibility(),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade100,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.blue, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateConfirmPassword,
|
||||
)),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Section heading
|
||||
const Row(
|
||||
children: [
|
||||
Icon(Icons.person_pin_circle, color: Colors.blue),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
'Informasi Profil',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
const Divider(),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// No HP
|
||||
TextFormField(
|
||||
controller: controller.noHpController,
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Nomor HP',
|
||||
hintText: 'Masukkan nomor HP aktif',
|
||||
prefixIcon: const Icon(Icons.phone, color: Colors.blue),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade100,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.blue, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
],
|
||||
),
|
||||
),
|
||||
validator: controller.validateDonaturNoHp,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Alamat
|
||||
TextFormField(
|
||||
controller: controller.alamatController,
|
||||
keyboardType: TextInputType.streetAddress,
|
||||
maxLines: 2,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Alamat Lengkap',
|
||||
hintText: 'Masukkan alamat lengkap Anda',
|
||||
prefixIcon: const Icon(Icons.home, color: Colors.blue),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade100,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.blue, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateDonaturAlamat,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Jenis Donatur (Dropdown)
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
),
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: controller.jenisController.text.isEmpty
|
||||
? 'Individu'
|
||||
: controller.jenisController.text,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Jenis Donatur',
|
||||
prefixIcon:
|
||||
const Icon(Icons.category, color: Colors.blue),
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 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: 25),
|
||||
|
||||
// Catatan Informasi
|
||||
Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.blue.shade200),
|
||||
),
|
||||
child: Row(
|
||||
const SizedBox(height: 20),
|
||||
// Step indicator
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.info_outline, color: Colors.blue),
|
||||
Icon(Icons.person_add, color: AppTheme.primaryColor),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
Text(
|
||||
'Informasi',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue,
|
||||
),
|
||||
Text(
|
||||
'Informasi Akun',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppTheme.primaryColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
const Divider(),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// Nama Lengkap
|
||||
TextFormField(
|
||||
controller: controller.namaController,
|
||||
keyboardType: TextInputType.name,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Nama Lengkap',
|
||||
hintText: 'Masukkan nama lengkap Anda',
|
||||
prefixIcon:
|
||||
Icon(Icons.person, color: AppTheme.primaryColor),
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(
|
||||
color: AppTheme.primaryColor, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateDonaturNama,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Email
|
||||
TextFormField(
|
||||
controller: controller.emailController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Email',
|
||||
hintText: 'contoh@email.com',
|
||||
prefixIcon:
|
||||
Icon(Icons.email, color: AppTheme.primaryColor),
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(
|
||||
color: AppTheme.primaryColor, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateEmail,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Password
|
||||
Obx(() => TextFormField(
|
||||
controller: controller.passwordController,
|
||||
obscureText: controller.isPasswordHidden.value,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Password',
|
||||
hintText: 'Minimal 8 karakter',
|
||||
prefixIcon:
|
||||
Icon(Icons.lock, color: AppTheme.primaryColor),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
controller.isPasswordHidden.value
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: AppTheme.primaryColor,
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
'Data Anda akan terverifikasi dan terlindungi. Kami menjaga privasi dan keamanan data Anda.',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.blueGrey,
|
||||
onPressed: () =>
|
||||
controller.togglePasswordVisibility(),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide:
|
||||
BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(
|
||||
color: AppTheme.primaryColor, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validatePassword,
|
||||
)),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Confirm Password
|
||||
Obx(() => TextFormField(
|
||||
controller: controller.confirmPasswordController,
|
||||
obscureText: controller.isConfirmPasswordHidden.value,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Konfirmasi Password',
|
||||
hintText: 'Masukkan password yang sama',
|
||||
prefixIcon: Icon(Icons.lock_outline,
|
||||
color: AppTheme.primaryColor),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
controller.isConfirmPasswordHidden.value
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: AppTheme.primaryColor,
|
||||
),
|
||||
onPressed: () =>
|
||||
controller.toggleConfirmPasswordVisibility(),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide:
|
||||
BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(
|
||||
color: AppTheme.primaryColor, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateConfirmPassword,
|
||||
)),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Section heading
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.person_pin_circle,
|
||||
color: AppTheme.primaryColor),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
'Informasi Profil',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppTheme.primaryColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
const Divider(),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// No HP
|
||||
TextFormField(
|
||||
controller: controller.noHpController,
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Nomor HP',
|
||||
hintText: 'Masukkan nomor HP aktif',
|
||||
prefixIcon:
|
||||
Icon(Icons.phone, color: AppTheme.primaryColor),
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(
|
||||
color: AppTheme.primaryColor, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateDonaturNoHp,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Alamat
|
||||
TextFormField(
|
||||
controller: controller.alamatController,
|
||||
keyboardType: TextInputType.streetAddress,
|
||||
maxLines: 2,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Alamat Lengkap',
|
||||
hintText: 'Masukkan alamat lengkap Anda',
|
||||
prefixIcon:
|
||||
Icon(Icons.home, color: AppTheme.primaryColor),
|
||||
filled: true,
|
||||
fillColor: Colors.white,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: BorderSide(
|
||||
color: AppTheme.primaryColor, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
validator: controller.validateDonaturAlamat,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
// Jenis Donatur (Dropdown)
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
),
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: controller.jenisController.text.isEmpty
|
||||
? 'Individu'
|
||||
: controller.jenisController.text,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Jenis Donatur',
|
||||
labelStyle: TextStyle(color: AppTheme.primaryColor),
|
||||
prefixIcon: Icon(Icons.category,
|
||||
color: AppTheme.primaryColor),
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 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';
|
||||
},
|
||||
dropdownColor: Colors.white,
|
||||
icon: Icon(Icons.arrow_drop_down,
|
||||
color: AppTheme.primaryColor),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 25),
|
||||
|
||||
// Catatan Informasi
|
||||
Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF1F8E9),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: const Color(0xFFAED581)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.info_outline,
|
||||
color: Color(0xFF558B2F)),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
Text(
|
||||
'Informasi',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF558B2F),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
'Data Anda akan terverifikasi dan terlindungi. Kami menjaga privasi dan keamanan data Anda.',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF33691E),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 25),
|
||||
|
||||
// Register Button
|
||||
Obx(() => Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppTheme.primaryColor.withOpacity(0.3),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 3,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 25),
|
||||
|
||||
// Register Button
|
||||
Obx(() => Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.blue.withOpacity(0.3),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 3,
|
||||
offset: const Offset(0, 2),
|
||||
child: ElevatedButton(
|
||||
onPressed: controller.isLoading.value
|
||||
? null
|
||||
: controller.registerDonatur,
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||
backgroundColor: AppTheme.primaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ElevatedButton(
|
||||
onPressed: controller.isLoading.value
|
||||
? null
|
||||
: controller.registerDonatur,
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||
backgroundColor: Colors.blue,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
child: controller.isLoading.value
|
||||
? const SpinKitThreeBounce(
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
)
|
||||
: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.how_to_reg, color: Colors.white),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
'DAFTAR SEKARANG',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
child: controller.isLoading.value
|
||||
? const SpinKitThreeBounce(
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
)
|
||||
: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.how_to_reg,
|
||||
color: Colors.white),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
'DAFTAR SEKARANG',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
letterSpacing: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
)),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Login Link
|
||||
Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade50,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.grey.shade200),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'Sudah punya akun?',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Get.offAllNamed(Routes.login),
|
||||
child: const Text(
|
||||
'Masuk',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue,
|
||||
// Login Link
|
||||
Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.grey.shade200),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'Sudah punya akun?',
|
||||
style: TextStyle(color: Color(0xFF546E7A)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Get.offAllNamed(Routes.login),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppTheme.primaryColor,
|
||||
),
|
||||
child: const Text(
|
||||
'Masuk',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
Reference in New Issue
Block a user