localization updates, terminal errors, etc

This commit is contained in:
2026-05-03 16:36:21 +07:00
parent c425f484b4
commit 36f75eb454
14 changed files with 579 additions and 317 deletions
+21 -32
View File
@@ -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 }}