Files
musadaq-saas/musadaq-app/lib/features/audit/views/audit_log_view.dart
2026-05-08 01:41:28 +03:00

205 lines
7.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/audit_log_controller.dart';
class AuditLogView extends StatelessWidget {
const AuditLogView({super.key});
@override
Widget build(BuildContext context) {
final controller = Get.put(AuditLogController());
final isDark = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor: isDark ? const Color(0xFF121212) : const Color(0xFFF5F7FA),
appBar: AppBar(
title: const Text('سجل النشاط', style: TextStyle(fontWeight: FontWeight.bold)),
backgroundColor: const Color(0xFF0F4C81),
foregroundColor: Colors.white,
),
body: Column(
children: [
// Filter chips
Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
color: isDark ? const Color(0xFF1E1E2E) : Colors.white,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Obx(() => Row(
children: [
_filterChip('الكل', 'all', controller, isDark),
_filterChip('الفواتير', 'invoice', controller, isDark),
_filterChip('المستخدمون', 'user', controller, isDark),
_filterChip('الشركات', 'company', controller, isDark),
_filterChip('المدفوعات', 'payment', controller, isDark),
],
)),
),
),
// Log List
Expanded(
child: Obx(() {
if (controller.isLoading.value && controller.logs.isEmpty) {
return const Center(child: CircularProgressIndicator(color: Color(0xFF0F4C81)));
}
if (controller.logs.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.history, size: 64, color: isDark ? Colors.white12 : Colors.grey.shade300),
const SizedBox(height: 12),
Text('لا يوجد نشاط', style: TextStyle(color: isDark ? Colors.white38 : Colors.grey, fontSize: 16)),
],
),
);
}
return RefreshIndicator(
onRefresh: () => controller.fetchLogs(),
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: controller.logs.length + (controller.currentPage.value < controller.totalPages.value ? 1 : 0),
itemBuilder: (context, index) {
if (index == controller.logs.length) {
return Center(
child: TextButton(
onPressed: () => controller.loadMore(),
child: const Text('تحميل المزيد...'),
),
);
}
return _buildLogItem(controller.logs[index], isDark);
},
),
);
}),
),
],
),
);
}
Widget _filterChip(String label, String value, AuditLogController ctrl, bool isDark) {
return Obx(() {
final isSelected = ctrl.selectedFilter.value == value;
return Padding(
padding: const EdgeInsets.only(left: 8),
child: ChoiceChip(
label: Text(label),
selected: isSelected,
onSelected: (_) => ctrl.applyFilter(value),
selectedColor: const Color(0xFF0F4C81),
backgroundColor: isDark ? Colors.white10 : const Color(0xFFF1F5F9),
labelStyle: TextStyle(
color: isSelected ? Colors.white : (isDark ? Colors.white70 : Colors.black87),
fontWeight: isSelected ? FontWeight.w700 : FontWeight.w400,
fontSize: 13,
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
side: BorderSide(color: isSelected ? Colors.transparent : Colors.grey.shade300),
),
);
});
}
Widget _buildLogItem(Map<String, dynamic> log, bool isDark) {
final action = log['action']?.toString() ?? '';
final IconData icon;
final Color color;
if (action.contains('approve')) {
icon = Icons.check_circle;
color = const Color(0xFF10B981);
} else if (action.contains('update')) {
icon = Icons.edit;
color = const Color(0xFF3B82F6);
} else if (action.contains('create') || action.contains('upload')) {
icon = Icons.add_circle;
color = const Color(0xFF6366F1);
} else if (action.contains('delete')) {
icon = Icons.delete;
color = const Color(0xFFEF4444);
} else if (action.contains('login')) {
icon = Icons.login;
color = const Color(0xFFF59E0B);
} else if (action.contains('payment')) {
icon = Icons.payment;
color = const Color(0xFFD4AF37);
} else {
icon = Icons.history;
color = Colors.grey;
}
final time = log['created_at']?.toString() ?? '';
final userName = log['user_name']?.toString() ?? 'نظام';
final summary = log['summary']?.toString() ?? action;
final entityType = log['entity_type']?.toString() ?? '';
return Container(
margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF1E1E2E) : Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: isDark ? Colors.white10 : Colors.grey.shade200),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 40, height: 40,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(10),
),
child: Icon(icon, color: color, size: 20),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(summary, style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14, color: isDark ? Colors.white : Colors.black87)),
const SizedBox(height: 4),
Row(
children: [
Icon(Icons.person, size: 12, color: isDark ? Colors.white38 : Colors.grey),
const SizedBox(width: 4),
Text(userName, style: TextStyle(fontSize: 12, color: isDark ? Colors.white38 : Colors.grey)),
const SizedBox(width: 12),
if (entityType.isNotEmpty) ...[
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1),
decoration: BoxDecoration(
color: color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(4),
),
child: Text(_entityLabel(entityType), style: TextStyle(fontSize: 10, color: color, fontWeight: FontWeight.w600)),
),
],
],
),
const SizedBox(height: 2),
Text(time, style: TextStyle(fontSize: 11, color: isDark ? Colors.white24 : Colors.grey.shade400, fontFamily: 'monospace')),
],
),
),
],
),
);
}
String _entityLabel(String type) {
return switch (type) {
'invoice' => 'فاتورة',
'user' => 'مستخدم',
'company' => 'شركة',
'payment' => 'دفعة',
_ => type,
};
}
}