Files
gridpilot.gg/apps/website/components/errors/ErrorDetails.tsx
2026-01-18 16:18:18 +01:00

103 lines
2.8 KiB
TypeScript

'use client';
import React, { useState } from 'react';
import { ChevronDown, ChevronUp, Copy, Terminal } from 'lucide-react';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon';
import { Card } from '@/ui/Card';
interface ErrorDetailsProps {
error: Error & { digest?: string };
}
/**
* ErrorDetails
*
* Handles the display of technical error information with a toggle.
* Part of the 500 route redesign.
*/
export function ErrorDetails({ error }: ErrorDetailsProps) {
const [showDetails, setShowDetails] = useState(false);
const [copied, setCopied] = useState(false);
const copyError = async () => {
const details = {
message: error.message,
digest: error.digest,
stack: error.stack,
url: typeof window !== 'undefined' ? window.location.href : 'unknown',
timestamp: new Date().toISOString(),
};
try {
await navigator.clipboard.writeText(JSON.stringify(details, null, 2));
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
// Silent fail
}
};
return (
<Stack gap={4} fullWidth pt={4} borderTop borderColor="border-white">
<Stack
as="button"
onClick={() => setShowDetails(!showDetails)}
direction="row"
align="center"
justify="center"
gap={2}
color="text-gray-500"
className="transition-all hover:text-gray-300"
>
<Icon icon={Terminal} size={3} />
<Text
size="xs"
weight="medium"
uppercase
letterSpacing="widest"
color="inherit"
>
{showDetails ? 'Hide Technical Logs' : 'Show Technical Logs'}
</Text>
{showDetails ? <Icon icon={ChevronUp} size={3} /> : <Icon icon={ChevronDown} size={3} />}
</Stack>
{showDetails && (
<Stack gap={3}>
<Card
variant="outline"
rounded="md"
p={4}
fullWidth
maxHeight="48"
overflow="auto"
borderColor="border-white"
className="bg-graphite-black/40"
>
<Text font="mono" size="xs" color="text-gray-500" block leading="relaxed">
{error.stack || 'No stack trace available'}
{error.digest && `\n\nDigest: ${error.digest}`}
</Text>
</Card>
<Stack direction="row" justify="end">
<Button
variant="secondary"
size="sm"
onClick={copyError}
icon={<Icon icon={Copy} size={3} />}
height="8"
fontSize="10px"
>
{copied ? 'Copied to Clipboard' : 'Copy Error Details'}
</Button>
</Stack>
</Stack>
)}
</Stack>
);
}