137 lines
5.1 KiB
TypeScript
137 lines
5.1 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
export default function AdminHomework({ homework, members }: any) {
|
|
const router = useRouter();
|
|
const [title, setTitle] = useState("");
|
|
const [description, setDescription] = useState("");
|
|
const [videoFile, setVideoFile] = useState<File | null>(null);
|
|
const [videoUrl, setVideoUrl] = useState("");
|
|
const [target, setTarget] = useState("all");
|
|
const [saving, setSaving] = useState(false);
|
|
const [error, setError] = useState("");
|
|
|
|
async function handleSubmit(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
if (!title || !description) return;
|
|
setSaving(true);
|
|
setError("");
|
|
|
|
try {
|
|
let finalVideoUrl = videoUrl;
|
|
if (videoFile) {
|
|
const formData = new FormData();
|
|
formData.append("file", videoFile);
|
|
formData.append("subdir", "homework");
|
|
const up = await fetch("/api/upload", { method: "POST", body: formData });
|
|
if (!up.ok) throw new Error("Upload vidéo échoué");
|
|
const { url } = await up.json();
|
|
finalVideoUrl = url;
|
|
}
|
|
|
|
const res = await fetch("/api/homework", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
title,
|
|
description,
|
|
videoUrl: finalVideoUrl,
|
|
userId: target === "all" ? null : target,
|
|
}),
|
|
});
|
|
if (!res.ok) throw new Error("Enregistrement échoué");
|
|
|
|
setTitle("");
|
|
setDescription("");
|
|
setVideoFile(null);
|
|
setVideoUrl("");
|
|
setTarget("all");
|
|
router.refresh();
|
|
} catch (err: any) {
|
|
setError(err.message || "Erreur");
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
}
|
|
|
|
async function deleteHomework(id: string) {
|
|
if (!confirm("Supprimer cet exercice ?")) return;
|
|
await fetch("/api/homework", {
|
|
method: "DELETE",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ id }),
|
|
});
|
|
router.refresh();
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<h2 className="text-lg font-bold">🏋️ Exercices à travailler</h2>
|
|
|
|
<form onSubmit={handleSubmit} className="card space-y-3 border-primary-500/30">
|
|
<h3 className="font-semibold">📝 Nouvel exercice</h3>
|
|
<div>
|
|
<label className="label">Titre</label>
|
|
<input className="input" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Ex: 10 rounds de shadow box" required />
|
|
</div>
|
|
<div>
|
|
<label className="label">Description</label>
|
|
<textarea className="input min-h-[100px]" value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Décris l'exercice..." required />
|
|
</div>
|
|
<div>
|
|
<label className="label">À destination de</label>
|
|
<select className="input" value={target} onChange={(e) => setTarget(e.target.value)}>
|
|
<option value="all">Tous les membres</option>
|
|
{members.map((m: any) => (
|
|
<option key={m.id} value={m.id}>{m.name}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="label">Vidéo démonstrative (optionnel)</label>
|
|
{videoFile ? (
|
|
<p className="mb-2 text-sm text-primary-300">{videoFile.name}</p>
|
|
) : (
|
|
<label className="btn-secondary mb-2 w-full cursor-pointer">
|
|
📹 Téléverser une vidéo
|
|
<input type="file" accept="video/*" className="hidden" onChange={(e) => setVideoFile(e.target.files?.[0] || null)} />
|
|
</label>
|
|
)}
|
|
<input className="input" value={videoUrl} onChange={(e) => setVideoUrl(e.target.value)} placeholder="...ou coller une URL de vidéo" />
|
|
</div>
|
|
{error && <p className="text-sm text-red-400">{error}</p>}
|
|
<button type="submit" className="btn-primary w-full" disabled={saving}>
|
|
{saving ? "Enregistrement..." : "✅ Publier"}
|
|
</button>
|
|
</form>
|
|
|
|
<div className="space-y-3">
|
|
{homework.length === 0 && (
|
|
<p className="card text-center text-sm text-white/50">Aucun exercice publié.</p>
|
|
)}
|
|
{homework.map((h: any) => (
|
|
<div key={h.id} className="card">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<h3 className="font-semibold">{h.title}</h3>
|
|
<p className="mt-1 whitespace-pre-line text-sm text-white/75">{h.description}</p>
|
|
<p className="mt-2 text-xs text-white/40">
|
|
{h.user ? `Pour ${h.user.name}` : "Pour tous les membres"} ·{" "}
|
|
{new Date(h.createdAt).toLocaleDateString("fr-FR")}
|
|
</p>
|
|
{h.videoUrl && (
|
|
<video controls playsInline preload="metadata" className="mt-2 aspect-video w-full rounded-xl max-w-sm" src={h.videoUrl} />
|
|
)}
|
|
</div>
|
|
<button onClick={() => deleteHomework(h.id)} className="ml-3 shrink-0 text-sm text-red-400">
|
|
🗑️
|
|
</button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |