Yaltopia-FIFA/components/issues/issues-panel.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

155 lines
4.8 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
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 { PageHeader } from "@/components/dashboard/page-header";
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
type Issue = {
id: string;
subject: string;
body: string;
status: string;
master_reply: string | null;
created_at: string;
leagues: { name: string } | null;
};
export function IssuesPanel({
leagues,
asMaster,
}: {
leagues: { id: string; name: string }[];
asMaster: boolean;
}) {
const [issues, setIssues] = useState<Issue[]>([]);
const [loading, setLoading] = useState(false);
const [showConfirm, setShowConfirm] = useState(false);
const [pending, setPending] = useState<FormData | null>(null);
useEffect(() => {
api.issues.list(asMaster).then((d) => setIssues(d as Issue[]));
}, [asMaster]);
async function submit(fd: FormData) {
setLoading(true);
try {
await api.issues.create({
leagueId: fd.get("league_id") as string,
subject: fd.get("subject") as string,
body: fd.get("body") as string,
});
const updated = (await api.issues.list(asMaster)) as Issue[];
setIssues(updated);
} finally {
setLoading(false);
setShowConfirm(false);
setPending(null);
}
}
return (
<div className="space-y-6">
<PageHeader
title="Issues"
description={
asMaster
? "Messages from team managers"
: "Send problems to your league master"
}
/>
{!asMaster && (
<GlassCard title="New issue">
<form
className="space-y-3"
onSubmit={(e) => {
e.preventDefault();
if (leagues.length === 0) return;
setPending(new FormData(e.currentTarget));
setShowConfirm(true);
}}
>
<div>
<Label>League</Label>
<select
name="league_id"
required
className="mt-1 flex h-10 w-full rounded-lg border border-white/15 bg-white/5 px-3 text-sm"
>
{leagues.map((l) => (
<option key={l.id} value={l.id}>
{l.name}
</option>
))}
</select>
</div>
<div>
<Label>Subject</Label>
<Input name="subject" required className="mt-1" />
</div>
<div>
<Label>Details</Label>
<textarea
name="body"
required
rows={4}
className="mt-1 flex w-full rounded-lg border border-white/15 bg-white/5 px-3 py-2 text-sm"
/>
</div>
<Button type="submit" disabled={loading || leagues.length === 0}>
Submit to league master
</Button>
</form>
</GlassCard>
)}
<GlassCard title={asMaster ? "All issues" : "Your issues"}>
<ul className="space-y-3">
{issues.map((issue) => (
<li
key={issue.id}
className="rounded-lg border border-white/10 p-3 text-sm"
>
<div className="flex justify-between gap-2">
<p className="font-medium">{issue.subject}</p>
<span className="text-xs capitalize text-[var(--color-muted)]">
{issue.status}
</span>
</div>
<p className="mt-1 text-xs text-cyan-400/70">
{issue.leagues?.name}
</p>
<p className="mt-2 text-[var(--color-muted)]">{issue.body}</p>
{issue.master_reply && (
<p className="mt-2 rounded-lg bg-white/5 p-2 text-foreground">
<span className="text-xs text-[var(--color-muted)]">Reply: </span>
{issue.master_reply}
</p>
)}
</li>
))}
{issues.length === 0 && (
<p className="text-[var(--color-muted)]">No issues</p>
)}
</ul>
</GlassCard>
<ConfirmDialog
open={showConfirm}
onOpenChange={setShowConfirm}
title="Send issue to league master?"
description="Your message will be visible to league masters for this league."
confirmLabel="Send"
variant="primary"
loading={loading}
onConfirm={() => pending && submit(pending)}
/>
</div>
);
}