Files
GSM/ActivityLog.jsx
2026-01-07 02:41:37 +01:00

173 lines
5.8 KiB
JavaScript

import { useState, useEffect } from 'react'
import { useUser } from '../context/UserContext'
import { getActivityLog } from '../api'
const actionLabels = {
server_start: 'Server gestartet',
server_stop: 'Server gestoppt',
server_restart: 'Server neugestartet',
rcon_command: 'RCON Befehl',
autoshutdown_config: 'Auto-Shutdown geändert',
zomboid_config: 'Config geändert',
factorio_world_create: 'Welt erstellt',
factorio_world_delete: 'Welt gelöscht'
}
const actionIcons = {
server_start: '▶️',
server_stop: '⏹️',
server_restart: '🔄',
rcon_command: '💻',
autoshutdown_config: '⏱️',
zomboid_config: '📝',
factorio_world_create: '🌍',
factorio_world_delete: '🗑️'
}
const serverLabels = {
minecraft: 'Minecraft',
factorio: 'Factorio',
zomboid: 'Project Zomboid',
vrising: 'V Rising'
}
function getAvatarUrl(discordId, avatar) {
if (!discordId || !avatar) return null
return `https://cdn.discordapp.com/avatars/${discordId}/${avatar}.png?size=32`
}
function getDiscordProfileUrl(discordId) {
return `https://discord.com/users/${discordId}`
}
export default function ActivityLog({ onClose }) {
const { token } = useUser()
const [logs, setLogs] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState('')
useEffect(() => {
const fetchLogs = async () => {
try {
const data = await getActivityLog(token, 100)
setLogs(data)
setError('')
} catch (err) {
setError('Fehler beim Laden des Activity Logs')
} finally {
setLoading(false)
}
}
fetchLogs()
}, [token])
const formatDate = (dateStr) => {
const date = new Date(dateStr + 'Z')
const now = new Date()
const diff = now - date
if (diff < 60000) return 'Gerade eben'
if (diff < 3600000) return Math.floor(diff / 60000) + ' Min'
if (diff < 86400000) return Math.floor(diff / 3600000) + ' Std'
return date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
hour: '2-digit',
minute: '2-digit'
})
}
return (
<div className="modal-backdrop fade-in" onClick={onClose}>
<div className="modal fade-in-scale" style={{ maxWidth: '42rem' }} onClick={(e) => e.stopPropagation()}>
<div className="modal-header">
<h2 className="modal-title">Activity Log</h2>
<button onClick={onClose} className="btn btn-ghost">
Schließen
</button>
</div>
<div className="modal-body" style={{ maxHeight: '60vh', overflowY: 'auto' }}>
{error && (
<div className="alert alert-error mb-4">{error}</div>
)}
{loading ? (
<div className="text-center py-4 text-neutral-400">Laden...</div>
) : logs.length === 0 ? (
<div className="text-center py-4 text-neutral-500">Noch keine Aktivitäten</div>
) : (
<div className="space-y-2">
{logs.map((log) => {
const avatarUrl = getAvatarUrl(log.discord_id, log.avatar)
const profileUrl = log.discord_id ? getDiscordProfileUrl(log.discord_id) : null
return (
<div key={log.id} className="card p-3 flex items-start gap-3">
{/* Avatar or Action Icon */}
{avatarUrl ? (
<a
href={profileUrl}
target="_blank"
rel="noopener noreferrer"
className="flex-shrink-0"
>
<img
src={avatarUrl}
alt=""
className="w-8 h-8 rounded-full hover:ring-2 hover:ring-blue-500 transition-all"
/>
</a>
) : (
<div className="w-8 h-8 rounded-full bg-neutral-700 flex items-center justify-center flex-shrink-0">
<span className="text-neutral-400 text-xs">
{log.username?.charAt(0)?.toUpperCase()}
</span>
</div>
)}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
{profileUrl ? (
<a
href={profileUrl}
target="_blank"
rel="noopener noreferrer"
className="text-white font-medium hover:text-blue-400 transition-colors"
>
{log.username}
</a>
) : (
<span className="text-white font-medium">{log.username}</span>
)}
<span className="text-neutral-500">
{actionIcons[log.action] || '📋'} {actionLabels[log.action] || log.action}
</span>
{log.target && (
<span className="text-blue-400">
{serverLabels[log.target] || log.target}
</span>
)}
</div>
{log.details && (
<div className="text-sm text-neutral-500 mt-1 truncate font-mono">
{log.details}
</div>
)}
</div>
<div className="text-xs text-neutral-500 whitespace-nowrap">
{formatDate(log.created_at)}
</div>
</div>
)
})}
</div>
)}
</div>
</div>
</div>
)
}