116 lines
3.5 KiB
TypeScript
116 lines
3.5 KiB
TypeScript
"use client";
|
||
|
||
// ============================================================================
|
||
// Auth Complete Page
|
||
// ============================================================================
|
||
|
||
import React, { useEffect, useState, Suspense } from "react";
|
||
import { useSearchParams, useRouter } from "next/navigation";
|
||
import { useAuth } from "@/components/auth/auth-provider";
|
||
import {
|
||
Card,
|
||
CardContent,
|
||
CardDescription,
|
||
CardHeader,
|
||
CardTitle,
|
||
} from "@/components/ui/card";
|
||
import { AlertCircle, CheckCircle, Loader2 } from "lucide-react";
|
||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||
import { Button } from "@/components/ui/button";
|
||
|
||
function AuthCompleteContent() {
|
||
const searchParams = useSearchParams();
|
||
const router = useRouter();
|
||
const { login } = useAuth();
|
||
const [status, setStatus] = useState<"loading" | "success" | "error">(
|
||
"loading"
|
||
);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
useEffect(() => {
|
||
const token = searchParams.get("token");
|
||
|
||
if (!token) {
|
||
setStatus("error");
|
||
setError("Токен авторизации не найден");
|
||
return;
|
||
}
|
||
|
||
const completeAuth = async () => {
|
||
try {
|
||
await login(token);
|
||
setStatus("success");
|
||
|
||
// Redirect after short delay
|
||
setTimeout(() => {
|
||
router.push("/");
|
||
}, 1500);
|
||
} catch (err: any) {
|
||
setStatus("error");
|
||
setError(err?.detail || err?.error?.message || "Ошибка авторизации");
|
||
}
|
||
};
|
||
|
||
completeAuth();
|
||
}, [searchParams, login, router]);
|
||
|
||
return (
|
||
<div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-950 dark:to-slate-900 p-4">
|
||
<Card className="w-full max-w-md">
|
||
<CardHeader className="text-center">
|
||
<div className="mx-auto mb-4">
|
||
{status === "loading" && (
|
||
<Loader2 className="h-12 w-12 animate-spin text-primary" />
|
||
)}
|
||
{status === "success" && (
|
||
<CheckCircle className="h-12 w-12 text-green-500" />
|
||
)}
|
||
{status === "error" && (
|
||
<AlertCircle className="h-12 w-12 text-destructive" />
|
||
)}
|
||
</div>
|
||
|
||
<CardTitle>
|
||
{status === "loading" && "Авторизация..."}
|
||
{status === "success" && "Успешно!"}
|
||
{status === "error" && "Ошибка"}
|
||
</CardTitle>
|
||
|
||
<CardDescription>
|
||
{status === "loading" && "Пожалуйста, подождите"}
|
||
{status === "success" && "Перенаправляем в приложение..."}
|
||
{status === "error" && error}
|
||
</CardDescription>
|
||
</CardHeader>
|
||
|
||
{status === "error" && (
|
||
<CardContent>
|
||
<Alert variant="destructive" className="mb-4">
|
||
<AlertCircle className="h-4 w-4" />
|
||
<AlertDescription>{error}</AlertDescription>
|
||
</Alert>
|
||
|
||
<Button onClick={() => router.push("/login")} className="w-full">
|
||
Вернуться к входу
|
||
</Button>
|
||
</CardContent>
|
||
)}
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default function AuthCompletePage() {
|
||
return (
|
||
<Suspense
|
||
fallback={
|
||
<div className="flex min-h-screen items-center justify-center">
|
||
<Loader2 className="h-12 w-12 animate-spin text-primary" />
|
||
</div>
|
||
}
|
||
>
|
||
<AuthCompleteContent />
|
||
</Suspense>
|
||
);
|
||
}
|