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

68 lines
2.0 KiB
TypeScript

'use client';
import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card';
import { Icon } from '@/ui/Icon';
import { Text } from '@/ui/Text';
import { Accordion } from '@/ui/Accordion';
import { Copy } from 'lucide-react';
import React, { useState } from 'react';
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 [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 (
<div style={{ width: '100%', marginTop: '1.5rem', paddingTop: '1.5rem', borderTop: '1px solid var(--ui-color-border-muted)' }}>
<Accordion title="Technical Logs">
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
<Card variant="outline">
<Text font="mono" size="xs" variant="low" block leading="relaxed" style={{ maxHeight: '12rem', overflow: 'auto' }}>
{error.stack || 'No stack trace available'}
{error.digest && `\n\nDigest: ${error.digest}`}
</Text>
</Card>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button
variant="secondary"
size="sm"
onClick={copyError}
icon={<Icon icon={Copy} size={3} intent="low" />}
>
{copied ? 'Copied!' : 'Copy Details'}
</Button>
</div>
</div>
</Accordion>
</div>
);
}