TKK_E32230148/lib/pages/history_page.dart

219 lines
8.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class HistoryPage extends StatelessWidget {
final FirebaseFirestore firestore;
final bool canClearHistory;
const HistoryPage({
super.key,
required this.firestore,
this.canClearHistory = false,
});
Future<void> resetRiwayatAkses(BuildContext context) async {
final snapshot = await firestore.collection("access_logs").get();
final batch = firestore.batch();
for (var doc in snapshot.docs) {
batch.delete(doc.reference);
}
await batch.commit();
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Access logs successfully cleared")),
);
}
}
void konfirmasiResetDialog(BuildContext context) {
showDialog(
context: context,
builder: (_) => AlertDialog(
backgroundColor: const Color(0xff111111),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: const Text("Clear Logs?", style: TextStyle(color: Colors.white)),
content: const Text(
"Are you sure you want to delete all access history?",
style: TextStyle(color: Colors.white70),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text("Cancel"),
),
TextButton(
onPressed: () {
Navigator.pop(context);
resetRiwayatAkses(context);
},
child: const Text("Clear All", style: TextStyle(color: Colors.redAccent)),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
floatingActionButton: canClearHistory
? FloatingActionButton(
backgroundColor: Colors.redAccent.withOpacity(0.9),
elevation: 8,
onPressed: () => konfirmasiResetDialog(context),
tooltip: "Reset History",
child: const Icon(Icons.delete_sweep_rounded, color: Colors.white, size: 28),
)
: null,
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(bottom: 20),
child: Text(
'ACCESS HISTORY',
style: TextStyle(
color: Colors.white,
fontSize: 32,
fontWeight: FontWeight.bold,
letterSpacing: 1,
),
),
),
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: firestore
.collection("access_logs")
.orderBy("timestamp", descending: true)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator(color: Colors.blueAccent));
}
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
return const Center(
child: Text(
"No access logs available",
style: TextStyle(color: Colors.white38, fontSize: 16),
),
);
}
final logs = snapshot.data!.docs;
return ListView.builder(
itemCount: logs.length,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(bottom: 80),
itemBuilder: (context, index) {
final log = logs[index].data() as Map<String, dynamic>;
String currentStatus = (log["status"] ?? "").toString();
final appStatuses = {"APP_OPEN", "APP_CLOSE"};
final manualStatuses = {"MANUAL_OPEN", "MANUAL_CLOSE"};
bool isGranted = appStatuses.contains(currentStatus) ||
manualStatuses.contains(currentStatus) ||
currentStatus == "ACCESS_GRANTED" ||
currentStatus == "SUCCESS" ||
currentStatus.contains("GRANT") ||
currentStatus.contains("SUCCESS") ||
currentStatus.contains("ACCEPT") ||
currentStatus.contains("OK");
String label;
if (appStatuses.contains(currentStatus) || manualStatuses.contains(currentStatus)) {
label = currentStatus.replaceAll('_', ' ');
} else {
label = isGranted ? "GRANTED" : "DENIED";
}
Timestamp? t = log["timestamp"] as Timestamp?;
String waktu = "-";
if (t != null) {
DateTime dt = t.toDate();
waktu = "${dt.day.toString().padLeft(2, '0')}/${dt.month.toString().padLeft(2, '0')} ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}";
} else {
DateTime dt = DateTime.now();
waktu = "${dt.day.toString().padLeft(2, '0')}/${dt.month.toString().padLeft(2, '0')} ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}";
}
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
color: const Color(0xff111111),
borderRadius: BorderRadius.circular(18),
border: Border.all(
color: isGranted ? Colors.green.withOpacity(0.2) : Colors.red.withOpacity(0.2),
width: 1.5,
),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: isGranted ? Colors.green.withOpacity(0.1) : Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
isGranted ? Icons.check_circle_rounded : Icons.cancel_rounded,
color: isGranted ? Colors.greenAccent : Colors.redAccent,
size: 26,
),
),
const SizedBox(width: 15),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
log["name"] ?? "Unknown Card",
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
const SizedBox(height: 4),
Text(
"UID: ${log["uid"]}",
style: const TextStyle(color: Colors.white54, fontSize: 13),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
waktu,
style: const TextStyle(color: Colors.white38, fontSize: 12),
),
const SizedBox(height: 4),
Text(
label,
style: TextStyle(
color: isGranted ? Colors.greenAccent : Colors.redAccent,
fontSize: 11,
fontWeight: FontWeight.bold,
),
),
],
),
],
),
);
},
);
},
),
),
],
),
);
}
}