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 createState() => _RiwayatBookingsKaryawanPageState(); } class _RiwayatBookingsKaryawanPageState extends State { Map> groupedBookings = {}; bool loading = true; String? error; final Color primaryColor = const Color(0xFFF06292); @override void initState() { super.initState(); fetchAcceptedBookings(); } Future 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> 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> 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 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(), ), ), ); } }