181 lines
6.0 KiB
TypeScript
181 lines
6.0 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import { useRouter } from "next/navigation";
|
||
import Image from "next/image";
|
||
|
||
type Country = { id: string; name: string };
|
||
type CardTier = "GOLD" | "SILVER" | "BRONZE";
|
||
|
||
export default function PlayerForm({
|
||
countries,
|
||
initial,
|
||
playerId,
|
||
}: {
|
||
countries: Country[];
|
||
initial?: { name: string; position: string; countryId: string; price: number; image?: string | null; cardTier: CardTier };
|
||
playerId?: string;
|
||
}) {
|
||
const router = useRouter();
|
||
const [form, setForm] = useState({
|
||
name: initial?.name ?? "",
|
||
position: initial?.position ?? "FWD",
|
||
countryId: initial?.countryId ?? "",
|
||
price: initial?.price ?? 5.0,
|
||
image: initial?.image ?? "",
|
||
cardTier: initial?.cardTier ?? "BRONZE",
|
||
});
|
||
const [loading, setLoading] = useState(false);
|
||
const [uploading, setUploading] = useState(false);
|
||
const [error, setError] = useState("");
|
||
|
||
async function handleImageUpload(e: React.ChangeEvent<HTMLInputElement>) {
|
||
const file = e.target.files?.[0];
|
||
if (!file) return;
|
||
|
||
setUploading(true);
|
||
setError("");
|
||
|
||
const formData = new FormData();
|
||
formData.append("file", file);
|
||
|
||
try {
|
||
const res = await fetch("/api/upload/player-image", {
|
||
method: "POST",
|
||
body: formData,
|
||
});
|
||
|
||
if (res.ok) {
|
||
const data = await res.json();
|
||
setForm({ ...form, image: data.fileName });
|
||
} else {
|
||
const data = await res.json();
|
||
setError(data.error ?? "خطا در آپلود تصویر");
|
||
}
|
||
} catch (err) {
|
||
setError("خطا در آپلود تصویر");
|
||
} finally {
|
||
setUploading(false);
|
||
}
|
||
}
|
||
|
||
async function handleSubmit(e: React.FormEvent) {
|
||
e.preventDefault();
|
||
setLoading(true);
|
||
const res = await fetch(playerId ? `/api/players/${playerId}` : "/api/players", {
|
||
method: playerId ? "PUT" : "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(form),
|
||
});
|
||
if (res.ok) {
|
||
router.push("/admin/players");
|
||
router.refresh();
|
||
} else {
|
||
const d = await res.json();
|
||
setError(d.error ?? "خطا");
|
||
}
|
||
setLoading(false);
|
||
}
|
||
|
||
return (
|
||
<form onSubmit={handleSubmit} className="bg-white rounded-2xl shadow p-6 flex flex-col gap-4">
|
||
{error && <p className="text-red-500 text-sm">{error}</p>}
|
||
|
||
<div>
|
||
<label className="block text-sm font-medium mb-1">تصویر بازیکن</label>
|
||
<div className="flex items-center gap-4">
|
||
{form.image && (
|
||
<div className="relative w-24 h-24 rounded-xl overflow-hidden border">
|
||
<Image
|
||
src={`/uploads/players/${form.image}`}
|
||
alt={form.name}
|
||
fill
|
||
className="object-cover"
|
||
/>
|
||
</div>
|
||
)}
|
||
<div className="flex-1">
|
||
<input
|
||
type="file"
|
||
accept="image/*"
|
||
onChange={handleImageUpload}
|
||
disabled={uploading}
|
||
className="w-full border rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
|
||
/>
|
||
{uploading && <p className="text-sm text-gray-500 mt-1">در حال آپلود...</p>}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-sm font-medium mb-1">نام بازیکن</label>
|
||
<input
|
||
type="text"
|
||
value={form.name}
|
||
onChange={(e) => setForm({ ...form, name: e.target.value })}
|
||
className="w-full border rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
|
||
required
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-sm font-medium mb-1">پست</label>
|
||
<select
|
||
value={form.position}
|
||
onChange={(e) => setForm({ ...form, position: e.target.value })}
|
||
className="w-full border rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
|
||
>
|
||
<option value="GK">دروازهبان</option>
|
||
<option value="DEF">مدافع</option>
|
||
<option value="MID">هافبک</option>
|
||
<option value="FWD">مهاجم</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label className="block text-sm font-medium mb-1">تیم ملی</label>
|
||
<select
|
||
value={form.countryId}
|
||
onChange={(e) => setForm({ ...form, countryId: e.target.value })}
|
||
className="w-full border rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
|
||
required
|
||
>
|
||
<option value="">انتخاب کنید</option>
|
||
{countries.map((c) => (
|
||
<option key={c.id} value={c.id}>{c.name}</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label className="block text-sm font-medium mb-1">قیمت (میلیون)</label>
|
||
<input
|
||
type="number"
|
||
step="0.5"
|
||
min="4"
|
||
max="15"
|
||
value={form.price}
|
||
onChange={(e) => setForm({ ...form, price: parseFloat(e.target.value) })}
|
||
className="w-full border rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-sm font-medium mb-1">نوع کارت</label>
|
||
<select
|
||
value={form.cardTier}
|
||
onChange={(e) => setForm({ ...form, cardTier: e.target.value as CardTier })}
|
||
className="w-full border rounded-xl px-4 py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500"
|
||
>
|
||
<option value="GOLD">طلایی</option>
|
||
<option value="SILVER">نقره ای</option>
|
||
<option value="BRONZE">برنزی</option>
|
||
</select>
|
||
</div>
|
||
<button
|
||
type="submit"
|
||
disabled={loading}
|
||
className="bg-green-700 text-white py-3 rounded-xl font-bold hover:bg-green-800 transition disabled:opacity-50"
|
||
>
|
||
{loading ? "در حال ذخیره..." : playerId ? "ذخیره تغییرات" : "افزودن بازیکن"}
|
||
</button>
|
||
</form>
|
||
);
|
||
}
|