website refactor
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
import { AlertTriangle, Wifi, RefreshCw, ArrowLeft } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { ErrorDisplay as UiErrorDisplay } from '@/ui/ErrorDisplay';
|
||||
|
||||
interface ErrorDisplayProps {
|
||||
error: ApiError;
|
||||
@@ -14,123 +13,12 @@ interface ErrorDisplayProps {
|
||||
* User-friendly error display for production environments
|
||||
*/
|
||||
export function ErrorDisplay({ error, onRetry }: ErrorDisplayProps) {
|
||||
const router = useRouter();
|
||||
const [isRetrying, setIsRetrying] = useState(false);
|
||||
|
||||
const userMessage = error.getUserMessage();
|
||||
const isConnectivity = error.isConnectivityIssue();
|
||||
|
||||
const handleRetry = async () => {
|
||||
if (onRetry) {
|
||||
setIsRetrying(true);
|
||||
try {
|
||||
onRetry();
|
||||
} finally {
|
||||
setIsRetrying(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleGoBack = () => {
|
||||
router.back();
|
||||
};
|
||||
|
||||
const handleGoHome = () => {
|
||||
router.push('/');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-deep-graphite flex items-center justify-center p-4">
|
||||
<div className="max-w-md w-full bg-iron-gray border border-charcoal-outline rounded-2xl shadow-2xl overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="bg-red-500/10 border-b border-red-500/20 p-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2 bg-red-500/20 rounded-lg">
|
||||
{isConnectivity ? (
|
||||
<Wifi className="w-6 h-6 text-red-400" />
|
||||
) : (
|
||||
<AlertTriangle className="w-6 h-6 text-red-400" />
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-white">
|
||||
{isConnectivity ? 'Connection Issue' : 'Something Went Wrong'}
|
||||
</h1>
|
||||
<p className="text-sm text-gray-400">Error {error.context.statusCode || 'N/A'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Body */}
|
||||
<div className="p-6 space-y-4">
|
||||
<p className="text-gray-300 leading-relaxed">{userMessage}</p>
|
||||
|
||||
{/* Details for debugging (collapsed by default) */}
|
||||
<details className="text-xs text-gray-500 font-mono bg-deep-graphite p-3 rounded border border-charcoal-outline">
|
||||
<summary className="cursor-pointer hover:text-gray-300">Technical Details</summary>
|
||||
<div className="mt-2 space-y-1">
|
||||
<div>Type: {error.type}</div>
|
||||
<div>Endpoint: {error.context.endpoint || 'N/A'}</div>
|
||||
{error.context.statusCode && <div>Status: {error.context.statusCode}</div>}
|
||||
{error.context.retryCount !== undefined && (
|
||||
<div>Retries: {error.context.retryCount}</div>
|
||||
)}
|
||||
</div>
|
||||
</details>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex flex-col gap-2 pt-2">
|
||||
{error.isRetryable() && (
|
||||
<button
|
||||
onClick={handleRetry}
|
||||
disabled={isRetrying}
|
||||
className="flex items-center justify-center gap-2 px-4 py-2 bg-red-500 hover:bg-red-600 text-white rounded-lg font-medium transition-colors disabled:opacity-50"
|
||||
>
|
||||
{isRetrying ? (
|
||||
<>
|
||||
<RefreshCw className="w-4 h-4 animate-spin" />
|
||||
Retrying...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
Try Again
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={handleGoBack}
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-iron-gray hover:bg-charcoal-outline text-gray-300 rounded-lg font-medium transition-colors border border-charcoal-outline"
|
||||
>
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
Go Back
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleGoHome}
|
||||
className="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-iron-gray hover:bg-charcoal-outline text-gray-300 rounded-lg font-medium transition-colors border border-charcoal-outline"
|
||||
>
|
||||
Home
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="bg-iron-gray/50 border-t border-charcoal-outline p-4 text-xs text-gray-500 text-center">
|
||||
If this persists, please contact support at{' '}
|
||||
<a
|
||||
href="mailto:support@gridpilot.com"
|
||||
className="text-primary-blue hover:underline"
|
||||
>
|
||||
support@gridpilot.com
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<UiErrorDisplay
|
||||
error={error}
|
||||
onRetry={onRetry}
|
||||
variant="full-screen"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -139,8 +27,10 @@ export function ErrorDisplay({ error, onRetry }: ErrorDisplayProps) {
|
||||
*/
|
||||
export function FullScreenError({ error, onRetry }: ErrorDisplayProps) {
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 bg-deep-graphite flex items-center justify-center p-4">
|
||||
<ErrorDisplay error={error} onRetry={onRetry} />
|
||||
</div>
|
||||
<UiErrorDisplay
|
||||
error={error}
|
||||
onRetry={onRetry}
|
||||
variant="full-screen"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user