semua fitur selesai

This commit is contained in:
Andreas Malvino
2025-06-30 15:22:38 +07:00
parent 8284c93aa5
commit 0423c2fdf9
54 changed files with 11844 additions and 3143 deletions

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../data/providers/auth_provider.dart';
import '../../../routes/app_routes.dart';
import 'dart:math';
class AuthController extends GetxController {
final AuthProvider _authProvider = Get.find<AuthProvider>();
@ -20,6 +21,10 @@ class AuthController extends GetxController {
final RxString phoneNumber = ''.obs;
final RxString selectedRole = 'WARGA'.obs; // Default role
final RxString alamatLengkap = ''.obs;
final Rx<DateTime?> tanggalLahir = Rx<DateTime?>(null);
final RxString rtRw = ''.obs;
final RxString kelurahan = ''.obs;
final RxString kecamatan = ''.obs;
// Form status
final RxBool isLoading = false.obs;
@ -96,7 +101,7 @@ class AuthController extends GetxController {
// Navigate based on role name
if (roleName == null) {
_navigateToWargaDashboard(); // Default to warga if role name not found
await _checkWargaStatusAndNavigate(); // Default to warga if role name not found
return;
}
@ -105,6 +110,9 @@ class AuthController extends GetxController {
_navigateToPetugasBumdesDashboard();
break;
case 'WARGA':
// For WARGA role, check account status in warga_desa table
await _checkWargaStatusAndNavigate();
break;
default:
_navigateToWargaDashboard();
break;
@ -114,6 +122,64 @@ class AuthController extends GetxController {
}
}
// Check warga status in warga_desa table and navigate accordingly
Future<void> _checkWargaStatusAndNavigate() async {
try {
final user = _authProvider.currentUser;
if (user == null) {
errorMessage.value = 'Tidak dapat memperoleh data pengguna';
return;
}
// Get user data from warga_desa table
final userData =
await _authProvider.client
.from('warga_desa')
.select('status, keterangan')
.eq('user_id', user.id)
.maybeSingle();
if (userData == null) {
errorMessage.value = 'Data pengguna tidak ditemukan';
return;
}
final status = userData['status'] as String?;
switch (status?.toLowerCase()) {
case 'active':
// Allow login for active users
_navigateToWargaDashboard();
break;
case 'suspended':
// Show error for suspended users
final keterangan =
userData['keterangan'] as String? ?? 'Tidak ada keterangan';
errorMessage.value =
'Akun Anda dinonaktifkan oleh petugas. Keterangan: $keterangan';
// Sign out the user
await _authProvider.signOut();
break;
case 'pending':
// Show error for pending users
errorMessage.value =
'Akun Anda sedang dalam proses verifikasi. Silakan tunggu hingga verifikasi selesai.';
// Sign out the user
await _authProvider.signOut();
break;
default:
errorMessage.value = 'Status akun tidak valid';
// Sign out the user
await _authProvider.signOut();
break;
}
} catch (e) {
errorMessage.value = 'Gagal memeriksa status akun: ${e.toString()}';
// Sign out the user on error
await _authProvider.signOut();
}
}
void _navigateToPetugasBumdesDashboard() {
Get.offAllNamed(Routes.PETUGAS_BUMDES_DASHBOARD);
}
@ -188,60 +254,69 @@ class AuthController extends GetxController {
// Register user implementation
Future<void> registerUser() async {
// Validate all required fields
if (email.value.isEmpty ||
password.value.isEmpty ||
nik.value.isEmpty ||
phoneNumber.value.isEmpty ||
alamatLengkap.value.isEmpty) {
errorMessage.value = 'Semua field harus diisi';
// Clear previous error messages
errorMessage.value = '';
// Validate form fields
if (!formKey.currentState!.validate()) {
return;
}
// Basic validation for email
if (!GetUtils.isEmail(email.value.trim())) {
errorMessage.value = 'Format email tidak valid';
return;
}
// Basic validation for password
if (password.value.length < 6) {
errorMessage.value = 'Password minimal 6 karakter';
return;
}
// Basic validation for NIK
if (nik.value.length != 16) {
errorMessage.value = 'NIK harus 16 digit';
return;
}
// Basic validation for phone number
if (!phoneNumber.value.startsWith('08') || phoneNumber.value.length < 10) {
errorMessage.value =
'Nomor HP tidak valid (harus diawali 08 dan minimal 10 digit)';
// Validate date of birth separately (since it's not a standard form field)
if (!validateDateOfBirth()) {
return;
}
try {
isLoading.value = true;
errorMessage.value = '';
// Create user with Supabase
final response = await _authProvider.signUp(
// Format tanggal lahir to string (YYYY-MM-DD)
final formattedTanggalLahir =
tanggalLahir.value != null
? '${tanggalLahir.value!.year}-${tanggalLahir.value!.month.toString().padLeft(2, '0')}-${tanggalLahir.value!.day.toString().padLeft(2, '0')}'
: '';
// Generate register_id with format REG-YYYY-1234567
final currentYear = DateTime.now().year.toString();
final randomDigits = _generateRandomDigits(7); // Generate 7 random digits
final registerId = 'REG-$currentYear-$randomDigits';
// 1. Register user with Supabase Auth and add role_id to metadata
final response = await _authProvider.client.auth.signUp(
email: email.value.trim(),
password: password.value,
data: {
'nik': nik.value.trim(),
'phone_number': phoneNumber.value.trim(),
'alamat_lengkap': alamatLengkap.value.trim(),
'role': selectedRole.value,
'role_id':
'bb5360d5-8fd0-404e-8f6f-71ec4d8ad0ae', // Fixed role_id for WARGA
},
);
// Check if registration was successful
if (response.user != null) {
// 2. Get the UID from the created auth user
final userId = response.user!.id;
// 3. Insert user data into the warga_desa table
await _authProvider.client.from('warga_desa').insert({
'user_id': userId,
'email': email.value.trim(),
'nama_lengkap': nameController.text.trim(),
'nik': nik.value.trim(),
'status': 'pending',
'tanggal_lahir': formattedTanggalLahir,
'no_hp': phoneNumber.value.trim(),
'rt_rw': rtRw.value.trim(),
'kelurahan_desa': kelurahan.value.trim(),
'kecamatan': kecamatan.value.trim(),
'alamat': alamatLengkap.value.trim(),
'register_id': registerId, // Add register_id to the warga_desa table
});
// Registration successful
Get.offNamed(Routes.REGISTRATION_SUCCESS);
Get.offNamed(
Routes.REGISTRATION_SUCCESS,
arguments: {'register_id': registerId},
);
} else {
errorMessage.value = 'Gagal mendaftar. Silakan coba lagi.';
}
@ -252,4 +327,155 @@ class AuthController extends GetxController {
isLoading.value = false;
}
}
// Generate random digits of specified length
String _generateRandomDigits(int length) {
final random = Random();
final buffer = StringBuffer();
for (var i = 0; i < length; i++) {
buffer.write(random.nextInt(10));
}
return buffer.toString();
}
// Validation methods
String? validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email tidak boleh kosong';
}
if (!GetUtils.isEmail(value)) {
return 'Format email tidak valid';
}
return null;
}
String? validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Password tidak boleh kosong';
}
if (value.length < 8) {
return 'Password minimal 8 karakter';
}
if (!value.contains(RegExp(r'[A-Z]'))) {
return 'Password harus memiliki minimal 1 huruf besar';
}
if (!value.contains(RegExp(r'[0-9]'))) {
return 'Password harus memiliki minimal 1 angka';
}
return null;
}
String? validateConfirmPassword(String? value) {
if (value == null || value.isEmpty) {
return 'Konfirmasi password tidak boleh kosong';
}
if (value != password.value) {
return 'Password tidak cocok';
}
return null;
}
String? validateName(String? value) {
if (value == null || value.isEmpty) {
return 'Nama lengkap tidak boleh kosong';
}
if (value.length < 3) {
return 'Nama lengkap minimal 3 karakter';
}
if (!RegExp(r"^[a-zA-Z\s\.]+$").hasMatch(value)) {
return 'Nama hanya boleh berisi huruf, spasi, titik, dan apostrof';
}
return null;
}
String? validateNIK(String? value) {
if (value == null || value.isEmpty) {
return 'NIK tidak boleh kosong';
}
if (value.length != 16) {
return 'NIK harus 16 digit';
}
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
return 'NIK hanya boleh berisi angka';
}
return null;
}
String? validatePhone(String? value) {
if (value == null || value.isEmpty) {
return 'No HP tidak boleh kosong';
}
if (!value.startsWith('08')) {
return 'Nomor HP harus diawali dengan 08';
}
if (value.length < 10 || value.length > 13) {
return 'Nomor HP harus antara 10-13 digit';
}
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
return 'Nomor HP hanya boleh berisi angka';
}
return null;
}
String? validateRTRW(String? value) {
if (value == null || value.isEmpty) {
return 'RT/RW tidak boleh kosong';
}
if (!RegExp(r'^\d{1,3}\/\d{1,3}$').hasMatch(value)) {
return 'Format RT/RW tidak valid (contoh: 001/002)';
}
return null;
}
String? validateKelurahan(String? value) {
if (value == null || value.isEmpty) {
return 'Kelurahan/Desa tidak boleh kosong';
}
if (value.length < 3) {
return 'Kelurahan/Desa minimal 3 karakter';
}
return null;
}
String? validateKecamatan(String? value) {
if (value == null || value.isEmpty) {
return 'Kecamatan tidak boleh kosong';
}
if (value.length < 3) {
return 'Kecamatan minimal 3 karakter';
}
return null;
}
String? validateAlamat(String? value) {
if (value == null || value.isEmpty) {
return 'Alamat lengkap tidak boleh kosong';
}
if (value.length < 5) {
return 'Alamat terlalu pendek, minimal 5 karakter';
}
return null;
}
bool validateDateOfBirth() {
if (tanggalLahir.value == null) {
errorMessage.value = 'Tanggal lahir harus diisi';
return false;
}
// Check if user is at least 17 years old
final DateTime today = DateTime.now();
final DateTime minimumAge = DateTime(
today.year - 17,
today.month,
today.day,
);
if (tanggalLahir.value!.isAfter(minimumAge)) {
errorMessage.value = 'Anda harus berusia minimal 17 tahun';
return false;
}
return true;
}
}