first commit

This commit is contained in:
Andreas Malvino
2025-06-02 22:39:03 +07:00
commit e7090af3da
245 changed files with 49210 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,443 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:intl/intl.dart';
import 'package:flutter_logs/flutter_logs.dart';
import '../../../data/models/paket_model.dart';
import '../../../data/providers/aset_provider.dart';
import '../../../data/providers/sewa_provider.dart';
import '../../../services/service_manager.dart';
import '../../../services/navigation_service.dart';
class OrderSewaPaketController extends GetxController {
// Dependencies
final AsetProvider asetProvider = Get.find<AsetProvider>();
final SewaProvider sewaProvider = Get.find<SewaProvider>();
final NavigationService navigationService = ServiceManager().navigationService;
// State variables
final paket = Rx<PaketModel?>(null);
final paketImages = RxList<String>([]);
final isLoading = RxBool(true);
final isPhotosLoading = RxBool(true);
final selectedSatuanWaktu = Rx<Map<String, dynamic>?>(null);
final selectedDate = RxString('');
final selectedStartDate = Rx<DateTime?>(null);
final selectedEndDate = Rx<DateTime?>(null);
final selectedStartTime = RxInt(-1);
final selectedEndTime = RxInt(-1);
final formattedDateRange = RxString('');
final formattedTimeRange = RxString('');
final totalPrice = RxDouble(0.0);
final kuantitas = RxInt(1);
final isSubmitting = RxBool(false);
// Format currency
final currencyFormat = NumberFormat.currency(
locale: 'id',
symbol: 'Rp',
decimalDigits: 0,
);
@override
void onInit() {
super.onInit();
FlutterLogs.logInfo("OrderSewaPaketController", "onInit", "Initializing OrderSewaPaketController");
// Get the paket ID from arguments
final Map<String, dynamic> args = Get.arguments ?? {};
final String? paketId = args['id'];
if (paketId != null) {
loadPaketData(paketId);
} else {
debugPrint('❌ No paket ID provided in arguments');
isLoading.value = false;
}
}
// Handle hot reload - restore state if needed
void handleHotReload() {
if (paket.value == null) {
final Map<String, dynamic> args = Get.arguments ?? {};
final String? paketId = args['id'];
if (paketId != null) {
// Try to get from cache first
final cachedPaket = GetStorage().read('cached_paket_$paketId');
if (cachedPaket != null) {
debugPrint('🔄 Hot reload: Restoring paket from cache');
paket.value = cachedPaket;
loadPaketPhotos(paketId);
initializePriceOptions();
} else {
loadPaketData(paketId);
}
}
}
}
// Load paket data from API
Future<void> loadPaketData(String id) async {
try {
isLoading.value = true;
debugPrint('🔍 Loading paket data for ID: $id');
// First check if we have it in cache
final cachedPaket = GetStorage().read('cached_paket_$id');
if (cachedPaket != null) {
debugPrint('✅ Found cached paket data');
paket.value = cachedPaket;
await loadPaketPhotos(id);
initializePriceOptions();
} else {
// Get all pakets and filter for the one we need
final List<dynamic> allPakets = await asetProvider.getPakets();
final rawPaket = allPakets.firstWhere(
(paket) => paket['id'] == id,
orElse: () => null,
);
// Declare loadedPaket outside the if block for wider scope
PaketModel? loadedPaket;
if (rawPaket != null) {
// Convert to PaketModel
try {
// Handle Map directly - pakets from getPakets() are always maps
loadedPaket = PaketModel.fromMap(rawPaket);
debugPrint('✅ Successfully converted paket to PaketModel');
} catch (e) {
debugPrint('❌ Error converting paket map to PaketModel: $e');
// Fallback using our helper methods
loadedPaket = PaketModel(
id: getPaketId(rawPaket),
nama: getPaketNama(rawPaket),
deskripsi: getPaketDeskripsi(rawPaket),
harga: getPaketHarga(rawPaket),
kuantitas: getPaketKuantitas(rawPaket),
foto_paket: getPaketMainPhoto(rawPaket),
satuanWaktuSewa: getPaketSatuanWaktuSewa(rawPaket),
);
debugPrint('✅ Created PaketModel using helper methods');
}
// Update the state with the loaded paket
if (loadedPaket != null) {
debugPrint('✅ Loaded paket: ${loadedPaket.nama}');
paket.value = loadedPaket;
// Cache for future use
GetStorage().write('cached_paket_$id', loadedPaket);
// Load photos for this paket
await loadPaketPhotos(id);
// Set initial pricing option
initializePriceOptions();
// Ensure we have at least one photo if available
if (paketImages.isEmpty) {
String? mainPhoto = getPaketMainPhoto(paket.value);
if (mainPhoto != null && mainPhoto.isNotEmpty) {
paketImages.add(mainPhoto);
debugPrint('✅ Added main paket photo: $mainPhoto');
}
}
}
} else {
debugPrint('❌ No paket found with id: $id');
}
}
// Calculate the total price if we have a paket loaded
if (paket.value != null) {
calculateTotalPrice();
debugPrint('💰 Total price calculated: ${totalPrice.value}');
}
} catch (e) {
debugPrint('❌ Error loading paket data: $e');
} finally {
isLoading.value = false;
}
}
// Helper methods to safely access paket properties
String? getPaketId(dynamic paket) {
if (paket == null) return null;
try {
return paket.id ?? paket['id'];
} catch (_) {
return null;
}
}
String? getPaketNama(dynamic paket) {
if (paket == null) return null;
try {
return paket.nama ?? paket['nama'];
} catch (_) {
return null;
}
}
String? getPaketDeskripsi(dynamic paket) {
if (paket == null) return null;
try {
return paket.deskripsi ?? paket['deskripsi'];
} catch (_) {
return null;
}
}
double getPaketHarga(dynamic paket) {
if (paket == null) return 0.0;
try {
var harga = paket.harga ?? paket['harga'] ?? 0;
return double.tryParse(harga.toString()) ?? 0.0;
} catch (_) {
return 0.0;
}
}
int getPaketKuantitas(dynamic paket) {
if (paket == null) return 1;
try {
var qty = paket.kuantitas ?? paket['kuantitas'] ?? 1;
return int.tryParse(qty.toString()) ?? 1;
} catch (_) {
return 1;
}
}
String? getPaketMainPhoto(dynamic paket) {
if (paket == null) return null;
try {
return paket.foto_paket ?? paket['foto_paket'];
} catch (_) {
return null;
}
}
List<dynamic> getPaketSatuanWaktuSewa(dynamic paket) {
if (paket == null) return [];
try {
return paket.satuanWaktuSewa ?? paket['satuanWaktuSewa'] ?? [];
} catch (_) {
return [];
}
}
// Load photos for the paket
Future<void> loadPaketPhotos(String paketId) async {
try {
isPhotosLoading.value = true;
final photos = await asetProvider.getFotoPaket(paketId);
if (photos != null && photos.isNotEmpty) {
paketImages.clear();
for (var photo in photos) {
try {
if (photo.fotoPaket != null && photo.fotoPaket.isNotEmpty) {
paketImages.add(photo.fotoPaket);
} else if (photo.fotoAset != null && photo.fotoAset.isNotEmpty) {
paketImages.add(photo.fotoAset);
}
} catch (e) {
var fotoUrl = photo['foto_paket'] ?? photo['foto_aset'];
if (fotoUrl != null && fotoUrl.isNotEmpty) {
paketImages.add(fotoUrl);
}
}
}
}
} finally {
isPhotosLoading.value = false;
}
}
// Initialize price options
void initializePriceOptions() {
if (paket.value == null) return;
final satuanWaktuSewa = getPaketSatuanWaktuSewa(paket.value);
if (satuanWaktuSewa.isNotEmpty) {
// Default to the first option
selectSatuanWaktu(satuanWaktuSewa.first);
}
}
// Select satuan waktu
void selectSatuanWaktu(Map<String, dynamic> satuanWaktu) {
selectedSatuanWaktu.value = satuanWaktu;
// Reset date and time selections
selectedStartDate.value = null;
selectedEndDate.value = null;
selectedStartTime.value = -1;
selectedEndTime.value = -1;
selectedDate.value = '';
formattedDateRange.value = '';
formattedTimeRange.value = '';
calculateTotalPrice();
}
// Check if the rental is daily
bool isDailyRental() {
final namaSatuan = selectedSatuanWaktu.value?['nama_satuan_waktu'] ?? '';
return namaSatuan.toString().toLowerCase().contains('hari');
}
// Select date range for daily rental
void selectDateRange(DateTime start, DateTime end) {
selectedStartDate.value = start;
selectedEndDate.value = end;
// Format the date range
final formatter = DateFormat('d MMM yyyy', 'id');
if (start.year == end.year && start.month == end.month && start.day == end.day) {
formattedDateRange.value = formatter.format(start);
} else {
formattedDateRange.value = '${formatter.format(start)} - ${formatter.format(end)}';
}
selectedDate.value = formatter.format(start);
calculateTotalPrice();
}
// Select date for hourly rental
void selectDate(DateTime date) {
selectedStartDate.value = date;
selectedDate.value = DateFormat('d MMM yyyy', 'id').format(date);
calculateTotalPrice();
}
// Select time range for hourly rental
void selectTimeRange(int start, int end) {
selectedStartTime.value = start;
selectedEndTime.value = end;
// Format the time range
final startTime = '$start:00';
final endTime = '$end:00';
formattedTimeRange.value = '$startTime - $endTime';
calculateTotalPrice();
}
// Calculate total price
void calculateTotalPrice() {
if (selectedSatuanWaktu.value == null) {
totalPrice.value = 0.0;
return;
}
final basePrice = double.tryParse(selectedSatuanWaktu.value!['harga'].toString()) ?? 0.0;
if (isDailyRental()) {
if (selectedStartDate.value != null && selectedEndDate.value != null) {
final days = selectedEndDate.value!.difference(selectedStartDate.value!).inDays + 1;
totalPrice.value = basePrice * days;
} else {
totalPrice.value = basePrice;
}
} else {
if (selectedStartTime.value >= 0 && selectedEndTime.value >= 0) {
final hours = selectedEndTime.value - selectedStartTime.value;
totalPrice.value = basePrice * hours;
} else {
totalPrice.value = basePrice;
}
}
// Multiply by quantity
totalPrice.value *= kuantitas.value;
}
// Format price as currency
String formatPrice(double price) {
return currencyFormat.format(price);
}
// Submit order
Future<void> submitOrder() async {
try {
if (paket.value == null || selectedSatuanWaktu.value == null) {
Get.snackbar(
'Error',
'Data paket tidak lengkap',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
return;
}
if ((isDailyRental() && (selectedStartDate.value == null || selectedEndDate.value == null)) ||
(!isDailyRental() && (selectedStartDate.value == null || selectedStartTime.value < 0 || selectedEndTime.value < 0))) {
Get.snackbar(
'Error',
'Silakan pilih waktu sewa',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
return;
}
isSubmitting.value = true;
// Prepare order data
final Map<String, dynamic> orderData = {
'id_paket': paket.value!.id,
'id_satuan_waktu_sewa': selectedSatuanWaktu.value!['id'],
'tanggal_mulai': selectedStartDate.value!.toIso8601String(),
'tanggal_selesai': selectedEndDate.value?.toIso8601String() ?? selectedStartDate.value!.toIso8601String(),
'jam_mulai': isDailyRental() ? null : selectedStartTime.value,
'jam_selesai': isDailyRental() ? null : selectedEndTime.value,
'total_harga': totalPrice.value,
'kuantitas': kuantitas.value,
};
// Submit the order
final result = await sewaProvider.createPaketOrder(orderData);
if (result != null) {
Get.snackbar(
'Sukses',
'Pesanan berhasil dibuat',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
colorText: Colors.white,
);
// Navigate to payment page
navigationService.navigateToPembayaranSewa(result['id']);
} else {
Get.snackbar(
'Error',
'Gagal membuat pesanan',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
} catch (e) {
debugPrint('❌ Error submitting order: $e');
Get.snackbar(
'Error',
'Terjadi kesalahan: $e',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
} finally {
isSubmitting.value = false;
}
}
// Handle back button press
void onBackPressed() {
navigationService.navigateToSewaAset();
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,471 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../../data/providers/aset_provider.dart';
import '../../../data/models/aset_model.dart';
import '../../../routes/app_routes.dart';
import '../../../data/models/pesanan_model.dart';
import '../../../data/models/satuan_waktu_model.dart';
import '../../../data/models/satuan_waktu_sewa_model.dart';
import '../../../data/providers/auth_provider.dart';
import '../../../data/providers/pesanan_provider.dart';
import '../../../services/navigation_service.dart';
import '../../../services/service_manager.dart';
import 'package:get_storage/get_storage.dart';
class SewaAsetController extends GetxController
with GetSingleTickerProviderStateMixin {
final AsetProvider _asetProvider = Get.find<AsetProvider>();
final AuthProvider authProvider = Get.find<AuthProvider>();
final PesananProvider pesananProvider = Get.put(PesananProvider());
final NavigationService navigationService = Get.find<NavigationService>();
final box = GetStorage();
// Tab controller
late TabController tabController;
// Reactive tab index
final currentTabIndex = 0.obs;
// State variables
final asets = <AsetModel>[].obs;
final filteredAsets = <AsetModel>[].obs;
// Paket-related variables
final pakets = RxList<dynamic>([]);
final filteredPakets = RxList<dynamic>([]);
final isLoadingPakets = false.obs;
final isLoading = true.obs;
// Search controller
final TextEditingController searchController = TextEditingController();
// Reactive variables
final isOrdering = false.obs;
final selectedAset = Rx<AsetModel?>(null);
final selectedSatuanWaktuSewa = Rx<SatuanWaktuSewaModel?>(null);
final selectedDurasi = 1.obs;
final totalHarga = 0.obs;
final selectedDate = DateTime.now().obs;
final selectedTime = '08:00'.obs;
final satuanWaktuDropdownItems =
<DropdownMenuItem<SatuanWaktuSewaModel>>[].obs;
// Flag untuk menangani hot reload
final hasInitialized = false.obs;
@override
void onInit() {
super.onInit();
debugPrint('🚀 SewaAsetController: onInit called');
// Initialize tab controller
tabController = TabController(length: 2, vsync: this);
// Listen for tab changes
tabController.addListener(() {
currentTabIndex.value = tabController.index;
// Load packages data when switching to package tab for the first time
if (currentTabIndex.value == 1 && pakets.isEmpty) {
loadPakets();
}
});
loadAsets();
searchController.addListener(() {
if (currentTabIndex.value == 0) {
filterAsets(searchController.text);
} else {
filterPakets(searchController.text);
}
});
hasInitialized.value = true;
}
@override
void onReady() {
super.onReady();
debugPrint('🚀 SewaAsetController: onReady called');
}
@override
void onClose() {
debugPrint('🧹 SewaAsetController: onClose called');
searchController.dispose();
tabController.dispose();
super.onClose();
}
// Method untuk menangani hot reload
void handleHotReload() {
debugPrint('🔥 Hot reload detected in SewaAsetController');
if (!hasInitialized.value) {
debugPrint('🔄 Reinitializing SewaAsetController after hot reload');
loadAsets();
if (currentTabIndex.value == 1) {
loadPakets();
}
hasInitialized.value = true;
}
}
// Method untuk menangani tombol back
void onBackPressed() {
debugPrint('🔙 Back button pressed in SewaAsetView');
navigationService.backFromSewaAset();
}
Future<void> loadAsets() async {
try {
isLoading.value = true;
final sewaAsets = await _asetProvider.getSewaAsets();
// Debug data satuan waktu sewa yang diterima
debugPrint('===== DEBUG ASET & SATUAN WAKTU SEWA =====');
for (var aset in sewaAsets) {
debugPrint('Aset: ${aset.nama} (ID: ${aset.id})');
if (aset.satuanWaktuSewa.isEmpty) {
debugPrint(' - Tidak ada satuan waktu sewa yang terkait');
} else {
debugPrint(
' - Memiliki ${aset.satuanWaktuSewa.length} satuan waktu sewa:',
);
for (var sws in aset.satuanWaktuSewa) {
debugPrint(' * ID: ${sws['id']}');
debugPrint(' Aset ID: ${sws['aset_id']}');
debugPrint(' Satuan Waktu ID: ${sws['satuan_waktu_id']}');
debugPrint(' Harga: ${sws['harga']}');
debugPrint(' Nama Satuan Waktu: ${sws['nama_satuan_waktu']}');
debugPrint(' -----');
}
}
debugPrint('=====================================');
}
asets.assignAll(sewaAsets);
filteredAsets.assignAll(sewaAsets);
// Tambahkan log info tentang jumlah aset yang berhasil dimuat
debugPrint('Loaded ${sewaAsets.length} aset sewa successfully');
} catch (e) {
debugPrint('Error loading asets: $e');
Get.snackbar(
'Error',
'Terjadi kesalahan saat memuat data aset',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
} finally {
isLoading.value = false;
}
}
void filterAsets(String query) {
if (query.isEmpty) {
filteredAsets.assignAll(asets);
} else {
filteredAsets.assignAll(
asets
.where(
(aset) => aset.nama.toLowerCase().contains(query.toLowerCase()),
)
.toList(),
);
}
}
void refreshAsets() {
loadAsets();
}
String formatPrice(dynamic price) {
if (price == null) return 'Rp 0';
// Handle different types
num numericPrice;
if (price is int || price is double) {
numericPrice = price;
} else if (price is String) {
numericPrice = double.tryParse(price) ?? 0;
} else {
return 'Rp 0';
}
final formatter = NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
);
return formatter.format(numericPrice);
}
void selectAset(AsetModel aset) {
selectedAset.value = aset;
// Reset related values
selectedSatuanWaktuSewa.value = null;
selectedDurasi.value = 1;
totalHarga.value = 0;
// Prepare dropdown items for satuan waktu sewa
updateSatuanWaktuDropdown();
}
void updateSatuanWaktuDropdown() {
satuanWaktuDropdownItems.clear();
if (selectedAset.value != null &&
selectedAset.value!.satuanWaktuSewa.isNotEmpty) {
for (var item in selectedAset.value!.satuanWaktuSewa) {
final satuanWaktuSewa = SatuanWaktuSewaModel.fromJson(item);
satuanWaktuDropdownItems.add(
DropdownMenuItem<SatuanWaktuSewaModel>(
value: satuanWaktuSewa,
child: Text(
'${satuanWaktuSewa.namaSatuanWaktu ?? "Unknown"} - Rp${NumberFormat.decimalPattern('id').format(satuanWaktuSewa.harga)}',
),
),
);
}
}
}
void selectSatuanWaktu(SatuanWaktuSewaModel? satuanWaktuSewa) {
selectedSatuanWaktuSewa.value = satuanWaktuSewa;
calculateTotalPrice();
}
void updateDurasi(int durasi) {
if (durasi < 1) durasi = 1;
selectedDurasi.value = durasi;
calculateTotalPrice();
}
void calculateTotalPrice() {
if (selectedSatuanWaktuSewa.value != null) {
totalHarga.value =
selectedSatuanWaktuSewa.value!.harga * selectedDurasi.value;
} else {
totalHarga.value = 0;
}
}
void pickDate(DateTime date) {
selectedDate.value = date;
}
void pickTime(String time) {
selectedTime.value = time;
}
// Helper method to show error snackbar
void _showError(String message) {
Get.snackbar(
'Error',
message,
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
// Method untuk melakukan pemesanan
Future<void> placeOrderAset() async {
if (selectedAset.value == null) {
_showError('Silakan pilih aset terlebih dahulu');
return;
}
if (selectedSatuanWaktuSewa.value == null) {
_showError('Silakan pilih satuan waktu sewa');
return;
}
if (selectedDurasi.value <= 0) {
_showError('Durasi sewa harus lebih dari 0');
return;
}
final userId = authProvider.getCurrentUserId();
if (userId == null) {
_showError('Anda belum login, silakan login terlebih dahulu');
return;
}
try {
final result = await _asetProvider.orderAset(
userId: userId,
asetId: selectedAset.value!.id,
satuanWaktuSewaId: selectedSatuanWaktuSewa.value!.id,
durasi: selectedDurasi.value,
totalHarga: totalHarga.value,
);
if (result) {
Get.snackbar(
'Sukses',
'Pesanan berhasil dibuat',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
colorText: Colors.white,
);
resetSelections();
} else {
_showError('Gagal membuat pesanan');
}
} catch (e) {
_showError('Terjadi kesalahan: $e');
}
}
// Method untuk reset pilihan setelah pemesanan berhasil
void resetSelections() {
selectedAset.value = null;
selectedSatuanWaktuSewa.value = null;
selectedDurasi.value = 1;
totalHarga.value = 0;
}
// Load packages data from paket table
Future<void> loadPakets() async {
try {
isLoadingPakets.value = true;
// Call the provider method to get paket data
final paketData = await _asetProvider.getPakets();
// Debug paket data
debugPrint('===== DEBUG PAKET & SATUAN WAKTU SEWA =====');
for (var paket in paketData) {
debugPrint('Paket: ${paket['nama']} (ID: ${paket['id']})');
if (paket['satuanWaktuSewa'] == null ||
paket['satuanWaktuSewa'].isEmpty) {
debugPrint(' - Tidak ada satuan waktu sewa yang terkait');
} else {
debugPrint(
' - Memiliki ${paket['satuanWaktuSewa'].length} satuan waktu sewa:',
);
for (var sws in paket['satuanWaktuSewa']) {
debugPrint(' * ID: ${sws['id']}');
debugPrint(' Paket ID: ${sws['paket_id']}');
debugPrint(' Satuan Waktu ID: ${sws['satuan_waktu_id']}');
debugPrint(' Harga: ${sws['harga']}');
debugPrint(' Nama Satuan Waktu: ${sws['nama_satuan_waktu']}');
debugPrint(' -----');
}
}
debugPrint('=====================================');
}
pakets.assignAll(paketData);
filteredPakets.assignAll(paketData);
debugPrint('Loaded ${paketData.length} paket successfully');
} catch (e) {
debugPrint('Error loading pakets: $e');
Get.snackbar(
'Error',
'Terjadi kesalahan saat memuat data paket',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
} finally {
isLoadingPakets.value = false;
}
}
// Method to filter pakets based on search query
void filterPakets(String query) {
if (query.isEmpty) {
filteredPakets.assignAll(pakets);
} else {
filteredPakets.assignAll(
pakets
.where(
(paket) => paket['nama'].toString().toLowerCase().contains(
query.toLowerCase(),
),
)
.toList(),
);
}
}
void refreshPakets() {
loadPakets();
}
// Method to load paket data
Future<void> loadPaketData() async {
try {
isLoadingPakets.value = true;
final result = await _asetProvider.getPakets();
if (result != null) {
pakets.clear();
filteredPakets.clear();
pakets.addAll(result);
filteredPakets.addAll(result);
}
} catch (e) {
debugPrint('Error loading pakets: $e');
Get.snackbar(
'Error',
'Gagal memuat data paket. Silakan coba lagi nanti.',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
} finally {
isLoadingPakets.value = false;
}
}
// Method for placing an order for a paket
Future<void> placeOrderPaket({
required String paketId,
required String satuanWaktuSewaId,
required int durasi,
required int totalHarga,
}) async {
debugPrint('===== PLACE ORDER PAKET =====');
debugPrint('paketId: $paketId');
debugPrint('satuanWaktuSewaId: $satuanWaktuSewaId');
debugPrint('durasi: $durasi');
debugPrint('totalHarga: $totalHarga');
final userId = authProvider.getCurrentUserId();
if (userId == null) {
_showError('Anda belum login, silakan login terlebih dahulu');
return;
}
try {
final result = await _asetProvider.orderPaket(
userId: userId,
paketId: paketId,
satuanWaktuSewaId: satuanWaktuSewaId,
durasi: durasi,
totalHarga: totalHarga,
);
if (result) {
Get.snackbar(
'Sukses',
'Pesanan paket berhasil dibuat',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
colorText: Colors.white,
);
} else {
_showError('Gagal membuat pesanan paket');
}
} catch (e) {
_showError('Terjadi kesalahan: $e');
}
}
}

View File

@ -0,0 +1,180 @@
import 'package:get/get.dart';
import '../../../data/providers/auth_provider.dart';
import '../../../routes/app_routes.dart';
import '../../../services/navigation_service.dart';
class WargaDashboardController extends GetxController {
// Dependency injection
final AuthProvider _authProvider = Get.find<AuthProvider>();
final NavigationService navigationService = Get.find<NavigationService>();
// User data
final userName = 'Pengguna Warga'.obs;
final userRole = 'Warga'.obs;
final userAvatar = Rx<String?>(null);
final userEmail = ''.obs;
final userNik = ''.obs;
final userPhone = ''.obs;
final userAddress = ''.obs;
// Navigation state is now managed by NavigationService
// Sample data (would be loaded from API)
final activeRentals = <Map<String, dynamic>>[].obs;
// Active bills
final activeBills = <Map<String, dynamic>>[].obs;
// Active penalties
final activePenalties = <Map<String, dynamic>>[].obs;
@override
void onInit() {
super.onInit();
// Set navigation index to Home (0)
navigationService.setNavIndex(0);
// Load user data
_loadUserData();
// Load sample data
_loadSampleData();
// Load dummy data for bills and penalties
loadDummyData();
// Load unpaid rentals
loadUnpaidRentals();
}
Future<void> _loadUserData() async {
try {
// Get the full name from warga_desa table
final fullName = await _authProvider.getUserFullName();
if (fullName != null && fullName.isNotEmpty) {
userName.value = fullName;
}
// Get the avatar URL
final avatar = await _authProvider.getUserAvatar();
userAvatar.value = avatar;
// Get the role name
final roleId = await _authProvider.getUserRoleId();
if (roleId != null) {
final roleName = await _authProvider.getRoleName(roleId);
if (roleName != null) {
userRole.value = roleName;
}
}
// Load additional user data
// In a real app, these would come from the API/database
userEmail.value = await _authProvider.getUserEmail() ?? '';
userNik.value = await _authProvider.getUserNIK() ?? '';
userPhone.value = await _authProvider.getUserPhone() ?? '';
userAddress.value = await _authProvider.getUserAddress() ?? '';
} catch (e) {
print('Error loading user data: $e');
}
}
void _loadSampleData() {
// Clear any existing data
activeRentals.clear();
// Load active rentals from API
// For now, using sample data
activeRentals.add({
'id': '1',
'name': 'Kursi',
'time': '24 April 2023, 10:00 - 12:00',
'duration': '2 jam',
'price': 'Rp50.000',
'can_extend': true,
});
}
void extendRental(String rentalId) {
// Implementasi untuk memperpanjang sewa
// Seharusnya melakukan API call ke backend
}
void endRental(String rentalId) {
// Implementasi untuk mengakhiri sewa
// Seharusnya melakukan API call ke backend
}
void navigateToRentals() {
// Navigate to SewaAset using the navigation service
navigationService.toSewaAset();
}
void refreshData() {
// Refresh data from repository
_loadSampleData();
loadDummyData();
}
void onNavItemTapped(int index) {
if (navigationService.currentNavIndex.value == index) {
return; // Don't do anything if same tab
}
navigationService.setNavIndex(index);
switch (index) {
case 0:
// Already on Home tab
break;
case 1:
// Navigate to Sewa page
navigationService.toWargaSewa();
break;
}
}
void logout() async {
await _authProvider.signOut();
navigationService.toLogin();
}
void loadDummyData() {
// Dummy active bills
activeBills.clear();
activeBills.add({
'id': '1',
'title': 'Tagihan Air',
'due_date': '30 Apr 2023',
'amount': 'Rp 125.000',
});
activeBills.add({
'id': '2',
'title': 'Sewa Aula Desa',
'due_date': '15 Apr 2023',
'amount': 'Rp 350.000',
});
// Dummy active penalties
activePenalties.clear();
activePenalties.add({
'id': '1',
'title': 'Keterlambatan Sewa Traktor',
'days_late': '7',
'amount': 'Rp 75.000',
});
}
Future<void> loadUnpaidRentals() async {
try {
final results = await _authProvider.getSewaAsetByStatus([
'MENUNGGU PEMBAYARAN',
'PEMBAYARANAN DENDA',
]);
activeBills.value = results;
} catch (e) {
print('Error loading unpaid rentals: $e');
}
}
}

View File

@ -0,0 +1,710 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../../routes/app_routes.dart';
import '../../../services/navigation_service.dart';
import '../../../data/providers/auth_provider.dart';
import '../../../data/providers/aset_provider.dart';
class WargaSewaController extends GetxController
with GetSingleTickerProviderStateMixin {
late TabController tabController;
// Get navigation service
final NavigationService navigationService = Get.find<NavigationService>();
// Get auth provider for user data and sewa_aset queries
final AuthProvider authProvider = Get.find<AuthProvider>();
// Get aset provider for asset data
final AsetProvider asetProvider = Get.find<AsetProvider>();
// Observable lists for different rental statuses
final rentals = <Map<String, dynamic>>[].obs;
final pendingRentals = <Map<String, dynamic>>[].obs;
final acceptedRentals = <Map<String, dynamic>>[].obs;
final completedRentals = <Map<String, dynamic>>[].obs;
final cancelledRentals = <Map<String, dynamic>>[].obs;
// Loading states
final isLoading = false.obs;
final isLoadingPending = false.obs;
final isLoadingAccepted = false.obs;
final isLoadingCompleted = false.obs;
final isLoadingCancelled = false.obs;
@override
void onInit() {
super.onInit();
// Ensure tab index is set to Sewa (1)
navigationService.setNavIndex(1);
// Initialize tab controller with 6 tabs
tabController = TabController(length: 6, vsync: this);
// Set initial tab and ensure tab view is updated
tabController.index = 0;
// Load real rental data for all tabs
loadRentalsData();
loadPendingRentals();
loadAcceptedRentals();
loadCompletedRentals();
loadCancelledRentals();
// Listen to tab changes to update state if needed
tabController.addListener(() {
// Update selected tab index when changed via swipe
final int currentIndex = tabController.index;
debugPrint('Tab changed to index: $currentIndex');
// Load data for the selected tab if not already loaded
switch (currentIndex) {
case 0: // Belum Bayar
if (rentals.isEmpty && !isLoading.value) {
loadRentalsData();
}
break;
case 1: // Pending
if (pendingRentals.isEmpty && !isLoadingPending.value) {
loadPendingRentals();
}
break;
case 2: // Diterima
if (acceptedRentals.isEmpty && !isLoadingAccepted.value) {
loadAcceptedRentals();
}
break;
case 3: // Aktif
// Add Aktif tab logic when needed
break;
case 4: // Selesai
if (completedRentals.isEmpty && !isLoadingCompleted.value) {
loadCompletedRentals();
}
break;
case 5: // Dibatalkan
if (cancelledRentals.isEmpty && !isLoadingCancelled.value) {
loadCancelledRentals();
}
break;
}
});
}
@override
void onReady() {
super.onReady();
// Ensure nav index is set to Sewa (1) when the controller is ready
// This helps maintain correct state during hot reload
navigationService.setNavIndex(1);
}
@override
void onClose() {
tabController.dispose();
super.onClose();
}
// Load real data from sewa_aset table
Future<void> loadRentalsData() async {
try {
isLoading.value = true;
// Clear existing data
rentals.clear();
// Get sewa_aset data with status "MENUNGGU PEMBAYARAN" or "PEMBAYARAN DENDA"
final sewaAsetList = await authProvider.getSewaAsetByStatus([
'MENUNGGU PEMBAYARAN',
'PEMBAYARAN DENDA'
]);
debugPrint('Fetched ${sewaAsetList.length} sewa_aset records');
// Process each sewa_aset record
for (var sewaAset in sewaAsetList) {
// Get asset details if aset_id is available
String assetName = 'Aset';
String? imageUrl;
String namaSatuanWaktu = sewaAset['nama_satuan_waktu'] ?? 'jam';
if (sewaAset['aset_id'] != null) {
final asetData = await asetProvider.getAsetById(sewaAset['aset_id']);
if (asetData != null) {
assetName = asetData.nama;
imageUrl = asetData.imageUrl;
}
}
// Parse waktu mulai and waktu selesai
DateTime? waktuMulai;
DateTime? waktuSelesai;
String waktuSewa = '';
String tanggalSewa = '';
String jamMulai = '';
String jamSelesai = '';
String rentangWaktu = '';
if (sewaAset['waktu_mulai'] != null && sewaAset['waktu_selesai'] != null) {
waktuMulai = DateTime.parse(sewaAset['waktu_mulai']);
waktuSelesai = DateTime.parse(sewaAset['waktu_selesai']);
// Format for display
final formatTanggal = DateFormat('dd-MM-yyyy');
final formatWaktu = DateFormat('HH:mm');
final formatTanggalLengkap = DateFormat('dd MMMM yyyy', 'id_ID');
tanggalSewa = formatTanggalLengkap.format(waktuMulai);
jamMulai = formatWaktu.format(waktuMulai);
jamSelesai = formatWaktu.format(waktuSelesai);
// Format based on satuan waktu
if (namaSatuanWaktu.toLowerCase() == 'jam') {
// For hours, show time range on same day
rentangWaktu = '$jamMulai - $jamSelesai';
} else if (namaSatuanWaktu.toLowerCase() == 'hari') {
// For days, show date range
final tanggalMulai = formatTanggalLengkap.format(waktuMulai);
final tanggalSelesai = formatTanggalLengkap.format(waktuSelesai);
rentangWaktu = '$tanggalMulai - $tanggalSelesai';
} else {
// Default format
rentangWaktu = '$jamMulai - $jamSelesai';
}
// Full time format for waktuSewa
waktuSewa = '${formatTanggal.format(waktuMulai)} | ${formatWaktu.format(waktuMulai)} - '
'${formatTanggal.format(waktuSelesai)} | ${formatWaktu.format(waktuSelesai)}';
}
// Format price
String totalPrice = 'Rp 0';
if (sewaAset['total'] != null) {
final formatter = NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
);
totalPrice = formatter.format(sewaAset['total']);
}
// Add to rentals list
rentals.add({
'id': sewaAset['id'] ?? '',
'name': assetName,
'imageUrl': imageUrl ?? 'assets/images/gambar_pendukung.jpg',
'jumlahUnit': sewaAset['kuantitas'] ?? 0,
'waktuSewa': waktuSewa,
'duration': '${sewaAset['durasi'] ?? 0} ${namaSatuanWaktu}',
'status': sewaAset['status'] ?? 'MENUNGGU PEMBAYARAN',
'totalPrice': totalPrice,
'countdown': '00:59:59', // Default countdown
'tanggalSewa': tanggalSewa,
'jamMulai': jamMulai,
'jamSelesai': jamSelesai,
'rentangWaktu': rentangWaktu,
'namaSatuanWaktu': namaSatuanWaktu,
'waktuMulai': sewaAset['waktu_mulai'],
'waktuSelesai': sewaAset['waktu_selesai'],
});
}
debugPrint('Processed ${rentals.length} rental records');
} catch (e) {
debugPrint('Error loading rentals data: $e');
} finally {
isLoading.value = false;
}
}
// Navigation methods
void navigateToRentals() {
navigationService.toSewaAset();
}
void onNavItemTapped(int index) {
if (navigationService.currentNavIndex.value == index) return;
navigationService.setNavIndex(index);
switch (index) {
case 0:
// Navigate to Home
Get.offNamed(Routes.WARGA_DASHBOARD);
break;
case 1:
// Already on Sewa tab
break;
case 2:
// Navigate to Langganan
Get.offNamed(Routes.LANGGANAN);
break;
}
}
// Actions
void cancelRental(String id) {
Get.snackbar(
'Info',
'Pembatalan berhasil',
snackPosition: SnackPosition.BOTTOM,
);
}
// Navigate to payment page with the selected rental data
void viewRentalDetail(Map<String, dynamic> rental) {
debugPrint('Navigating to payment page with rental ID: ${rental['id']}');
// Navigate to payment page with rental data
Get.toNamed(
Routes.PEMBAYARAN_SEWA,
arguments: {
'orderId': rental['id'],
'rentalData': rental,
},
);
}
void payRental(String id) {
Get.snackbar(
'Info',
'Navigasi ke halaman pembayaran',
snackPosition: SnackPosition.BOTTOM,
);
}
// Load data for the Selesai tab (status: SELESAI)
Future<void> loadCompletedRentals() async {
try {
isLoadingCompleted.value = true;
// Clear existing data
completedRentals.clear();
// Get sewa_aset data with status "SELESAI"
final sewaAsetList = await authProvider.getSewaAsetByStatus(['SELESAI']);
debugPrint('Fetched ${sewaAsetList.length} completed sewa_aset records');
// Process each sewa_aset record
for (var sewaAset in sewaAsetList) {
// Get asset details if aset_id is available
String assetName = 'Aset';
String? imageUrl;
String namaSatuanWaktu = sewaAset['nama_satuan_waktu'] ?? 'jam';
if (sewaAset['aset_id'] != null) {
final asetData = await asetProvider.getAsetById(sewaAset['aset_id']);
if (asetData != null) {
assetName = asetData.nama;
imageUrl = asetData.imageUrl;
}
}
// Parse waktu mulai and waktu selesai
DateTime? waktuMulai;
DateTime? waktuSelesai;
String waktuSewa = '';
String tanggalSewa = '';
String jamMulai = '';
String jamSelesai = '';
String rentangWaktu = '';
if (sewaAset['waktu_mulai'] != null && sewaAset['waktu_selesai'] != null) {
waktuMulai = DateTime.parse(sewaAset['waktu_mulai']);
waktuSelesai = DateTime.parse(sewaAset['waktu_selesai']);
// Format for display
final formatTanggal = DateFormat('dd-MM-yyyy');
final formatWaktu = DateFormat('HH:mm');
final formatTanggalLengkap = DateFormat('dd MMMM yyyy', 'id_ID');
tanggalSewa = formatTanggalLengkap.format(waktuMulai);
jamMulai = formatWaktu.format(waktuMulai);
jamSelesai = formatWaktu.format(waktuSelesai);
// Format based on satuan waktu
if (namaSatuanWaktu.toLowerCase() == 'jam') {
// For hours, show time range on same day
rentangWaktu = '$jamMulai - $jamSelesai';
} else if (namaSatuanWaktu.toLowerCase() == 'hari') {
// For days, show date range
final tanggalMulai = formatTanggalLengkap.format(waktuMulai);
final tanggalSelesai = formatTanggalLengkap.format(waktuSelesai);
rentangWaktu = '$tanggalMulai - $tanggalSelesai';
} else {
// Default format
rentangWaktu = '$jamMulai - $jamSelesai';
}
// Full time format for waktuSewa
waktuSewa = '${formatTanggal.format(waktuMulai)} | ${formatWaktu.format(waktuMulai)} - '
'${formatTanggal.format(waktuSelesai)} | ${formatWaktu.format(waktuSelesai)}';
}
// Format price
String totalPrice = 'Rp 0';
if (sewaAset['total'] != null) {
final formatter = NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
);
totalPrice = formatter.format(sewaAset['total']);
}
// Add to completed rentals list
completedRentals.add({
'id': sewaAset['id'] ?? '',
'name': assetName,
'imageUrl': imageUrl ?? 'assets/images/gambar_pendukung.jpg',
'jumlahUnit': sewaAset['kuantitas'] ?? 0,
'waktuSewa': waktuSewa,
'duration': '${sewaAset['durasi'] ?? 0} ${namaSatuanWaktu}',
'status': sewaAset['status'] ?? 'SELESAI',
'totalPrice': totalPrice,
'tanggalSewa': tanggalSewa,
'jamMulai': jamMulai,
'jamSelesai': jamSelesai,
'rentangWaktu': rentangWaktu,
'namaSatuanWaktu': namaSatuanWaktu,
'waktuMulai': sewaAset['waktu_mulai'],
'waktuSelesai': sewaAset['waktu_selesai'],
});
}
debugPrint('Processed ${completedRentals.length} completed rental records');
} catch (e) {
debugPrint('Error loading completed rentals data: $e');
} finally {
isLoadingCompleted.value = false;
}
}
// Load data for the Dibatalkan tab (status: DIBATALKAN)
Future<void> loadCancelledRentals() async {
try {
isLoadingCancelled.value = true;
// Clear existing data
cancelledRentals.clear();
// Get sewa_aset data with status "DIBATALKAN"
final sewaAsetList = await authProvider.getSewaAsetByStatus(['DIBATALKAN']);
debugPrint('Fetched ${sewaAsetList.length} cancelled sewa_aset records');
// Process each sewa_aset record
for (var sewaAset in sewaAsetList) {
// Get asset details if aset_id is available
String assetName = 'Aset';
String? imageUrl;
String namaSatuanWaktu = sewaAset['nama_satuan_waktu'] ?? 'jam';
if (sewaAset['aset_id'] != null) {
final asetData = await asetProvider.getAsetById(sewaAset['aset_id']);
if (asetData != null) {
assetName = asetData.nama;
imageUrl = asetData.imageUrl;
}
}
// Parse waktu mulai and waktu selesai
DateTime? waktuMulai;
DateTime? waktuSelesai;
String waktuSewa = '';
String tanggalSewa = '';
String jamMulai = '';
String jamSelesai = '';
String rentangWaktu = '';
if (sewaAset['waktu_mulai'] != null && sewaAset['waktu_selesai'] != null) {
waktuMulai = DateTime.parse(sewaAset['waktu_mulai']);
waktuSelesai = DateTime.parse(sewaAset['waktu_selesai']);
// Format for display
final formatTanggal = DateFormat('dd-MM-yyyy');
final formatWaktu = DateFormat('HH:mm');
final formatTanggalLengkap = DateFormat('dd MMMM yyyy', 'id_ID');
tanggalSewa = formatTanggalLengkap.format(waktuMulai);
jamMulai = formatWaktu.format(waktuMulai);
jamSelesai = formatWaktu.format(waktuSelesai);
// Format based on satuan waktu
if (namaSatuanWaktu.toLowerCase() == 'jam') {
// For hours, show time range on same day
rentangWaktu = '$jamMulai - $jamSelesai';
} else if (namaSatuanWaktu.toLowerCase() == 'hari') {
// For days, show date range
final tanggalMulai = formatTanggalLengkap.format(waktuMulai);
final tanggalSelesai = formatTanggalLengkap.format(waktuSelesai);
rentangWaktu = '$tanggalMulai - $tanggalSelesai';
} else {
// Default format
rentangWaktu = '$jamMulai - $jamSelesai';
}
// Full time format for waktuSewa
waktuSewa = '${formatTanggal.format(waktuMulai)} | ${formatWaktu.format(waktuMulai)} - '
'${formatTanggal.format(waktuSelesai)} | ${formatWaktu.format(waktuSelesai)}';
}
// Format price
String totalPrice = 'Rp 0';
if (sewaAset['total'] != null) {
final formatter = NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
);
totalPrice = formatter.format(sewaAset['total']);
}
// Add to cancelled rentals list
cancelledRentals.add({
'id': sewaAset['id'] ?? '',
'name': assetName,
'imageUrl': imageUrl ?? 'assets/images/gambar_pendukung.jpg',
'jumlahUnit': sewaAset['kuantitas'] ?? 0,
'waktuSewa': waktuSewa,
'duration': '${sewaAset['durasi'] ?? 0} ${namaSatuanWaktu}',
'status': sewaAset['status'] ?? 'DIBATALKAN',
'totalPrice': totalPrice,
'tanggalSewa': tanggalSewa,
'jamMulai': jamMulai,
'jamSelesai': jamSelesai,
'rentangWaktu': rentangWaktu,
'namaSatuanWaktu': namaSatuanWaktu,
'waktuMulai': sewaAset['waktu_mulai'],
'waktuSelesai': sewaAset['waktu_selesai'],
'alasanPembatalan': sewaAset['alasan_pembatalan'] ?? '-',
});
}
debugPrint('Processed ${cancelledRentals.length} cancelled rental records');
} catch (e) {
debugPrint('Error loading cancelled rentals data: $e');
} finally {
isLoadingCancelled.value = false;
}
}
// Load data for the Pending tab (status: PERIKSA PEMBAYARAN)
Future<void> loadPendingRentals() async {
try {
isLoadingPending.value = true;
// Clear existing data
pendingRentals.clear();
// Get sewa_aset data with status "PERIKSA PEMBAYARAN"
final sewaAsetList = await authProvider.getSewaAsetByStatus(['PERIKSA PEMBAYARAN']);
debugPrint('Fetched ${sewaAsetList.length} pending sewa_aset records');
// Process each sewa_aset record
for (var sewaAset in sewaAsetList) {
// Get asset details if aset_id is available
String assetName = 'Aset';
String? imageUrl;
String namaSatuanWaktu = sewaAset['nama_satuan_waktu'] ?? 'jam';
if (sewaAset['aset_id'] != null) {
final asetData = await asetProvider.getAsetById(sewaAset['aset_id']);
if (asetData != null) {
assetName = asetData.nama;
imageUrl = asetData.imageUrl;
}
}
// Parse waktu mulai and waktu selesai
DateTime? waktuMulai;
DateTime? waktuSelesai;
String waktuSewa = '';
String tanggalSewa = '';
String jamMulai = '';
String jamSelesai = '';
String rentangWaktu = '';
if (sewaAset['waktu_mulai'] != null && sewaAset['waktu_selesai'] != null) {
waktuMulai = DateTime.parse(sewaAset['waktu_mulai']);
waktuSelesai = DateTime.parse(sewaAset['waktu_selesai']);
// Format for display
final formatTanggal = DateFormat('dd-MM-yyyy');
final formatWaktu = DateFormat('HH:mm');
final formatTanggalLengkap = DateFormat('dd MMMM yyyy', 'id_ID');
tanggalSewa = formatTanggalLengkap.format(waktuMulai);
jamMulai = formatWaktu.format(waktuMulai);
jamSelesai = formatWaktu.format(waktuSelesai);
// Format based on satuan waktu
if (namaSatuanWaktu.toLowerCase() == 'jam') {
// For hours, show time range on same day
rentangWaktu = '$jamMulai - $jamSelesai';
} else if (namaSatuanWaktu.toLowerCase() == 'hari') {
// For days, show date range
final tanggalMulai = formatTanggalLengkap.format(waktuMulai);
final tanggalSelesai = formatTanggalLengkap.format(waktuSelesai);
rentangWaktu = '$tanggalMulai - $tanggalSelesai';
} else {
// Default format
rentangWaktu = '$jamMulai - $jamSelesai';
}
// Full time format for waktuSewa
waktuSewa = '${formatTanggal.format(waktuMulai)} | ${formatWaktu.format(waktuMulai)} - '
'${formatTanggal.format(waktuSelesai)} | ${formatWaktu.format(waktuSelesai)}';
}
// Format price
String totalPrice = 'Rp 0';
if (sewaAset['total'] != null) {
final formatter = NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
);
totalPrice = formatter.format(sewaAset['total']);
}
// Add to pending rentals list
pendingRentals.add({
'id': sewaAset['id'] ?? '',
'name': assetName,
'imageUrl': imageUrl ?? 'assets/images/gambar_pendukung.jpg',
'jumlahUnit': sewaAset['kuantitas'] ?? 0,
'waktuSewa': waktuSewa,
'duration': '${sewaAset['durasi'] ?? 0} ${namaSatuanWaktu}',
'status': sewaAset['status'] ?? 'PERIKSA PEMBAYARAN',
'totalPrice': totalPrice,
'tanggalSewa': tanggalSewa,
'jamMulai': jamMulai,
'jamSelesai': jamSelesai,
'rentangWaktu': rentangWaktu,
'namaSatuanWaktu': namaSatuanWaktu,
'waktuMulai': sewaAset['waktu_mulai'],
'waktuSelesai': sewaAset['waktu_selesai'],
});
}
debugPrint('Processed ${pendingRentals.length} pending rental records');
} catch (e) {
debugPrint('Error loading pending rentals data: $e');
} finally {
isLoadingPending.value = false;
}
}
// Load data for the Diterima tab (status: DITERIMA)
Future<void> loadAcceptedRentals() async {
try {
isLoadingAccepted.value = true;
// Clear existing data
acceptedRentals.clear();
// Get sewa_aset data with status "DITERIMA"
final sewaAsetList = await authProvider.getSewaAsetByStatus(['DITERIMA']);
debugPrint('Fetched ${sewaAsetList.length} accepted sewa_aset records');
// Process each sewa_aset record
for (var sewaAset in sewaAsetList) {
// Get asset details if aset_id is available
String assetName = 'Aset';
String? imageUrl;
String namaSatuanWaktu = sewaAset['nama_satuan_waktu'] ?? 'jam';
if (sewaAset['aset_id'] != null) {
final asetData = await asetProvider.getAsetById(sewaAset['aset_id']);
if (asetData != null) {
assetName = asetData.nama;
imageUrl = asetData.imageUrl;
}
}
// Parse waktu mulai and waktu selesai
DateTime? waktuMulai;
DateTime? waktuSelesai;
String waktuSewa = '';
String tanggalSewa = '';
String jamMulai = '';
String jamSelesai = '';
String rentangWaktu = '';
if (sewaAset['waktu_mulai'] != null && sewaAset['waktu_selesai'] != null) {
waktuMulai = DateTime.parse(sewaAset['waktu_mulai']);
waktuSelesai = DateTime.parse(sewaAset['waktu_selesai']);
// Format for display
final formatTanggal = DateFormat('dd-MM-yyyy');
final formatWaktu = DateFormat('HH:mm');
final formatTanggalLengkap = DateFormat('dd MMMM yyyy', 'id_ID');
tanggalSewa = formatTanggalLengkap.format(waktuMulai);
jamMulai = formatWaktu.format(waktuMulai);
jamSelesai = formatWaktu.format(waktuSelesai);
// Format based on satuan waktu
if (namaSatuanWaktu.toLowerCase() == 'jam') {
// For hours, show time range on same day
rentangWaktu = '$jamMulai - $jamSelesai';
} else if (namaSatuanWaktu.toLowerCase() == 'hari') {
// For days, show date range
final tanggalMulai = formatTanggalLengkap.format(waktuMulai);
final tanggalSelesai = formatTanggalLengkap.format(waktuSelesai);
rentangWaktu = '$tanggalMulai - $tanggalSelesai';
} else {
// Default format
rentangWaktu = '$jamMulai - $jamSelesai';
}
// Full time format for waktuSewa
waktuSewa = '${formatTanggal.format(waktuMulai)} | ${formatWaktu.format(waktuMulai)} - '
'${formatTanggal.format(waktuSelesai)} | ${formatWaktu.format(waktuSelesai)}';
}
// Format price
String totalPrice = 'Rp 0';
if (sewaAset['total'] != null) {
final formatter = NumberFormat.currency(
locale: 'id',
symbol: 'Rp ',
decimalDigits: 0,
);
totalPrice = formatter.format(sewaAset['total']);
}
// Add to accepted rentals list
acceptedRentals.add({
'id': sewaAset['id'] ?? '',
'name': assetName,
'imageUrl': imageUrl ?? 'assets/images/gambar_pendukung.jpg',
'jumlahUnit': sewaAset['kuantitas'] ?? 0,
'waktuSewa': waktuSewa,
'duration': '${sewaAset['durasi'] ?? 0} ${namaSatuanWaktu}',
'status': sewaAset['status'] ?? 'DITERIMA',
'totalPrice': totalPrice,
'tanggalSewa': tanggalSewa,
'jamMulai': jamMulai,
'jamSelesai': jamSelesai,
'rentangWaktu': rentangWaktu,
'namaSatuanWaktu': namaSatuanWaktu,
'waktuMulai': sewaAset['waktu_mulai'],
'waktuSelesai': sewaAset['waktu_selesai'],
});
}
debugPrint('Processed ${acceptedRentals.length} accepted rental records');
} catch (e) {
debugPrint('Error loading accepted rentals data: $e');
} finally {
isLoadingAccepted.value = false;
}
}
}