Yaltopia-FIFA/components/master/master-leagues-client.tsx
Kirubel-Kibru-Yaltopia 89440985f1
Some checks failed
Deploy to Cloudflare Workers / deploy (push) Has been cancelled
x
2026-05-24 21:46:10 +03:00

153 lines
5.3 KiB
TypeScript

"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { api } from "@/lib/api/client";
import { GlassCard } from "@/components/ui/glass-card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
import { PageHeader } from "@/components/dashboard/page-header";
import { Trash2, ExternalLink } from "lucide-react";
type League = {
id: string;
name: string;
description: string | null;
slug: string;
};
export function MasterLeaguesClient({ initialLeagues }: { initialLeagues: League[] }) {
const router = useRouter();
const [leagues, setLeagues] = useState(initialLeagues);
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [loading, setLoading] = useState(false);
const [deleteTarget, setDeleteTarget] = useState<League | null>(null);
const [error, setError] = useState<string | null>(null);
async function handleCreate(e: React.FormEvent) {
e.preventDefault();
if (loading) return;
setLoading(true);
setError(null);
try {
const created = (await api.leagues.create({
name: name.trim(),
description: description.trim() || undefined,
})) as League;
setLeagues((prev) => [created, ...prev]);
setName("");
setDescription("");
router.refresh();
} catch (err) {
setError(err instanceof Error ? err.message : "Failed to create");
} finally {
setLoading(false);
}
}
return (
<div className="space-y-6">
<PageHeader
title="Leagues"
description="Create and manage tournament leagues"
/>
{error && <p className="text-sm text-red-400">{error}</p>}
<GlassCard title="New league">
<form onSubmit={handleCreate} className="flex flex-wrap items-end gap-4">
<div className="min-w-[200px] flex-1">
<Label>Name</Label>
<Input
value={name}
onChange={(e) => setName(e.target.value)}
required
className="mt-1"
placeholder="Sunday League"
/>
</div>
<div className="min-w-[200px] flex-1">
<Label>Description</Label>
<Input
value={description}
onChange={(e) => setDescription(e.target.value)}
className="mt-1"
/>
</div>
<Button type="submit" disabled={loading}>
{loading ? "Creating…" : "Create league"}
</Button>
</form>
</GlassCard>
<GlassCard title={`All leagues (${leagues.length})`}>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-white/10 text-left text-[var(--color-muted)]">
<th className="pb-3 pr-4">Name</th>
<th className="pb-3 pr-4">ID</th>
<th className="pb-3 pr-4">Actions</th>
</tr>
</thead>
<tbody>
{leagues.map((l) => (
<tr key={l.id} className="border-b border-white/5">
<td className="py-3 pr-4 font-medium">{l.name}</td>
<td className="py-3 pr-4 font-mono text-xs text-[var(--color-muted)]">
{l.id.slice(0, 8)}
</td>
<td className="py-3">
<div className="flex gap-2">
<Button variant="outline" size="sm" asChild>
<Link href={`/master/leagues/${l.id}`}>
<ExternalLink className="h-3 w-3" />
Open
</Link>
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => setDeleteTarget(l)}
>
<Trash2 className="h-4 w-4 text-red-400" />
</Button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</GlassCard>
<ConfirmDialog
open={!!deleteTarget}
onOpenChange={(o) => !o && setDeleteTarget(null)}
title="Delete league?"
description={`Permanently delete "${deleteTarget?.name}" and all competitions, teams, and matches? This cannot be undone.`}
confirmLabel="Delete league"
loading={loading}
onConfirm={async () => {
if (!deleteTarget) return;
setLoading(true);
try {
await api.leagues.delete(deleteTarget.id);
setLeagues((prev) => prev.filter((x) => x.id !== deleteTarget.id));
setDeleteTarget(null);
router.refresh();
} catch (e) {
setError(e instanceof Error ? e.message : "Delete failed");
} finally {
setLoading(false);
}
}}
/>
</div>
);
}