Initial commit: JuanitoSport - Muay Thai & Yog4Fight PWA
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function AdminMessages({ messages, readMap, totalMembers }: any) {
|
||||
const router = useRouter();
|
||||
const [title, setTitle] = useState("");
|
||||
const [content, setContent] = useState("");
|
||||
const [category, setCategory] = useState("general");
|
||||
const [sending, setSending] = useState(false);
|
||||
|
||||
async function sendMessage(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setSending(true);
|
||||
const res = await fetch("/api/admin/messages", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ title, content, category }),
|
||||
});
|
||||
setSending(false);
|
||||
if (res.ok) {
|
||||
setTitle("");
|
||||
setContent("");
|
||||
setCategory("general");
|
||||
router.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h2 className="text-lg font-bold">💬 Messages / Tips</h2>
|
||||
|
||||
<form onSubmit={sendMessage} className="card space-y-3 border-primary-500/30">
|
||||
<h3 className="font-semibold">✍️ Nouveau message</h3>
|
||||
<div>
|
||||
<label className="label">Titre</label>
|
||||
<input className="input" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Ex: Conseil de la semaine" required />
|
||||
</div>
|
||||
<div>
|
||||
<label className="label">Message</label>
|
||||
<textarea className="input min-h-[120px]" value={content} onChange={(e) => setContent(e.target.value)} placeholder="Écris ton message... les adhérents le verront dans leur espace." required />
|
||||
</div>
|
||||
<div>
|
||||
<label className="label">Audience</label>
|
||||
<div className="flex gap-2">
|
||||
{[
|
||||
["general", "🌍 Tout le monde"],
|
||||
["muay-thai", "🥊 Muay Thai"],
|
||||
["yoga", "🧘 Yoga"],
|
||||
].map(([val, label]) => (
|
||||
<button
|
||||
key={val}
|
||||
type="button"
|
||||
onClick={() => setCategory(val)}
|
||||
className={`rounded-xl px-3 py-2 text-sm font-semibold ${
|
||||
category === val
|
||||
? "bg-primary-600 text-white"
|
||||
: "bg-white/5 text-white/60"
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" className="btn-primary w-full" disabled={sending || !title || !content}>
|
||||
{sending ? "Envoi..." : "📨 Publier le message"}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div className="space-y-3">
|
||||
{messages.length === 0 && (
|
||||
<p className="card text-center text-sm text-white/50">
|
||||
Aucun message publié.
|
||||
</p>
|
||||
)}
|
||||
{messages.map((m: any) => (
|
||||
<div key={m.id} className="card">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<h3 className="font-semibold">{m.title}</h3>
|
||||
<p className="mt-1 whitespace-pre-line text-sm text-white/75">{m.content}</p>
|
||||
<p className="mt-2 text-xs text-white/40">
|
||||
{new Date(m.createdAt).toLocaleDateString("fr-FR", { day: "numeric", month: "long", year: "numeric" })} ·{" "}
|
||||
{m.category === "muay-thai" ? "🥊" : m.category === "yoga" ? "🧘" : "🌍"}
|
||||
</p>
|
||||
</div>
|
||||
<span className="shrink-0 rounded-full bg-white/5 px-2 py-1 text-xs text-white/50">
|
||||
{readMap[m.id] || 0} lu(s)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import AdminMessages from "./messages-admin";
|
||||
|
||||
export default async function MessagesPage() {
|
||||
const messages = await prisma.message.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
});
|
||||
|
||||
const readCount = await prisma.messageRead.groupBy({
|
||||
by: ["messageId"],
|
||||
_count: { _all: true },
|
||||
});
|
||||
|
||||
const readMap: Record<string, number> = {};
|
||||
readCount.forEach((r) => {
|
||||
readMap[r.messageId] = r._count._all;
|
||||
});
|
||||
|
||||
return <AdminMessages messages={messages} readMap={readMap} totalMembers={0} />;
|
||||
}
|
||||
Reference in New Issue
Block a user