111 lines
3.6 KiB
TypeScript
111 lines
3.6 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import { handleCallback, login, type AuthError } from '@/auth/authService';
|
|
import { Loader2, CheckCircle, AlertCircle, Home } from 'lucide-react';
|
|
import { Button } from './ui/button';
|
|
|
|
type CallbackState = 'processing' | 'success' | 'error';
|
|
|
|
const AuthCallback: React.FC = () => {
|
|
const [state, setState] = useState<CallbackState>('processing');
|
|
const [error, setError] = useState<AuthError | null>(null);
|
|
|
|
useEffect(() => {
|
|
const processCallback = async () => {
|
|
try {
|
|
await handleCallback();
|
|
setState('success');
|
|
// Auto-redirect after success
|
|
setTimeout(() => {
|
|
window.location.href = '/';
|
|
}, 1500);
|
|
} catch (err) {
|
|
setError(err as AuthError);
|
|
setState('error');
|
|
}
|
|
};
|
|
|
|
processCallback();
|
|
}, []);
|
|
|
|
const handleRetry = async () => {
|
|
setState('processing');
|
|
setError(null);
|
|
try {
|
|
await login();
|
|
} catch (err) {
|
|
setError(err as AuthError);
|
|
setState('error');
|
|
}
|
|
};
|
|
|
|
const handleGoHome = () => {
|
|
window.location.href = '/';
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-background p-4">
|
|
<div className="w-full max-w-md">
|
|
<div className="bg-card border rounded-xl shadow-lg p-8">
|
|
{state === 'processing' && (
|
|
<div className="text-center space-y-4">
|
|
<div className="flex justify-center">
|
|
<div className="p-4 bg-primary/10 rounded-full">
|
|
<Loader2 className="h-8 w-8 text-primary animate-spin" />
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h1 className="text-xl font-semibold">Completing Sign In</h1>
|
|
<p className="text-muted-foreground">
|
|
Please wait while we verify your credentials...
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{state === 'success' && (
|
|
<div className="text-center space-y-4">
|
|
<div className="flex justify-center">
|
|
<div className="p-4 bg-green-500/10 rounded-full">
|
|
<CheckCircle className="h-8 w-8 text-green-500" />
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h1 className="text-xl font-semibold">Welcome Back!</h1>
|
|
<p className="text-muted-foreground">
|
|
Redirecting you to the dashboard...
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{state === 'error' && (
|
|
<div className="text-center space-y-6">
|
|
<div className="flex justify-center">
|
|
<div className="p-4 bg-destructive/10 rounded-full">
|
|
<AlertCircle className="h-8 w-8 text-destructive" />
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h1 className="text-xl font-semibold">Sign In Failed</h1>
|
|
<p className="text-muted-foreground">
|
|
{error?.message || 'An unexpected error occurred.'}
|
|
</p>
|
|
</div>
|
|
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
|
<Button onClick={handleRetry} className="gap-2">
|
|
Try Again
|
|
</Button>
|
|
<Button variant="outline" onClick={handleGoHome} className="gap-2">
|
|
<Home className="h-4 w-4" />
|
|
Go Home
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default AuthCallback;
|