first commit

This commit is contained in:
2026-08-07 09:40:16 +03:30
commit 0c51b30059
37 changed files with 5146 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
"use client";
import { useEffect, useState } from "react";
import Shell from "@/components/Shell";
import { TableSkeleton } from "@/components/Skeleton";
import { api } from "@/lib/api";
import { toastError } from "@/lib/toast";
type Tier = {
id: string;
label: string;
c1: string;
c2: string;
sort: number;
};
const hex = (s: string) => {
const v = String(s || "").replace("#", "").trim();
return /^[0-9a-fA-F]{6}$/.test(v) ? `#${v}` : null;
};
function Swatch({ c1, c2 }: { c1: string; c2: string }) {
const a = hex(c1);
const b = hex(c2);
return (
<div
style={{
width: 40,
height: 40,
borderRadius: "50%",
background:
a && b ? `linear-gradient(160deg, ${a}, ${b})` : "#16305a",
border: "1px solid #1e3a63",
}}
/>
);
}
export default function RankTiersPage() {
const [tiers, setTiers] = useState<Tier[]>([]);
const [busy, setBusy] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
async function load() {
setLoading(true);
try {
const r = await api.get<{ rank_tiers: Tier[] }>("/rank-tiers");
setTiers(r.rank_tiers || []);
} finally {
setLoading(false);
}
}
useEffect(() => {
load();
}, []);
const patch = (id: string, key: keyof Tier, val: string | number) =>
setTiers((ts) => ts.map((t) => (t.id === id ? { ...t, [key]: val } : t)));
async function save(t: Tier) {
setBusy(t.id);
try {
await api.post("/rank-tiers", t);
} catch (e) {
toastError((e as Error).message);
} finally {
setBusy(null);
}
}
return (
<Shell title="رتبه‌ها">
<p className="text-sm text-[#8aa] mb-4">
رنگ و برچسبِ رتبهها (برنز تا پادشاه). اینها در حلقهی آواتار و نشانِ
رتبهی داخلِ بازی دیده میشوند و بدونِ بهروزرسانیِ اپ اعمال میشوند.
رنگ را با کدِ hex (مثلِ <code>FFD54F</code>) وارد کنید.
</p>
{loading ? (
<TableSkeleton rows={5} cols={7} />
) : (
<div className="card overflow-x-auto">
<table>
<thead>
<tr>
<th>پیشنمایش</th>
<th>شناسه</th>
<th>برچسب</th>
<th>رنگ ۱ (hex)</th>
<th>رنگ ۲ (hex)</th>
<th>ترتیب</th>
<th></th>
</tr>
</thead>
<tbody>
{tiers.map((t) => (
<tr key={t.id}>
<td>
<Swatch c1={t.c1} c2={t.c2} />
</td>
<td className="text-[#8aa]">{t.id}</td>
<td>
<input
className="inp"
style={{ minWidth: 90 }}
value={t.label}
onChange={(e) => patch(t.id, "label", e.target.value)}
/>
</td>
<td>
<input
className="inp"
style={{ minWidth: 90 }}
value={t.c1}
onChange={(e) => patch(t.id, "c1", e.target.value)}
/>
</td>
<td>
<input
className="inp"
style={{ minWidth: 90 }}
value={t.c2}
onChange={(e) => patch(t.id, "c2", e.target.value)}
/>
</td>
<td>
<input
className="inp"
style={{ minWidth: 60 }}
type="number"
value={t.sort}
onChange={(e) => patch(t.id, "sort", +e.target.value)}
/>
</td>
<td>
<button
className="btn btn-gold"
disabled={busy === t.id}
onClick={() => save(t)}
>
ذخیره
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</Shell>
);
}