kelola penyewa dan beberapa error fix
This commit is contained in:
@ -3,6 +3,7 @@ import 'package:get/get.dart';
|
||||
import '../../../data/providers/auth_provider.dart';
|
||||
import '../../../routes/app_routes.dart';
|
||||
import 'dart:math';
|
||||
import '../../../modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
|
||||
class AuthController extends GetxController {
|
||||
final AuthProvider _authProvider = Get.find<AuthProvider>();
|
||||
@ -185,7 +186,9 @@ class AuthController extends GetxController {
|
||||
}
|
||||
|
||||
void _navigateToWargaDashboard() {
|
||||
Get.offAllNamed(Routes.WARGA_DASHBOARD);
|
||||
// Navigate to warga dashboard with parameter to indicate it's coming from login
|
||||
// This will trigger an immediate refresh of the data
|
||||
Get.offAllNamed(Routes.WARGA_DASHBOARD, arguments: {'from_login': true});
|
||||
}
|
||||
|
||||
void forgotPassword() async {
|
||||
@ -215,7 +218,7 @@ class AuthController extends GetxController {
|
||||
Get.snackbar(
|
||||
'Berhasil',
|
||||
'Link reset password telah dikirim ke email Anda',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: Colors.green[100],
|
||||
colorText: Colors.green[800],
|
||||
icon: const Icon(Icons.check_circle, color: Colors.green),
|
||||
@ -312,7 +315,18 @@ class AuthController extends GetxController {
|
||||
'register_id': registerId, // Add register_id to the warga_desa table
|
||||
});
|
||||
|
||||
// Registration successful
|
||||
// Reset registration fields BEFORE navigation to ensure clean state
|
||||
resetRegistrationFields();
|
||||
|
||||
// Bersihkan data auth provider untuk memastikan tidak ada data user yang tersimpan
|
||||
_authProvider.clearAuthData();
|
||||
|
||||
// Print debug message
|
||||
print(
|
||||
'Registration successful: Fields and controllers have been cleared',
|
||||
);
|
||||
|
||||
// Registration successful - navigate to success page
|
||||
Get.offNamed(
|
||||
Routes.REGISTRATION_SUCCESS,
|
||||
arguments: {'register_id': registerId},
|
||||
@ -478,4 +492,99 @@ class AuthController extends GetxController {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check registration status by register_id and email
|
||||
Future<Map<String, dynamic>?> checkRegistrationStatus(
|
||||
String registerId,
|
||||
String email,
|
||||
) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
|
||||
print('Checking registration status - ID: $registerId, Email: $email');
|
||||
|
||||
// Validasi input
|
||||
if (registerId.isEmpty || email.isEmpty) {
|
||||
print('Invalid input: registerId or email is empty');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Query warga_desa table where register_id and email match
|
||||
final response =
|
||||
await _authProvider.client
|
||||
.from('warga_desa')
|
||||
.select(
|
||||
'*',
|
||||
) // Ensure we select all columns including 'keterangan'
|
||||
.eq('register_id', registerId)
|
||||
.eq('email', email)
|
||||
.maybeSingle();
|
||||
|
||||
// Log response for debugging
|
||||
print('Registration status query response: $response');
|
||||
|
||||
// Validasi hasil query
|
||||
if (response == null) {
|
||||
print('No matching registration found');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response is Map<String, dynamic> && response.isEmpty) {
|
||||
print('Empty response received');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Jika berhasil, kembalikan data
|
||||
print('Registration found with status: ${response['status']}');
|
||||
return response;
|
||||
} catch (e) {
|
||||
print('Error checking registration status: ${e.toString()}');
|
||||
return null;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset all registration fields
|
||||
void resetRegistrationFields() {
|
||||
// Reset text controllers
|
||||
emailController.clear();
|
||||
passwordController.clear();
|
||||
nameController.clear();
|
||||
confirmPasswordController.clear();
|
||||
|
||||
// Reset form fields
|
||||
email.value = '';
|
||||
password.value = '';
|
||||
nik.value = '';
|
||||
phoneNumber.value = '';
|
||||
selectedRole.value = 'WARGA'; // Reset to default role
|
||||
alamatLengkap.value = '';
|
||||
tanggalLahir.value = null;
|
||||
rtRw.value = '';
|
||||
kelurahan.value = '';
|
||||
kecamatan.value = '';
|
||||
|
||||
// Reset form status
|
||||
isPasswordVisible.value = false;
|
||||
isConfirmPasswordVisible.value = false;
|
||||
errorMessage.value = '';
|
||||
|
||||
// Reset form key if needed
|
||||
if (formKey.currentState != null) {
|
||||
formKey.currentState!.reset();
|
||||
}
|
||||
|
||||
// Bersihkan WargaDashboardController jika terdaftar
|
||||
try {
|
||||
if (Get.isRegistered<WargaDashboardController>()) {
|
||||
print(
|
||||
'Removing WargaDashboardController to ensure clean state after registration',
|
||||
);
|
||||
Get.delete<WargaDashboardController>(force: true);
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error removing WargaDashboardController: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ class LoginView extends GetView<AuthController> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: Stack(
|
||||
children: [
|
||||
// Background gradient
|
||||
@ -77,9 +77,6 @@ class LoginView extends GetView<AuthController> {
|
||||
SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
physics: const ClampingScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Column(
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../theme/app_colors.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import '../../../routes/app_routes.dart';
|
||||
|
||||
class RegistrationSuccessView extends StatefulWidget {
|
||||
const RegistrationSuccessView({Key? key}) : super(key: key);
|
||||
@ -284,7 +285,7 @@ class _RegistrationSuccessViewState extends State<RegistrationSuccessView>
|
||||
Get.snackbar(
|
||||
'Berhasil Disalin',
|
||||
'Kode registrasi telah disalin ke clipboard',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: AppColors.successLight,
|
||||
colorText: AppColors.success,
|
||||
margin: const EdgeInsets.all(16),
|
||||
@ -329,7 +330,7 @@ class _RegistrationSuccessViewState extends State<RegistrationSuccessView>
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
// Navigate back to login page
|
||||
Get.offAllNamed('/login');
|
||||
Get.offNamed(Routes.LOGIN);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.primary,
|
||||
|
@ -2,100 +2,108 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../controllers/auth_controller.dart';
|
||||
import '../../../theme/app_colors.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class RegistrationView extends GetView<AuthController> {
|
||||
const RegistrationView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
// Background gradient - same as login page
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
colors: [
|
||||
AppColors.primaryLight.withOpacity(0.1),
|
||||
AppColors.background,
|
||||
AppColors.accentLight.withOpacity(0.1),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Pattern overlay - same as login page
|
||||
Opacity(
|
||||
opacity: 0.03,
|
||||
child: Container(
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
// Reset all registration fields when leaving the page
|
||||
controller.resetRegistrationFields();
|
||||
return true;
|
||||
},
|
||||
child: Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
// Background gradient - same as login page
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue[50], // Temporary solid color
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Accent circles - same as login page
|
||||
Positioned(
|
||||
top: -40,
|
||||
right: -20,
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: 150,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: RadialGradient(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
colors: [
|
||||
AppColors.primary.withOpacity(0.2),
|
||||
Colors.transparent,
|
||||
AppColors.primaryLight.withOpacity(0.1),
|
||||
AppColors.background,
|
||||
AppColors.accentLight.withOpacity(0.1),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -50,
|
||||
left: -30,
|
||||
child: Container(
|
||||
width: 180,
|
||||
height: 180,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: RadialGradient(
|
||||
colors: [
|
||||
AppColors.accent.withOpacity(0.2),
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Main content
|
||||
SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
_buildBackButton(),
|
||||
const SizedBox(height: 20),
|
||||
_buildHeader(),
|
||||
const SizedBox(height: 30),
|
||||
_buildRegistrationCard(),
|
||||
_buildLoginLink(),
|
||||
_buildCheckStatusLink(),
|
||||
const SizedBox(height: 30),
|
||||
],
|
||||
// Pattern overlay - same as login page
|
||||
Opacity(
|
||||
opacity: 0.03,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue[50], // Temporary solid color
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
// Accent circles - same as login page
|
||||
Positioned(
|
||||
top: -40,
|
||||
right: -20,
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: 150,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: RadialGradient(
|
||||
colors: [
|
||||
AppColors.primary.withOpacity(0.2),
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -50,
|
||||
left: -30,
|
||||
child: Container(
|
||||
width: 180,
|
||||
height: 180,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: RadialGradient(
|
||||
colors: [
|
||||
AppColors.accent.withOpacity(0.2),
|
||||
Colors.transparent,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Main content
|
||||
SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
_buildBackButton(),
|
||||
const SizedBox(height: 20),
|
||||
_buildHeader(),
|
||||
const SizedBox(height: 30),
|
||||
_buildRegistrationCard(),
|
||||
_buildLoginLink(),
|
||||
_buildCheckStatusLink(),
|
||||
const SizedBox(height: 30),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -104,7 +112,11 @@ class RegistrationView extends GetView<AuthController> {
|
||||
return Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: InkWell(
|
||||
onTap: () => Get.back(),
|
||||
onTap: () {
|
||||
// Reset all registration fields when going back
|
||||
controller.resetRegistrationFields();
|
||||
Get.back();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
@ -644,7 +656,11 @@ class RegistrationView extends GetView<AuthController> {
|
||||
style: TextStyle(color: AppColors.textSecondary),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
onPressed: () {
|
||||
// Reset all registration fields when going back to login
|
||||
controller.resetRegistrationFields();
|
||||
Get.back();
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
),
|
||||
@ -694,7 +710,8 @@ class RegistrationView extends GetView<AuthController> {
|
||||
// Show dialog to check registration status
|
||||
void _showCheckStatusDialog(BuildContext context) {
|
||||
final TextEditingController codeController = TextEditingController();
|
||||
final TextEditingController identifierController = TextEditingController();
|
||||
final TextEditingController emailController = TextEditingController();
|
||||
final authController = Get.find<AuthController>();
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
@ -788,9 +805,9 @@ class RegistrationView extends GetView<AuthController> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Email/NIK/Phone field
|
||||
// Email field
|
||||
Text(
|
||||
'Email/NIK/No HP',
|
||||
'Email',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
@ -799,12 +816,13 @@ class RegistrationView extends GetView<AuthController> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextField(
|
||||
controller: identifierController,
|
||||
controller: emailController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Masukkan email, NIK, atau no HP',
|
||||
hintText: 'Masukkan email yang terdaftar',
|
||||
hintStyle: TextStyle(color: AppColors.textLight),
|
||||
prefixIcon: Icon(
|
||||
Icons.person_outline,
|
||||
Icons.email_outlined,
|
||||
color: AppColors.iconGrey,
|
||||
size: 22,
|
||||
),
|
||||
@ -835,20 +853,99 @@ class RegistrationView extends GetView<AuthController> {
|
||||
width: double.infinity,
|
||||
height: 48,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
// TODO: Implement check status functionality
|
||||
onPressed: () async {
|
||||
// Validasi input
|
||||
if (codeController.text.isEmpty ||
|
||||
emailController.text.isEmpty) {
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
'Kode registrasi dan Email harus diisi',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: AppColors.errorLight,
|
||||
colorText: AppColors.error,
|
||||
icon: Icon(
|
||||
Icons.error_outline,
|
||||
color: AppColors.error,
|
||||
),
|
||||
duration: const Duration(seconds: 3),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Simpan nilai input untuk digunakan nanti
|
||||
final String registerId = codeController.text.trim();
|
||||
final String email = emailController.text.trim();
|
||||
|
||||
print(
|
||||
'Checking registration status for ID: $registerId, Email: $email',
|
||||
);
|
||||
|
||||
// Tutup dialog input
|
||||
Navigator.pop(context);
|
||||
|
||||
// Show a mock response for now
|
||||
Get.snackbar(
|
||||
'Status Pendaftaran',
|
||||
'Status pendaftaran sedang diproses. Silakan tunggu konfirmasi lebih lanjut.',
|
||||
snackPosition: SnackPosition.BOTTOM,
|
||||
backgroundColor: AppColors.infoLight,
|
||||
colorText: AppColors.info,
|
||||
icon: Icon(Icons.info_outline, color: AppColors.info),
|
||||
duration: const Duration(seconds: 4),
|
||||
// Tampilkan loading indicator
|
||||
Get.dialog(
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
|
||||
try {
|
||||
// Cek status pendaftaran
|
||||
final result = await authController
|
||||
.checkRegistrationStatus(registerId, email);
|
||||
|
||||
// Debug log
|
||||
print('Registration status check result: $result');
|
||||
|
||||
// Tutup dialog loading
|
||||
Get.back();
|
||||
|
||||
// Periksa hasil query
|
||||
if (result != null && result.isNotEmpty) {
|
||||
print('Valid result found, showing status dialog');
|
||||
|
||||
// Tambahkan delay kecil untuk memastikan UI diperbarui dengan benar
|
||||
// Ini membantu memastikan dialog status muncul setelah dialog loading ditutup
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
_showRegistrationStatusDialog(result);
|
||||
});
|
||||
} else {
|
||||
print('No result found or empty result');
|
||||
|
||||
// Tampilkan pesan error
|
||||
Get.snackbar(
|
||||
'Tidak Ditemukan',
|
||||
'Data pendaftaran tidak ditemukan. Pastikan kode registrasi dan email yang dimasukkan benar.',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: AppColors.errorLight,
|
||||
colorText: AppColors.error,
|
||||
icon: Icon(
|
||||
Icons.error_outline,
|
||||
color: AppColors.error,
|
||||
),
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// Tutup dialog loading jika terjadi error
|
||||
Get.back();
|
||||
|
||||
print('Error checking registration status: $e');
|
||||
|
||||
// Tampilkan pesan error
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
'Terjadi kesalahan saat memeriksa status. Silakan coba lagi nanti.',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: AppColors.errorLight,
|
||||
colorText: AppColors.error,
|
||||
icon: Icon(
|
||||
Icons.error_outline,
|
||||
color: AppColors.error,
|
||||
),
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.accent,
|
||||
@ -875,6 +972,219 @@ class RegistrationView extends GetView<AuthController> {
|
||||
);
|
||||
}
|
||||
|
||||
// Show dialog with registration status details
|
||||
void _showRegistrationStatusDialog(Map<String, dynamic> data) {
|
||||
// Log data yang diterima untuk debugging
|
||||
print('Showing registration status dialog with data: $data');
|
||||
|
||||
// Validasi data
|
||||
if (data.isEmpty) {
|
||||
print('Error: Empty data received in _showRegistrationStatusDialog');
|
||||
Get.snackbar(
|
||||
'Error',
|
||||
'Data status pendaftaran tidak valid',
|
||||
snackPosition: SnackPosition.TOP,
|
||||
backgroundColor: AppColors.errorLight,
|
||||
colorText: AppColors.error,
|
||||
duration: const Duration(seconds: 3),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final String status = data['status'] ?? 'unknown';
|
||||
final String namaLengkap = data['nama_lengkap'] ?? '';
|
||||
final String keterangan = data['keterangan'] ?? '';
|
||||
|
||||
print('Processing status: $status, nama: $namaLengkap');
|
||||
|
||||
// Define status color and message based on status
|
||||
Color statusColor;
|
||||
String statusMessage;
|
||||
IconData statusIcon;
|
||||
|
||||
switch (status) {
|
||||
case 'pending':
|
||||
statusColor = AppColors.warning;
|
||||
statusMessage =
|
||||
keterangan.isNotEmpty
|
||||
? keterangan
|
||||
: 'Pendaftaran Anda sedang dalam proses verifikasi oleh petugas. Mohon tunggu konfirmasi lebih lanjut.';
|
||||
statusIcon = Icons.hourglass_top;
|
||||
break;
|
||||
case 'active':
|
||||
statusColor = AppColors.success;
|
||||
statusMessage =
|
||||
keterangan.isNotEmpty
|
||||
? keterangan
|
||||
: 'Pendaftaran Anda telah disetujui. Anda dapat login menggunakan email dan password yang telah didaftarkan.';
|
||||
statusIcon = Icons.check_circle;
|
||||
break;
|
||||
case 'dibatalkan':
|
||||
statusColor = AppColors.error;
|
||||
statusMessage =
|
||||
keterangan.isNotEmpty
|
||||
? keterangan
|
||||
: 'Maaf, pendaftaran Anda ditolak. Silakan hubungi admin untuk informasi lebih lanjut.';
|
||||
statusIcon = Icons.cancel;
|
||||
break;
|
||||
case 'suspended':
|
||||
statusColor = AppColors.error;
|
||||
statusMessage =
|
||||
keterangan.isNotEmpty
|
||||
? keterangan
|
||||
: 'Akun Anda saat ini dinonaktifkan. Silakan hubungi admin untuk informasi lebih lanjut.';
|
||||
statusIcon = Icons.block;
|
||||
break;
|
||||
default:
|
||||
statusColor = AppColors.textSecondary;
|
||||
statusMessage =
|
||||
keterangan.isNotEmpty
|
||||
? keterangan
|
||||
: 'Status pendaftaran tidak diketahui. Silakan hubungi admin untuk informasi lebih lanjut.';
|
||||
statusIcon = Icons.help;
|
||||
}
|
||||
|
||||
print('Preparing to show dialog with status: $status, color: $statusColor');
|
||||
|
||||
// Gunakan Get.dialog sebagai pengganti showDialog untuk menghindari masalah context
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 80,
|
||||
height: 80,
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(statusIcon, color: statusColor, size: 40),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
'Status Pendaftaran',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
namaLengkap,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
child: Text(
|
||||
status.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: statusColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
statusMessage,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: AppColors.textSecondary,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
|
||||
// Tampilkan informasi tambahan jika ada
|
||||
if (data.containsKey('tanggal_update') &&
|
||||
data['tanggal_update'] != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.infoLight.withOpacity(0.3),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
size: 16,
|
||||
color: AppColors.info,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Informasi Tambahan',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
color: AppColors.info,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Terakhir diperbarui: ${_formatDate(data['tanggal_update'])}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => Get.back(),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: statusColor,
|
||||
foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
),
|
||||
child: const Text(
|
||||
'Tutup',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
barrierDismissible: true,
|
||||
);
|
||||
|
||||
print('Dialog setup completed');
|
||||
}
|
||||
|
||||
// New method to build date picker field
|
||||
Widget _buildDateField(BuildContext context) {
|
||||
return GestureDetector(
|
||||
@ -944,4 +1254,24 @@ class RegistrationView extends GetView<AuthController> {
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
String _formatDate(dynamic date) {
|
||||
if (date is String) {
|
||||
try {
|
||||
final DateTime parsedDate = DateTime.parse(date);
|
||||
return DateFormat('dd MMM yyyy, HH:mm').format(parsedDate);
|
||||
} catch (e) {
|
||||
return date;
|
||||
}
|
||||
} else if (date is num) {
|
||||
final DateTime parsedDate = DateTime.fromMillisecondsSinceEpoch(
|
||||
date.toInt() * 1000,
|
||||
);
|
||||
return DateFormat('dd MMM yyyy, HH:mm').format(parsedDate);
|
||||
} else if (date is DateTime) {
|
||||
return DateFormat('dd MMM yyyy, HH:mm').format(date);
|
||||
} else {
|
||||
return "Format tanggal tidak diketahui";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user