localization updates, terminal errors, etc
This commit is contained in:
@@ -40,38 +40,38 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
|
||||
const authenticate = async () => {
|
||||
setLogs((prev) => [...prev, `> ${dict.processing}`]);
|
||||
|
||||
// Эмулируем задержку для "хакерского" эффекта консоли
|
||||
await new Promise((resolve) => setTimeout(resolve, 800));
|
||||
|
||||
const hash = window.location.hash;
|
||||
let token = localStorage.getItem("nrxp_token");
|
||||
|
||||
// Логика получения токена из query parameters или хеша
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const queryToken = searchParams.get("token");
|
||||
|
||||
|
||||
if (queryToken) {
|
||||
token = queryToken;
|
||||
searchParams.delete("token");
|
||||
const newSearch = searchParams.toString();
|
||||
const newUrl = window.location.pathname + (newSearch ? `?${newSearch}` : "") + window.location.hash;
|
||||
const newUrl =
|
||||
window.location.pathname +
|
||||
(newSearch ? `?${newSearch}` : "") +
|
||||
window.location.hash;
|
||||
window.history.replaceState(null, "", newUrl);
|
||||
} else if (hash.includes("token=")) {
|
||||
const params = new URLSearchParams(hash.replace("#", "?"));
|
||||
const urlToken = params.get("token");
|
||||
if (urlToken) {
|
||||
token = urlToken;
|
||||
// Безопасно очищаем URL от токена, сохраняя search params
|
||||
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
||||
window.history.replaceState(
|
||||
null,
|
||||
"",
|
||||
window.location.pathname + window.location.search,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
setLogs((prev) => [
|
||||
...prev,
|
||||
"> [WAITING] INITIALIZE TELEGRAM SECURE LOGIN...",
|
||||
]);
|
||||
setLogs((prev) => [...prev, dict.logs.waitInit]);
|
||||
setStatus("awaiting");
|
||||
return;
|
||||
}
|
||||
@@ -87,32 +87,28 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
|
||||
if (res.ok) {
|
||||
localStorage.setItem("nrxp_token", token);
|
||||
setLogs((prev) => [...prev, "> [OK] SIGNATURE VALID"]);
|
||||
setLogs((prev) => [...prev, dict.logs.sigValid]);
|
||||
setStatus("granted");
|
||||
setLogs((prev) => [...prev, `> ${dict.redirecting}`]);
|
||||
setTimeout(() => router.push(`/${lang}/profile`), 1500);
|
||||
} else {
|
||||
localStorage.removeItem("nrxp_token");
|
||||
setLogs((prev) => [...prev, "> [FAIL] API REJECTED TOKEN"]);
|
||||
setLogs((prev) => [...prev, dict.logs.apiRejected]);
|
||||
setStatus("awaiting");
|
||||
}
|
||||
} catch (err) {
|
||||
setLogs((prev) => [...prev, "> [FAIL] CORE OFFLINE"]);
|
||||
setLogs((prev) => [...prev, dict.logs.coreOffline]);
|
||||
setStatus("denied");
|
||||
}
|
||||
};
|
||||
|
||||
authenticate();
|
||||
}, [dict, lang, router]); // Этот эффект запустится 1 раз при маунте
|
||||
}, [dict, lang, router]);
|
||||
|
||||
useEffect(() => {
|
||||
window.onTelegramAuth = async (user: any) => {
|
||||
setStatus("processing");
|
||||
setLogs((prev) => [
|
||||
...prev,
|
||||
"> [AUTH] RECEIVED TELEGRAM PAYLOAD",
|
||||
"> VERIFYING HMAC-SHA256 SIGNATURE...",
|
||||
]);
|
||||
setLogs((prev) => [...prev, dict.logs.authPayload, dict.logs.verifyHmac]);
|
||||
try {
|
||||
const API_BASE = process.env.NEXT_PUBLIC_API_URL || "/api";
|
||||
const res = await fetch(`${API_BASE}/auth/telegram`, {
|
||||
@@ -126,17 +122,17 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
localStorage.setItem("nrxp_token", data.token);
|
||||
setLogs((prev) => [
|
||||
...prev,
|
||||
"> [OK] SIGNATURE VALID",
|
||||
dict.logs.sigValid,
|
||||
`> ${dict.redirecting}`,
|
||||
]);
|
||||
setStatus("granted");
|
||||
setTimeout(() => router.push(`/${lang}/profile`), 1500);
|
||||
} else {
|
||||
setLogs((prev) => [...prev, "> [FAIL] INVALID SIGNATURE OR EXPIRED"]);
|
||||
setLogs((prev) => [...prev, dict.logs.invalidSig]);
|
||||
setStatus("denied");
|
||||
}
|
||||
} catch (e) {
|
||||
setLogs((prev) => [...prev, "> [FAIL] NETWORK ERROR"]);
|
||||
setLogs((prev) => [...prev, dict.logs.networkError]);
|
||||
setStatus("denied");
|
||||
}
|
||||
};
|
||||
@@ -165,14 +161,12 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen pt-32 pb-24 px-4 container mx-auto max-w-2xl relative flex flex-col items-center justify-center font-mono">
|
||||
{/* Мягкое фоновое свечение */}
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[80vw] h-[80vw] max-w-150 max-h-150 bg-primary/5 blur-[120px] rounded-full -z-10 pointer-events-none" />
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="w-full bg-card/40 backdrop-blur-xl border border-border/50 rounded-2xl p-8 md:p-12 shadow-2xl relative overflow-hidden"
|
||||
>
|
||||
{/* Заголовок и анимированные иконки статуса */}
|
||||
<div className="flex flex-col items-center mb-10 text-center">
|
||||
<div className="mb-8 relative">
|
||||
{status === "processing" && (
|
||||
@@ -211,7 +205,6 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* Терминал с логами процесса авторизации */}
|
||||
<div className="bg-background/80 border border-border/50 rounded-2xl p-6 font-mono text-sm text-muted-foreground/80 min-h-35 flex flex-col justify-end space-y-3 mb-8 shadow-inner">
|
||||
<AnimatePresence>
|
||||
{logs.map((log, i) => (
|
||||
@@ -220,9 +213,9 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
className={
|
||||
log.includes("[OK]")
|
||||
log.includes("[OK]") || log.includes("[OK]")
|
||||
? "text-secondary font-bold drop-shadow-[0_0_5px_rgba(0,229,242,0.5)]"
|
||||
: log.includes("[FAIL]")
|
||||
: log.includes("[FAIL]") || log.includes("[ОШИБКА]")
|
||||
? "text-destructive font-bold drop-shadow-[0_0_5px_rgba(255,0,0,0.5)]"
|
||||
: ""
|
||||
}
|
||||
@@ -232,7 +225,6 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
))}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Мигающий курсор загрузки */}
|
||||
{status === "processing" && (
|
||||
<div className="flex items-center gap-2 text-primary mt-2">
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
@@ -243,7 +235,6 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Сообщение об ошибке и кнопка в бот (если доступ запрещен) */}
|
||||
{status === "denied" && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
@@ -253,7 +244,6 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
<p className="text-sm text-muted-foreground leading-relaxed max-w-md">
|
||||
{dict.noToken}
|
||||
</p>
|
||||
{/* При ошибке даем ссылку на телеграм бота для авторизации */}
|
||||
<CyberButton
|
||||
href={`https://t.me/${process.env.NEXT_PUBLIC_BOT_USERNAME || "ntrnr_vpn_bot"}`}
|
||||
variant="primary"
|
||||
@@ -267,7 +257,6 @@ export function AuthClient({ dict, lang }: AuthClientProps) {
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* Блок логина виджетом Telegram (рендерится только если нет токена) */}
|
||||
{status === "awaiting" && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
|
||||
Reference in New Issue
Block a user