fix(mobile): resolve laundry service price dynamically based on selectedJenisLayanan in recommendation cards and details

This commit is contained in:
micko samawa 2026-06-28 14:14:02 +07:00
parent 00dc5b4a96
commit c04f98eadf
4 changed files with 72 additions and 14 deletions

View File

@ -12,6 +12,8 @@ class Laundry {
final String jamTutup;
final double hargaPerKg;
final double hargaKiloan;
final double hargaHarian;
final double hargaJam;
final int waktuProses; // dalam jam
final String? deskripsi;
final String? fotoUtama;
@ -34,6 +36,8 @@ class Laundry {
required this.jamTutup,
required this.hargaPerKg,
required this.hargaKiloan,
required this.hargaHarian,
required this.hargaJam,
required this.waktuProses,
this.deskripsi,
this.fotoUtama,
@ -67,23 +71,34 @@ class Laundry {
hargaKiloan = double.tryParse(json['harga_kiloan'].toString()) ?? 0;
}
if ((harga == 0 || hargaKiloan == 0) &&
json['layanan'] != null &&
double hargaHarian = 0;
double hargaJam = 0;
if (json['layanan'] != null &&
(json['layanan'] as List).isNotEmpty) {
final layananList = json['layanan'] as List;
harga = harga > 0
? harga
: double.tryParse(layananList.first['harga']?.toString() ?? '0') ?? 0;
for (final item in layananList) {
final jenis = item['jenis_layanan']?.toString().toLowerCase();
final jenis = item['jenis_layanan']?.toString().toLowerCase() ?? '';
final itemHarga =
double.tryParse(item['harga']?.toString() ?? '0') ?? 0;
if (jenis == 'kiloan') {
if (jenis == 'harian' || jenis == 'kiloan' || jenis == 'reguler') {
hargaHarian = itemHarga;
hargaKiloan = itemHarga;
} else if (jenis == 'jam' || jenis == 'express' || jenis == 'kilat' || jenis == 'satuan') {
hargaJam = itemHarga;
}
}
}
// Fallback if not populated
if (hargaHarian == 0) hargaHarian = hargaKiloan > 0 ? hargaKiloan : harga;
if (hargaJam == 0) hargaJam = harga;
// Get foto from API and build gallery list
final List<GaleriLaundry> galleryList = [];
@ -129,6 +144,8 @@ class Laundry {
jamTutup: _parseTime(json['jam_tutup'], '20:00'),
hargaPerKg: harga,
hargaKiloan: hargaKiloan,
hargaHarian: hargaHarian,
hargaJam: hargaJam,
waktuProses: json['waktu_proses'] ?? 24,
deskripsi: json['deskripsi'],
fotoUtama: json['foto_utama'],
@ -196,7 +213,23 @@ class Laundry {
// Format harga dengan Rupiah
String get formattedHarga {
return 'Rp ${_formatRupiah(hargaPerKg)}';
return 'Rp ${_formatRupiah(hargaHarian > 0 ? hargaHarian : hargaPerKg)}';
}
// Format harga sesuai jenis layanan (harian / jam)
String formattedHargaFor(String? jenisLayanan) {
if (jenisLayanan == null || jenisLayanan.isEmpty) {
return formattedHarga;
}
final target = jenisLayanan.toLowerCase();
if (target == 'jam' || target == 'express' || target == 'kilat' || target == 'satuan') {
final val = hargaJam > 0 ? hargaJam : hargaPerKg;
return 'Rp ${_formatRupiah(val)}';
} else {
final val = hargaHarian > 0 ? hargaHarian : hargaPerKg;
return 'Rp ${_formatRupiah(val)}';
}
}
String _formatRupiah(double value) {

View File

@ -8,8 +8,13 @@ import '../widgets/app_placeholder.dart';
class LaundryDetailScreen extends StatefulWidget {
final Laundry laundry;
final String? selectedJenisLayanan;
const LaundryDetailScreen({super.key, required this.laundry});
const LaundryDetailScreen({
super.key,
required this.laundry,
this.selectedJenisLayanan,
});
@override
State<LaundryDetailScreen> createState() => _LaundryDetailScreenState();
@ -286,7 +291,7 @@ class _LaundryDetailScreenState extends State<LaundryDetailScreen> {
_buildHeaderChip(
icon: Icons.payments_rounded,
label:
'${widget.laundry.formattedHargaKiloan}/kg',
'${widget.laundry.formattedHargaFor(widget.selectedJenisLayanan)}/kg',
),
_buildHeaderChip(
icon: Icons.schedule_rounded,
@ -355,6 +360,23 @@ class _LaundryDetailScreenState extends State<LaundryDetailScreen> {
title: 'Harga',
child: Column(
children: [
if (widget.laundry.hargaHarian > 0) ...[
_buildPriceCard(
'Laundry Kiloan (Harian/Reguler)',
widget.laundry.formattedHargaFor("harian"),
Icons.scale,
const Color(0xFF00897B),
),
const SizedBox(height: 8),
],
if (widget.laundry.hargaJam > 0)
_buildPriceCard(
'Laundry Express (Jam/Satuan)',
widget.laundry.formattedHargaFor("jam"),
Icons.flash_on,
const Color(0xFFFF9800),
),
if (widget.laundry.hargaHarian == 0 && widget.laundry.hargaJam == 0)
_buildPriceCard(
'Laundry Kiloan',
widget.laundry.formattedHargaKiloan,

View File

@ -3101,6 +3101,7 @@ class _RecommendationScreenState extends State<RecommendationScreen> {
laundry: Laundry.fromJson(itemData),
userLatitude: _userLatitude,
userLongitude: _userLongitude,
selectedJenisLayanan: _selectedJenisLayanan,
),
),
],

View File

@ -11,6 +11,7 @@ class LaundryCard extends StatelessWidget {
final bool showRanking;
final double? userLatitude;
final double? userLongitude;
final String? selectedJenisLayanan;
const LaundryCard({
super.key,
@ -20,6 +21,7 @@ class LaundryCard extends StatelessWidget {
this.showRanking = false,
this.userLatitude,
this.userLongitude,
this.selectedJenisLayanan,
});
@override
@ -198,7 +200,7 @@ class LaundryCard extends StatelessWidget {
child: Row(
children: [
Text(
laundry.formattedHarga,
laundry.formattedHargaFor(selectedJenisLayanan),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,