import React, { useState } from "react";
import { http } from "../lib/api";
import { frontendUrl } from "../lib/paths";
import {
Check, Zap, Crown, Sparkles, Loader2, RefreshCw, Clock, ShieldCheck,
Infinity as InfinityIcon, AlertTriangle, RotateCcw,
} from "lucide-react";
import { toast } from "sonner";
const TIER_ICONS = { free: Clock, basic: Sparkles, premium: Zap, ultra: Crown };
const TIER_RANK = { free: 0, basic: 1, premium: 2, ultra: 3 };
export function SubscriptionSection({ license, plans, onRefresh, onReset }) {
const [loading, setLoading] = useState(null);
const [checking, setChecking] = useState(false);
const [productKey, setProductKey] = useState("");
const [redeeming, setRedeeming] = useState(false);
const currentTier = license?.tier || "free";
const planList = plans || [];
const subscribe = async (tier) => {
setLoading(tier);
try {
const r = await http.post("/license/checkout", {
origin_url: frontendUrl("/chat"),
tier,
});
if (r.data.already_paid) {
toast.success(`Abonnement ${r.data.tier} actif`);
onRefresh?.();
return;
}
if (r.data.url) window.location.href = r.data.url;
} catch (e) {
toast.error(e?.response?.data?.detail || "Erreur Stripe");
} finally {
setLoading(null);
}
};
const redeemKey = async (e) => {
e.preventDefault();
const key = productKey.trim();
if (!key) return;
setRedeeming(true);
try {
const r = await http.post("/license/redeem-key", { key });
toast.success(`Licence ${(r.data.tier || "ultra").toUpperCase()} activée`);
setProductKey("");
onRefresh?.();
} catch (err) {
toast.error(err?.response?.data?.detail || "Clé invalide");
} finally {
setRedeeming(false);
}
};
const checkPayment = async () => {
setChecking(true);
try {
const r = await http.post("/license/claim-payment");
if (r.data.paid) {
toast.success(`Abonnement ${r.data.tier} activé`);
onRefresh?.();
} else {
toast.info(r.data.message || "Paiement en attente");
}
} catch (_) {
toast.error("Erreur vérification");
} finally {
setChecking(false);
}
};
if (license?.source === "product_key" && license?.active) {
return (
{license.tier_name || "Ultra"} · Licence produit
Accès illimité
);
}
if (license?.is_admin && license?.source === "admin_grant") {
return (
Admin
{onReset && (
)}
);
}
return (
{currentTier !== "free" && license?.active && (
{license.tier_name || currentTier} actif
Modèle : {license.model_label || "—"}
{license.valid_until && (
<> · renouvellement {new Date(license.valid_until).toLocaleDateString("fr-FR")}>
)}
)}
{currentTier === "free" && (
Gratuit
{license?.messages_left_today ?? 0} / {license?.messages_per_day ?? 15} messages
{license?.model_label && <> · {license.model_label}>}
)}
{(currentTier === "free" || !license?.active) && (
)}
{planList.filter((p) => p.id !== "free").map((plan) => {
const Icon = TIER_ICONS[plan.id] || Zap;
const isCurrent = currentTier === plan.id && license?.active;
const canUpgrade = !isCurrent && (TIER_RANK[plan.id] ?? 0) > (TIER_RANK[currentTier] ?? 0);
const cardStyle =
plan.id === "ultra"
? { bg: "var(--emo-warning-bg)", border: "var(--emo-warning-border)", accent: "var(--emo-admin-text)" }
: plan.id === "basic"
? { bg: "var(--emo-accent-soft)", border: "var(--emo-accent-border)", accent: "var(--emo-link)" }
: { bg: "var(--emo-accent-soft)", border: "var(--emo-accent-border)", accent: "var(--mode-color)" };
return (
{plan.name}
{plan.price_eur} €/mois
{plan.features?.slice(0, 4).map((f) => (
-
{f}
))}
{plan.models?.length > 0 && (
IA : {plan.models.slice(0, 3).join(" · ")}
)}
{isCurrent ? (
Plan actuel
) : canUpgrade || currentTier === "free" ? (
) : null}
);
})}
Paiement Stripe
);
}
export default function Paywall({ info, plans, onPaid }) {
const [loading, setLoading] = useState(null);
const [checking, setChecking] = useState(false);
const expired = info?.status === "expired";
const planList = plans || info?.plans || [];
const subscribe = async (tier) => {
setLoading(tier);
try {
const r = await http.post("/license/checkout", { origin_url: window.location.origin, tier });
if (r.data.already_paid) { onPaid?.(); return; }
if (r.data.url) window.location.href = r.data.url;
} catch (_) {
setLoading(null);
}
};
const checkPayment = async () => {
setChecking(true);
try {
const r = await http.post("/license/claim-payment");
if (r.data.paid) onPaid?.();
else {
const lic = await http.get("/license/status");
if (lic.data.active && lic.data.tier !== "free") onPaid?.();
else alert(r.data.message || "Paiement en attente.");
}
} catch (_) { /* ignore */ }
finally { setChecking(false); }
};
return (
{expired ? "Abonnement expiré" : "Quota du jour atteint"}
{expired
? "Renouvelez votre abonnement."
: <>Quota journalier atteint ({info?.messages_per_day || 15} messages).>}
{planList.filter((p) => p.id !== "free").map((plan) => (
))}
);
}