MIF_E31221388/salonbooking/lib/karyawan/riwayat_bookings_karyawan.dart

219 lines
7.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class RiwayatBookingsKaryawanPage extends StatefulWidget {
final String token;
const RiwayatBookingsKaryawanPage({Key? key, required this.token}) : super(key: key);
@override
State<RiwayatBookingsKaryawanPage> createState() => _RiwayatBookingsKaryawanPageState();
}
class _RiwayatBookingsKaryawanPageState extends State<RiwayatBookingsKaryawanPage> {
Map<String, Map<String, List>> groupedBookings = {};
bool loading = true;
String? error;
final Color primaryColor = const Color(0xFFF06292);
@override
void initState() {
super.initState();
fetchAcceptedBookings();
}
Future<void> fetchAcceptedBookings() async {
setState(() {
loading = true;
error = null;
});
try {
final response = await http.get(
Uri.parse('http://angeliasalon.my.id/api/bookings/accepted'),
headers: {
'Authorization': 'Bearer ${widget.token}',
'Accept': 'application/json',
},
);
if (response.statusCode == 200) {
final List data = json.decode(response.body);
final Map<String, Map<String, List>> tempGrouped = {};
for (var booking in data) {
final pelangganName = booking['user']?['name'] ?? 'Tidak diketahui';
final tanggalBooking = booking['tanggal_booking'] ?? '-';
tempGrouped.putIfAbsent(pelangganName, () => {});
tempGrouped[pelangganName]!.putIfAbsent(tanggalBooking, () => []);
tempGrouped[pelangganName]![tanggalBooking]!.add(booking);
}
final sortedPelanggan = tempGrouped.keys.toList()..sort();
final Map<String, Map<String, List>> sortedGrouped = {};
for (var pelanggan in sortedPelanggan) {
final tanggalMap = tempGrouped[pelanggan]!;
final sortedTanggal = tanggalMap.keys.toList()..sort();
sortedGrouped[pelanggan] = {
for (var tgl in sortedTanggal) tgl: tanggalMap[tgl]!,
};
}
setState(() {
groupedBookings = sortedGrouped;
loading = false;
});
} else {
setState(() {
error = 'Failed to load accepted bookings, status code: ${response.statusCode}';
loading = false;
});
}
} catch (e) {
setState(() {
error = 'Error fetching accepted bookings: $e';
loading = false;
});
}
}
Widget bookingItem(Map booking) {
final service = booking['service'];
final jam = booking['jam'] ?? '-';
final status = booking['status'] ?? '-';
Color statusColor;
switch (status.toLowerCase()) {
case 'diterima':
statusColor = Colors.green.shade700;
break;
case 'menunggu':
statusColor = Colors.orange.shade700;
break;
case 'ditolak':
statusColor = Colors.red.shade700;
break;
default:
statusColor = Colors.grey.shade600;
}
return ListTile(
contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 0),
leading: const Icon(Icons.content_cut, color: Colors.pinkAccent),
title: Text(
service?['name'] ?? 'Layanan tidak diketahui',
style: const TextStyle(fontWeight: FontWeight.w600),
),
subtitle: Row(
children: [
Text('Jam: $jam', style: const TextStyle(fontSize: 13)),
const SizedBox(width: 16),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: statusColor,
borderRadius: BorderRadius.circular(12),
),
child: Text(
status.toUpperCase(),
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.w600, fontSize: 12),
),
)
],
),
);
}
Widget bookingGroupCard(String pelangganName, Map<String, List> tanggalMap) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
elevation: 4,
shadowColor: Colors.black26,
child: ExpansionTile(
tilePadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
childrenPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
expandedCrossAxisAlignment: CrossAxisAlignment.start,
title: Text(
pelangganName,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: primaryColor),
),
children: tanggalMap.entries.map((entry) {
final tanggal = entry.key;
final bookings = entry.value;
return Padding(
padding: const EdgeInsets.only(left: 16.0, bottom: 10),
child: Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
elevation: 2,
shadowColor: Colors.grey.withOpacity(0.2),
child: ExpansionTile(
tilePadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
childrenPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
title: Text(
'Tanggal: $tanggal',
style: TextStyle(
fontWeight: FontWeight.w600,
color: Colors.pink.shade400,
),
),
children: bookings.map((b) => bookingItem(b)).toList(),
),
),
);
}).toList(),
),
);
}
void openRiwayat() {
// optional navigation or leave empty
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Riwayat Booking Karyawan'),
backgroundColor: primaryColor,
elevation: 5,
),
body: loading
? Center(child: CircularProgressIndicator(color: primaryColor, strokeWidth: 3))
: error != null
? Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(error!,
style: TextStyle(fontSize: 16, color: Colors.red.shade700),
textAlign: TextAlign.center),
),
)
: groupedBookings.isEmpty
? const Center(
child: Text(
'Belum ada riwayat booking',
style: TextStyle(fontSize: 18, color: Colors.black54),
),
)
: RefreshIndicator(
onRefresh: fetchAcceptedBookings,
child: ListView(
physics: const AlwaysScrollableScrollPhysics(),
children: groupedBookings.entries
.map((e) => bookingGroupCard(e.key, e.value))
.toList(),
),
),
);
}
}