spomeni/src/app/admin/(panel)/codes/page.tsx

145 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useEffect, useState } from "react";
interface Code {
id: string;
code: string;
usedByUserId: string | null;
usedAt: string | null;
createdAt: string;
createdBy: { username: string };
}
export default function AdminCodesPage() {
const [codes, setCodes] = useState<Code[]>([]);
const [loading, setLoading] = useState(true);
const [generating, setGenerating] = useState(false);
const [newCode, setNewCode] = useState("");
const [error, setError] = useState("");
const fetchCodes = async () => {
setLoading(true);
try {
const res = await fetch("/api/admin/codes", { credentials: "include" });
if (res.ok) {
setCodes(await res.json());
}
} catch {
// ignore
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchCodes();
}, []);
const handleGenerate = async () => {
setGenerating(true);
setError("");
setNewCode("");
try {
const res = await fetch("/api/admin/codes", { method: "POST", credentials: "include" });
const data = await res.json();
if (!res.ok) {
throw new Error(data.error || "Грешка при генерирање");
}
setNewCode(data.code);
fetchCodes();
} catch (err) {
setError(err instanceof Error ? err.message : "Грешка при генерирање");
} finally {
setGenerating(false);
}
};
const handleDelete = async (id: string) => {
if (!confirm("Дали сте сигурни?")) return;
try {
await fetch(`/api/admin/codes/${id}`, { method: "DELETE", credentials: "include" });
fetchCodes();
} catch {
// ignore
}
};
return (
<div>
<div className="mb-8 flex items-center justify-between">
<h1 className="text-2xl font-semibold text-stone-900">Кодови</h1>
<button
onClick={handleGenerate}
disabled={generating}
className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-primary-light disabled:cursor-not-allowed disabled:opacity-50"
>
{generating ? "Генерирање..." : "Генерирај код"}
</button>
</div>
{newCode && (
<div className="mb-8 rounded-lg border border-green-200 bg-green-50 p-4">
<p className="text-sm font-medium text-green-800">Нов код:</p>
<p className="mt-1 text-2xl font-bold tracking-widest text-green-900">{newCode}</p>
<p className="mt-1 text-xs text-green-600">Копирајте го кодот. Ќе биде прикажан само еднаш.</p>
</div>
)}
{error && (
<div className="mb-8 rounded-lg bg-red-50 p-4 text-sm text-red-700">{error}</div>
)}
<div className="rounded-lg bg-white shadow-sm">
{loading ? (
<p className="p-6 text-sm text-stone-500">Вчитување...</p>
) : codes.length === 0 ? (
<p className="p-6 text-sm text-stone-500">Нема генерирани кодови</p>
) : (
<table className="w-full text-left text-sm">
<thead className="border-b border-stone-200">
<tr>
<th className="px-6 py-3 font-medium text-stone-500">Код</th>
<th className="px-6 py-3 font-medium text-stone-500">Креиран од</th>
<th className="px-6 py-3 font-medium text-stone-500">Креиран</th>
<th className="px-6 py-3 font-medium text-stone-500">Статус</th>
<th className="px-6 py-3 font-medium text-stone-500">Акции</th>
</tr>
</thead>
<tbody className="divide-y divide-stone-100">
{codes.map((item) => (
<tr key={item.id} className="hover:bg-stone-50">
<td className="px-6 py-4 font-mono text-stone-900">{item.code}</td>
<td className="px-6 py-4 text-stone-600">{item.createdBy.username}</td>
<td className="px-6 py-4 text-stone-600">{new Date(item.createdAt).toLocaleDateString("mk-MK")}</td>
<td className="px-6 py-4">
{item.usedByUserId ? (
<span className="inline-flex rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800">
Искористен
</span>
) : (
<span className="inline-flex rounded-full bg-stone-100 px-2.5 py-0.5 text-xs font-medium text-stone-600">
Неискористен
</span>
)}
</td>
<td className="px-6 py-4">
{!item.usedByUserId && (
<button
onClick={() => handleDelete(item.id)}
className="text-sm text-red-600 hover:underline"
>
Избриши
</button>
)}
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
);
}