Files
gridpilot.gg/apps/website/components/dev/sections/ReplaySection.tsx
2026-01-01 16:40:14 +01:00

160 lines
5.2 KiB
TypeScript

import { useState, useEffect } from 'react';
import { Play, Copy, Trash2, Download, Clock } from 'lucide-react';
import { getGlobalReplaySystem } from '@/lib/infrastructure/ErrorReplay';
interface ReplayEntry {
id: string;
timestamp: string;
error: string;
type: string;
}
export function ReplaySection() {
const [replays, setReplays] = useState<ReplayEntry[]>([]);
const [selectedReplay, setSelectedReplay] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
loadReplays();
}, []);
const loadReplays = () => {
const system = getGlobalReplaySystem();
const index = system.getReplayIndex();
setReplays(index);
};
const handleReplay = async (replayId: string) => {
setLoading(true);
try {
const system = getGlobalReplaySystem();
await system.replay(replayId);
} catch (error) {
console.error('Replay failed:', error);
} finally {
setLoading(false);
}
};
const handleExport = (replayId: string) => {
const system = getGlobalReplaySystem();
const data = system.exportReplay(replayId, 'json');
const blob = new Blob([data], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `replay_${replayId}.json`;
a.click();
URL.revokeObjectURL(url);
};
const handleCopy = async (replayId: string) => {
const system = getGlobalReplaySystem();
const data = system.exportReplay(replayId, 'json');
try {
await navigator.clipboard.writeText(data);
console.log('Replay data copied to clipboard');
} catch (err) {
console.error('Failed to copy:', err);
}
};
const handleDelete = (replayId: string) => {
if (confirm('Delete this replay?')) {
const system = getGlobalReplaySystem();
system.deleteReplay(replayId);
loadReplays();
}
};
const handleClearAll = () => {
if (confirm('Clear all replays?')) {
const system = getGlobalReplaySystem();
system.clearAll();
loadReplays();
}
};
return (
<div className="space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs font-semibold text-gray-400">Error Replay</span>
<div className="flex gap-1">
<button
onClick={loadReplays}
className="p-1 hover:bg-charcoal-outline rounded"
title="Refresh"
>
<Clock className="w-3 h-3 text-gray-400" />
</button>
<button
onClick={handleClearAll}
className="p-1 hover:bg-charcoal-outline rounded"
title="Clear All"
>
<Trash2 className="w-3 h-3 text-red-400" />
</button>
</div>
</div>
{replays.length === 0 ? (
<div className="text-xs text-gray-500 text-center py-2">
No replays available
</div>
) : (
<div className="space-y-1 max-h-48 overflow-auto">
{replays.map((replay) => (
<div
key={replay.id}
className="bg-deep-graphite border border-charcoal-outline rounded p-2 text-xs"
>
<div className="flex items-start justify-between gap-2 mb-1">
<div className="flex-1 min-w-0">
<div className="font-mono text-red-400 font-bold truncate">
{replay.type}
</div>
<div className="text-gray-300 truncate">{replay.error}</div>
<div className="text-gray-500 text-[10px]">
{new Date(replay.timestamp).toLocaleTimeString()}
</div>
</div>
</div>
<div className="flex gap-1 mt-1">
<button
onClick={() => handleReplay(replay.id)}
disabled={loading}
className="flex items-center gap-1 px-2 py-1 bg-green-600 hover:bg-green-700 text-white rounded"
>
<Play className="w-3 h-3" />
Replay
</button>
<button
onClick={() => handleExport(replay.id)}
className="flex items-center gap-1 px-2 py-1 bg-iron-gray hover:bg-charcoal-outline text-gray-300 rounded border border-charcoal-outline"
>
<Download className="w-3 h-3" />
Export
</button>
<button
onClick={() => handleCopy(replay.id)}
className="flex items-center gap-1 px-2 py-1 bg-iron-gray hover:bg-charcoal-outline text-gray-300 rounded border border-charcoal-outline"
>
<Copy className="w-3 h-3" />
Copy
</button>
<button
onClick={() => handleDelete(replay.id)}
className="flex items-center gap-1 px-2 py-1 bg-iron-gray hover:bg-charcoal-outline text-gray-300 rounded border border-charcoal-outline"
>
<Trash2 className="w-3 h-3" />
</button>
</div>
</div>
))}
</div>
)}
</div>
);
}