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

328 lines
10 KiB
TypeScript

"use client";
import { useState, useEffect, useTransition } from "react";
import { useSession } from "next-auth/react";
import Card from "@/components/ui/Card";
import Button from "@/components/ui/Button";
import SectionTitle from "@/components/ui/SectionTitle";
import HouseForm from "./HouseForm";
import RequestList from "./RequestList";
import Alert from "@/components/ui/Alert";
import { deleteHouse, leaveHouse } from "@/actions/houses/update";
import { inviteUser } from "@/actions/houses/invitations";
interface House {
id: string;
name: string;
description: string | null;
creator: {
id: string;
username: string;
avatar: string | null;
};
memberships?: Array<{
id: string;
role: string;
user: {
id: string;
username: string;
avatar: string | null;
score?: number;
level?: number;
};
}>;
}
interface User {
id: string;
username: string;
avatar: string | null;
}
interface HouseManagementProps {
house: House | null;
users?: User[];
requests?: Array<{
id: string;
requester: {
id: string;
username: string;
avatar: string | null;
};
status: string;
createdAt: string;
}>;
onUpdate?: () => void;
}
interface Request {
id: string;
requester: {
id: string;
username: string;
avatar: string | null;
};
status: string;
createdAt: string;
}
export default function HouseManagement({
house,
users = [],
requests: initialRequests = [],
onUpdate,
}: HouseManagementProps) {
const { data: session } = useSession();
const [isEditing, setIsEditing] = useState(false);
const [showInviteForm, setShowInviteForm] = useState(false);
const [selectedUserId, setSelectedUserId] = useState("");
const [requests, setRequests] = useState<Request[]>(initialRequests);
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState<string | null>(null);
const userRole = house?.memberships?.find(
(m) => m.user.id === session?.user?.id
)?.role;
const isOwner = userRole === "OWNER";
const isAdmin = userRole === "ADMIN" || isOwner;
const pendingRequests = requests.filter((r) => r.status === "PENDING");
useEffect(() => {
const fetchRequests = async () => {
if (!house || !isAdmin) return;
try {
const response = await fetch(`/api/houses/${house.id}/requests?status=PENDING`);
if (response.ok) {
const data = await response.json();
setRequests(data);
}
} catch (error) {
console.error("Error fetching requests:", error);
}
};
fetchRequests();
}, [house?.id, isAdmin]);
const handleDelete = () => {
if (!house || !confirm("Êtes-vous sûr de vouloir supprimer cette maison ?")) {
return;
}
setError(null);
startTransition(async () => {
const result = await deleteHouse(house.id);
if (result.success) {
onUpdate?.();
} else {
setError(result.error || "Erreur lors de la suppression");
}
});
};
const handleLeave = () => {
if (!house || !confirm("Êtes-vous sûr de vouloir quitter cette maison ?")) {
return;
}
setError(null);
startTransition(async () => {
const result = await leaveHouse(house.id);
if (result.success) {
onUpdate?.();
} else {
setError(result.error || "Erreur lors de la sortie");
}
});
};
const handleInvite = () => {
if (!house || !selectedUserId) return;
setError(null);
setSuccess(null);
startTransition(async () => {
const result = await inviteUser(house.id, selectedUserId);
if (result.success) {
setSuccess("Invitation envoyée");
setShowInviteForm(false);
setSelectedUserId("");
onUpdate?.();
} else {
setError(result.error || "Erreur lors de l'envoi de l'invitation");
}
});
};
const availableUsers = users.filter(
(u) =>
u.id !== session?.user?.id &&
!house?.memberships?.some((m) => m.user.id === u.id)
);
if (!house) {
return (
<Card className="p-6">
<SectionTitle>Ma Maison</SectionTitle>
<p className="text-sm mb-4" style={{ color: "var(--muted-foreground)" }}>
Vous n'êtes membre d'aucune maison pour le moment.
</p>
</Card>
);
}
return (
<div className="space-y-6">
<Card className="p-4 sm:p-6">
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-4 mb-4">
<div className="flex-1 min-w-0">
<SectionTitle>{house.name}</SectionTitle>
{house.description && (
<p className="text-sm mt-2 break-words" style={{ color: "var(--muted-foreground)" }}>
{house.description}
</p>
)}
</div>
<div className="flex flex-wrap gap-2 sm:flex-nowrap">
{isAdmin && (
<>
<Button
onClick={() => setIsEditing(!isEditing)}
variant="secondary"
size="sm"
className="flex-1 sm:flex-none"
>
{isEditing ? "Annuler" : "Modifier"}
</Button>
{isOwner && (
<Button onClick={handleDelete} variant="danger" size="sm" className="flex-1 sm:flex-none">
Supprimer
</Button>
)}
</>
)}
{!isOwner && (
<Button onClick={handleLeave} variant="danger" size="sm" className="flex-1 sm:flex-none">
Quitter
</Button>
)}
</div>
</div>
{error && <Alert variant="error" className="mb-4">{error}</Alert>}
{success && <Alert variant="success" className="mb-4">{success}</Alert>}
{isEditing ? (
<HouseForm
house={house}
onSuccess={() => {
setIsEditing(false);
onUpdate?.();
}}
onCancel={() => setIsEditing(false)}
/>
) : (
<div>
<h3 className="font-bold mb-3" style={{ color: "var(--foreground)" }}>
Membres ({house.memberships?.length ?? 0})
</h3>
<div className="space-y-2">
{(house.memberships || []).map((membership) => (
<div
key={membership.id}
className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 p-2 rounded"
style={{ backgroundColor: "var(--card-hover)" }}
>
<div className="flex items-center gap-2 min-w-0 flex-1">
{membership.user.avatar && (
<img
src={membership.user.avatar}
alt={membership.user.username}
className="w-8 h-8 rounded-full flex-shrink-0"
/>
)}
<div className="min-w-0">
<span className="font-semibold block sm:inline" style={{ color: "var(--foreground)" }}>
{membership.user.username}
</span>
<span className="text-xs block sm:inline sm:ml-2" style={{ color: "var(--muted-foreground)" }}>
({membership.user.score} pts - Niveau {membership.user.level})
</span>
</div>
</div>
<span className="text-xs uppercase flex-shrink-0" style={{ color: "var(--accent)" }}>
{membership.role}
</span>
</div>
))}
</div>
{isAdmin && (
<div className="mt-4">
{showInviteForm ? (
<div className="space-y-2">
<select
value={selectedUserId}
onChange={(e) => setSelectedUserId(e.target.value)}
className="w-full p-2 rounded border"
style={{
backgroundColor: "var(--input)",
borderColor: "var(--border)",
color: "var(--foreground)",
}}
>
<option value="">Sélectionner un utilisateur</option>
{availableUsers.map((user) => (
<option key={user.id} value={user.id}>
{user.username}
</option>
))}
</select>
<div className="flex gap-2">
<Button
onClick={handleInvite}
disabled={!selectedUserId || isPending}
variant="primary"
size="sm"
>
{isPending ? "Envoi..." : "Inviter"}
</Button>
<Button
onClick={() => {
setShowInviteForm(false);
setSelectedUserId("");
}}
variant="secondary"
size="sm"
>
Annuler
</Button>
</div>
</div>
) : (
<Button
onClick={() => setShowInviteForm(true)}
variant="primary"
size="sm"
>
Inviter un utilisateur
</Button>
)}
</div>
)}
</div>
)}
</Card>
{isAdmin && pendingRequests.length > 0 && (
<Card className="p-4 sm:p-6">
<SectionTitle>Demandes d'adhésion</SectionTitle>
<RequestList requests={pendingRequests} onUpdate={onUpdate} />
</Card>
)}
</div>
);
}