diff --git a/frontend/src/components/admin/AuditLogView.jsx b/frontend/src/components/admin/AuditLogView.jsx
index df47c710..5750b066 100644
--- a/frontend/src/components/admin/AuditLogView.jsx
+++ b/frontend/src/components/admin/AuditLogView.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState, useMemo } from 'react';
import {
FilePlus,
RefreshCw,
@@ -6,12 +6,25 @@ import {
UserPlus,
Clock,
User as UserIcon,
- AlertCircle
+ AlertCircle,
+ Search,
+ MapPin,
+ ShieldCheck
} from 'lucide-react';
const AuditLogView = ({ logs = [], loading }) => {
+ // 1. States för filtrering
+ const [searchTerm, setSearchTerm] = useState('');
+ const [roleFilter, setRoleFilter] = useState('ALL');
+ const [actionFilter, setActionFilter] = useState('ALL');
+ const [clinicFilter, setClinicFilter] = useState('ALL');
+ const [dateFilter, setDateFilter] = useState('');
+
+ const clinics = useMemo(() => {
+ const uniqueClinics = [...new Set(logs.map(log => log.clinicName))].filter(Boolean);
+ return uniqueClinics.sort();
+ }, [logs]);
- // Mappa actions till färger och ikoner
const getActionStyle = (action) => {
switch (action) {
case 'CASE_CREATED': return { icon: , color: 'text-emerald-500', bg: 'bg-emerald-50' };
@@ -22,57 +35,193 @@ const AuditLogView = ({ logs = [], loading }) => {
}
};
- if (loading) return
Laddar historik...
;
- if (logs.length === 0) return (
-
-
-
Ingen aktivitet hittades
-
- );
+
+ const filteredLogs = useMemo(() => {
+ return logs.filter(log => {
+ const searchLower = searchTerm.toLowerCase();
+ const matchesSearch =
+ log.performedByName?.toLowerCase().includes(searchLower) ||
+ log.description?.toLowerCase().includes(searchLower) ||
+ log.clinicName?.toLowerCase().includes(searchLower) ||
+ log.petName?.toLowerCase().includes(searchLower) ||
+ log.recordId?.includes(searchTerm);
+
+ const matchesAction = actionFilter === 'ALL' || log.action === actionFilter;
+ const matchesRole = roleFilter === 'ALL' ||
+ log.performedByRole?.replace('ROLE_', '') === roleFilter.replace('ROLE_', '');
+
+ const matchesClinic = clinicFilter === 'ALL' || log.clinicName === clinicFilter;
+ const matchesDate = !dateFilter || (log.createdAt?.startsWith(dateFilter) ?? false);
+
+ return matchesSearch && matchesAction && matchesRole && matchesDate && matchesClinic;
+ });
+ }, [logs, searchTerm, actionFilter, roleFilter, clinicFilter, dateFilter]);
+
+ if (loading) return Laddar administrativ historik...
;
return (
-
- {logs.map((log) => {
- const style = getActionStyle(log.action);
- const date = new Date(log.createdAt).toLocaleString('sv-SE', {
- month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit'
- });
-
- return (
-
- {/* Timeline line */}
-
-
- {/* Icon */}
-
- {style.icon}
-
-
- {/* Content */}
-
-
-
- {log.action.replace('_', ' ')}
-
-
- {date}
-
-
-
{log.description}
-
-
-
-
-
- {log.performedByName}
-
+
+ {/* --- ADMIN FILTER PANEL --- */}
+
+
+
+
+
+ setSearchTerm(e.target.value)}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setDateFilter(e.target.value)}
+ className="w-full bg-white border border-slate-200 rounded-xl px-3 py-2 text-xs font-bold outline-none focus:ring-2 focus:ring-[#003f5a] text-slate-600"
+ />
+
+
+
+
+ {/* --- LOG LIST --- */}
+
+ {filteredLogs.length === 0 ? (
+
+
+
Inga loggar matchar administratörens filter
+
+ ) : (
+
+ {filteredLogs.map((log) => {
+ const style = getActionStyle(log.action);
+ const date = new Date(log.createdAt).toLocaleString('sv-SE', {
+ month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit'
+ });
+
+ return (
+
+
+
+
+ {style.icon}
+
+
+
+
+
+
+ {log.action.replace('_', ' ')}
+
+ {/* Roll-tagg */}
+
+
+ {log.performedByRole?.replace('ROLE_', '') ?? 'SYSTEM'}
+
+
+
+ {date}
+
+
+
+
{log.description}
+
+
+ {/* Utförare */}
+
+
+
+ {log.performedByName}
+
+
+ {/* DJURETS NAMN (NYTT) */}
+
+ Patient:
+
+ {log.petName}
+
+
+
+ {/* Klinik */}
+
+
+
+ {log.clinicName || 'System'}
+
+
+
+ {/* Ärende-ID */}
+
+ Ref:
+
+ {log.recordId}
+
+
+
+
-
ID: {log.recordId.substring(0, 8)}...
-
-
+ );
+ })}
- );
- })}
+ )}
+
);
};
diff --git a/src/main/java/org/example/vet1177/dto/response/activitylog/ActivityLogResponse.java b/src/main/java/org/example/vet1177/dto/response/activitylog/ActivityLogResponse.java
index e966df77..ac43ab8c 100644
--- a/src/main/java/org/example/vet1177/dto/response/activitylog/ActivityLogResponse.java
+++ b/src/main/java/org/example/vet1177/dto/response/activitylog/ActivityLogResponse.java
@@ -13,7 +13,10 @@ public record ActivityLogResponse(
String description,
UUID performedById,
String performedByName,
+ String performedByRole,
UUID recordId,
+ String clinicName,
+ String petName,
Instant createdAt
) {
@@ -24,7 +27,10 @@ public static ActivityLogResponse from(ActivityLog log) {
log.getDescription(),
log.getPerformedBy().getId(),
log.getPerformedBy().getName(),
+ log.getPerformedBy().getRole() != null ? log.getPerformedBy().getRole().name() : "ROLE_UNKNOWN",
log.getMedicalRecord().getId(),
+ log.getMedicalRecord().getClinic() != null ? log.getMedicalRecord().getClinic().getName() : "Okänd klinik",
+ log.getMedicalRecord().getPet() != null ? log.getMedicalRecord().getPet().getName() : "Okänt djur",
log.getCreatedAt()
);
}