Files
got-gaming/components/houses/InvitationList.tsx

130 lines
3.9 KiB
TypeScript

"use client";
import { useState, useTransition } from "react";
import Card from "@/components/ui/Card";
import Button from "@/components/ui/Button";
import {
acceptInvitation,
rejectInvitation,
} from "@/actions/houses/invitations";
import Alert from "@/components/ui/Alert";
interface Invitation {
id: string;
house: {
id: string;
name: string;
};
inviter: {
id: string;
username: string;
avatar: string | null;
};
status: string;
createdAt: string;
}
interface InvitationListProps {
invitations: Invitation[];
onUpdate?: () => void;
}
export default function InvitationList({
invitations,
onUpdate,
}: InvitationListProps) {
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<string | null>(null);
const handleAccept = (invitationId: string) => {
setError(null);
startTransition(async () => {
const result = await acceptInvitation(invitationId);
if (result.success) {
// Rafraîchir le score dans le header (l'utilisateur reçoit des points)
window.dispatchEvent(new Event("refreshUserScore"));
// Rafraîchir le badge d'invitations dans le header
window.dispatchEvent(new Event("refreshInvitations"));
onUpdate?.();
} else {
setError(result.error || "Erreur lors de l'acceptation");
}
});
};
const handleReject = (invitationId: string) => {
setError(null);
startTransition(async () => {
const result = await rejectInvitation(invitationId);
if (result.success) {
// Rafraîchir le badge d'invitations dans le header
window.dispatchEvent(new Event("refreshInvitations"));
onUpdate?.();
} else {
setError(result.error || "Erreur lors du refus");
}
});
};
if (invitations.length === 0) {
return (
<p className="text-sm" style={{ color: "var(--muted-foreground)" }}>
Aucune invitation en attente
</p>
);
}
return (
<div className="space-y-4">
{error && <Alert variant="error">{error}</Alert>}
{invitations.map((invitation) => (
<Card key={invitation.id} className="p-4">
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3">
<div className="flex-1 min-w-0">
<h4 className="font-bold mb-1 break-words" style={{ color: "var(--foreground)" }}>
Invitation de {invitation.inviter.username}
</h4>
<p className="text-sm mb-2 break-words" style={{ color: "var(--muted-foreground)" }}>
Pour rejoindre la maison <strong>{invitation.house.name}</strong>
</p>
</div>
{invitation.status === "PENDING" && (
<div className="flex gap-2 sm:flex-nowrap">
<Button
onClick={() => handleAccept(invitation.id)}
disabled={isPending}
variant="success"
size="sm"
className="flex-1 sm:flex-none"
>
Accepter
</Button>
<Button
onClick={() => handleReject(invitation.id)}
disabled={isPending}
variant="danger"
size="sm"
className="flex-1 sm:flex-none"
>
Refuser
</Button>
</div>
)}
{invitation.status === "ACCEPTED" && (
<span className="text-xs flex-shrink-0" style={{ color: "var(--success)" }}>
Acceptée
</span>
)}
{invitation.status === "REJECTED" && (
<span className="text-xs flex-shrink-0" style={{ color: "var(--destructive)" }}>
Refusée
</span>
)}
</div>
</Card>
))}
</div>
);
}