124 lines
4.9 KiB
TypeScript
124 lines
4.9 KiB
TypeScript
"use client";
|
||
|
||
import Link from "next/link";
|
||
import type { TrialState } from "../types";
|
||
|
||
export function TrialBanner({ trial }: { trial: TrialState | null | undefined }) {
|
||
if (!trial) return null;
|
||
|
||
if (!trial.active) {
|
||
const expired =
|
||
(typeof trial.days_remaining === "number" && trial.days_remaining <= 0) ||
|
||
(trial.ends_at && new Date(trial.ends_at).getTime() < Date.now());
|
||
if (!expired) return null;
|
||
return (
|
||
<div
|
||
className="rounded-2xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-900 dark:border-red-900 dark:bg-red-950/40 dark:text-red-100"
|
||
role="alert"
|
||
>
|
||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||
<p className="font-semibold">دوره آزمایشی منقضی شده است</p>
|
||
<Link href="/billing" className="font-semibold text-primary hover:underline">
|
||
ارتقا فوری
|
||
</Link>
|
||
</div>
|
||
<p className="mt-1 text-xs">برای ادامه قابلیتهای قفلشده، اشتراک را فعال کنید.</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
const days = trial.days_remaining;
|
||
const urgent = typeof days === "number" && days <= 3;
|
||
const tone = urgent
|
||
? "border-orange-300 bg-orange-50 text-orange-950 dark:border-orange-800 dark:bg-orange-950/30 dark:text-orange-100"
|
||
: "border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-100";
|
||
|
||
return (
|
||
<div className={`rounded-2xl border px-4 py-3 text-sm ${tone}`} role="status">
|
||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||
<p>
|
||
{urgent ? "هشدار: " : ""}
|
||
دوره آزمایشی فعال است
|
||
{typeof days === "number" ? (
|
||
<span className="font-semibold"> — {days} روز باقیمانده</span>
|
||
) : null}
|
||
{trial.ends_at ? (
|
||
<span className="mr-2 text-xs opacity-80" dir="ltr">
|
||
({new Date(trial.ends_at).toLocaleDateString("fa-IR")})
|
||
</span>
|
||
) : null}
|
||
</p>
|
||
<Link href="/billing" className="font-semibold text-primary hover:underline">
|
||
ارتقا به اشتراک
|
||
</Link>
|
||
</div>
|
||
{urgent ? (
|
||
<p className="mt-1 text-xs">قبل از انقضا ارتقا دهید تا قفل قابلیتها فعال نشود.</p>
|
||
) : null}
|
||
{trial.quotas && trial.quotas.length > 0 ? (
|
||
<ul className="mt-2 grid gap-1 text-xs sm:grid-cols-2">
|
||
{trial.quotas.map((q) => {
|
||
const nearLimit =
|
||
typeof q.used === "number" &&
|
||
typeof q.limit === "number" &&
|
||
q.limit > 0 &&
|
||
q.used / q.limit >= 0.8;
|
||
return (
|
||
<li key={q.key} className={nearLimit ? "font-semibold text-orange-800 dark:text-orange-200" : ""}>
|
||
{q.label || q.key}: {q.used ?? "—"} / {q.limit ?? "∞"}
|
||
{nearLimit ? " · نزدیک سقف" : ""}
|
||
</li>
|
||
);
|
||
})}
|
||
</ul>
|
||
) : null}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function SubscriptionBanner({
|
||
status,
|
||
planName,
|
||
}: {
|
||
status?: string | null;
|
||
planName?: string | null;
|
||
}) {
|
||
if (!status) {
|
||
return (
|
||
<div className="rounded-2xl border border-gray-200 bg-gray-50 px-4 py-3 text-sm text-gray-700 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300">
|
||
اشتراک ثبت نشده است.{" "}
|
||
<Link href="/billing" className="font-semibold text-primary hover:underline">
|
||
شروع trial یا انتخاب پلن
|
||
</Link>
|
||
</div>
|
||
);
|
||
}
|
||
const tone =
|
||
status === "active"
|
||
? "border-emerald-200 bg-emerald-50 text-emerald-900 dark:border-emerald-800 dark:bg-emerald-950/30 dark:text-emerald-100"
|
||
: status === "trialing"
|
||
? "border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-100"
|
||
: status === "past_due" || status === "expired" || status === "suspended"
|
||
? "border-red-200 bg-red-50 text-red-900 dark:border-red-900 dark:bg-red-950/40 dark:text-red-100"
|
||
: "border-gray-200 bg-gray-50 text-gray-800 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200";
|
||
return (
|
||
<div className={`rounded-2xl border px-4 py-3 text-sm ${tone}`} role="status">
|
||
وضعیت اشتراک: <span className="font-semibold">{status}</span>
|
||
{planName ? (
|
||
<>
|
||
{" "}
|
||
· پلن: <span className="font-semibold">{planName}</span>
|
||
</>
|
||
) : null}
|
||
{(status === "past_due" || status === "expired" || status === "suspended") && (
|
||
<>
|
||
{" "}
|
||
<Link href="/billing" className="font-semibold text-primary hover:underline">
|
||
رفع مشکل / ارتقا
|
||
</Link>
|
||
</>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|