subs and fixes hack game
This commit is contained in:
+90
-49
@@ -12,7 +12,7 @@ import {
|
||||
Globe,
|
||||
Terminal,
|
||||
} from "lucide-react";
|
||||
import { fetchProfile } from "./api";
|
||||
import { activateTrial, buySubscription, fetchProfile } from "./api";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
// --- ЛОКАЛИЗАЦИЯ И СТАТИКА ---
|
||||
const DICT = {
|
||||
@@ -153,10 +153,8 @@ export default function Profile() {
|
||||
// БЕЗОПАСНОЕ ИЗВЛЕЧЕНИЕ: Если чего-то нет, не падаем, а ставим дефолт
|
||||
// Твой бэкенд отдает Json(user), так что data - это и есть объект пользователя
|
||||
const user = data?.user || data || {};
|
||||
const subscription = data?.subscription || {
|
||||
plan_name: "Free",
|
||||
expires_at: null,
|
||||
};
|
||||
const subscription = data?.subscription; // Теперь может быть null
|
||||
const hasSub = subscription && subscription.plan_name;
|
||||
const recruits = data?.recruits || 0;
|
||||
const earned = data?.earned || 0;
|
||||
const plans = data?.plans || [
|
||||
@@ -173,6 +171,28 @@ export default function Profile() {
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
const getPrice = (usd: number, rub: number) => {
|
||||
return lang === "ru" ? `${rub} ₽/мес` : `$${usd}/mo`;
|
||||
};
|
||||
|
||||
const handleTrial = async () => {
|
||||
try {
|
||||
await activateTrial();
|
||||
window.location.reload();
|
||||
} catch (e) {
|
||||
alert("Error / Уже использовано");
|
||||
}
|
||||
};
|
||||
|
||||
const handleBuy = async (planName: string) => {
|
||||
try {
|
||||
await buySubscription(planName);
|
||||
window.location.reload();
|
||||
} catch (e) {
|
||||
alert("Error");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-[#131124] via-[#08080C] to-black p-4 sm:p-6 pb-24 text-foreground font-mono">
|
||||
<header className="mb-8 text-center pt-8 relative z-10 flex flex-col items-center">
|
||||
@@ -195,50 +215,64 @@ export default function Profile() {
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="grid gap-6 max-w-2xl mx-auto relative z-10"
|
||||
>
|
||||
{/* PROFILE & BALANCE */}
|
||||
<div className="bg-white/[0.03] backdrop-blur-2xl border border-white/10 rounded-3xl p-6 shadow-[0_8px_32px_0_rgba(0,0,0,0.4)] relative overflow-hidden">
|
||||
<div className="absolute -top-20 -right-20 w-64 h-64 bg-primary/20 rounded-full blur-[80px] pointer-events-none" />
|
||||
|
||||
<div className="flex justify-between items-start mb-8">
|
||||
<div>
|
||||
<p className="text-muted-foreground text-xs uppercase tracking-widest mb-1">
|
||||
{t.operative}
|
||||
</p>
|
||||
<p className="text-sm font-bold opacity-80 text-primary">
|
||||
@{user.tg_username || user.tg_id || "Anon"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-muted-foreground text-xs uppercase tracking-widest mb-1">
|
||||
{t.balance}
|
||||
</p>
|
||||
<p className="text-3xl font-black text-secondary drop-shadow-[0_0_12px_rgba(0,229,242,0.6)]">
|
||||
{user.balance || 0}{" "}
|
||||
<span className="text-sm opacity-70">E$</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-black/40 border border-white/5 rounded-2xl p-4">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Activity className="w-4 h-4 text-primary" />
|
||||
<span className="text-sm uppercase tracking-widest text-muted-foreground">
|
||||
{t.uplink_status}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className={`px-3 py-1 rounded-full text-xs font-bold uppercase ${subscription.plan_name === "Free" ? "bg-white/10 text-white" : "bg-primary/20 text-primary border border-primary/30 shadow-[0_0_10px_rgba(139,61,255,0.3)]"}`}
|
||||
>
|
||||
{subscription.plan_name} TIER
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{subscription.expires_at
|
||||
? `${t.expires}: ${new Date(subscription.expires_at).toLocaleDateString()}`
|
||||
: t.no_limit}
|
||||
<div className="flex justify-between items-start mb-8">
|
||||
<div>
|
||||
<p className="text-muted-foreground text-xs uppercase tracking-widest mb-1">
|
||||
{t.operative}
|
||||
</p>
|
||||
<p className="text-sm font-bold opacity-80 text-primary">
|
||||
@{user.tg_username || user.tg_id || "Anon"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-muted-foreground text-xs uppercase tracking-widest mb-1">
|
||||
{t.balance} | TICKETS:{" "}
|
||||
<span className="text-primary">{user.game_tickets || 0}</span>
|
||||
</p>
|
||||
<p className="text-3xl font-black text-secondary drop-shadow-[0_0_12px_rgba(0,229,242,0.6)]">
|
||||
{user.balance || 0} <span className="text-sm opacity-70">E$</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-black/40 border border-white/5 rounded-2xl p-4">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Activity className="w-4 h-4 text-primary" />
|
||||
<span className="text-sm uppercase tracking-widest text-muted-foreground">
|
||||
{t.uplink_status}
|
||||
</span>
|
||||
</div>
|
||||
{hasSub ? (
|
||||
<span className="px-3 py-1 rounded-full text-xs font-bold uppercase bg-primary/20 text-primary border border-primary/30 shadow-[0_0_10px_rgba(139,61,255,0.3)]">
|
||||
{subscription.plan_name}
|
||||
</span>
|
||||
) : (
|
||||
<span className="px-3 py-1 rounded-full text-xs font-bold uppercase bg-white/10 text-muted-foreground">
|
||||
OFFLINE
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{hasSub ? (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t.expires}:{" "}
|
||||
{new Date(subscription.expires_at).toLocaleDateString()}
|
||||
</p>
|
||||
) : (
|
||||
<div className="flex justify-between items-center mt-2">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
No active subscription.
|
||||
</p>
|
||||
{!user.has_used_trial && (
|
||||
<button
|
||||
onClick={handleTrial}
|
||||
className="text-xs bg-secondary/20 hover:bg-secondary/40 text-secondary px-3 py-1 rounded transition-colors"
|
||||
>
|
||||
ACTIVATE 3-DAY TRIAL (5GB)
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
@@ -308,8 +342,15 @@ export default function Profile() {
|
||||
<li key={i}>- {f}</li>
|
||||
))}
|
||||
</ul>
|
||||
<button className="mt-auto w-full py-2 rounded-xl bg-white/5 group-hover:bg-primary text-xs font-bold transition-colors relative z-10">
|
||||
{t.acquire}
|
||||
<button
|
||||
onClick={() => handleBuy(plan.name)}
|
||||
className="mt-auto w-full py-2 rounded-xl bg-white/5 group-hover:bg-primary text-xs font-bold transition-colors relative z-10"
|
||||
>
|
||||
{t.acquire}{" "}
|
||||
{getPrice(
|
||||
plan.price_usd || plan.price,
|
||||
plan.price_rub || plan.price * 100,
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user