180 lines
5.9 KiB
TypeScript
180 lines
5.9 KiB
TypeScript
"use client";
|
||
|
||
import { useState, useEffect } from "react";
|
||
import { Trash2, Edit, Copy, QrCode } from "lucide-react";
|
||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Client } from "@/lib/types/client";
|
||
import QRCodeDisplay from "./QRCodeDisplay";
|
||
|
||
interface ClientListProps {
|
||
onEdit: (client: Client) => void;
|
||
onRefresh: () => void;
|
||
}
|
||
|
||
export default function ClientList({ onEdit, onRefresh }: ClientListProps) {
|
||
const [clients, setClients] = useState<Client[]>([]);
|
||
const [loading, setLoading] = useState(true);
|
||
const [selectedClient, setSelectedClient] = useState<Client | null>(null);
|
||
const [showQR, setShowQR] = useState<string | null>(null);
|
||
|
||
useEffect(() => {
|
||
fetchClients();
|
||
}, []);
|
||
|
||
const fetchClients = async () => {
|
||
try {
|
||
const adminPassword = localStorage.getItem("adminPassword") || "";
|
||
const response = await fetch("/api/admin/clients", {
|
||
headers: {
|
||
Authorization: `Bearer ${adminPassword}`,
|
||
},
|
||
});
|
||
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
setClients(data);
|
||
} else if (response.status === 404) {
|
||
// API non disponible (mode statique/APK)
|
||
// Afficher un message d'information
|
||
console.warn("API non disponible en mode statique");
|
||
setClients([]);
|
||
} else {
|
||
console.error("Erreur lors du chargement des clients:", response.status);
|
||
setClients([]);
|
||
}
|
||
} catch (error) {
|
||
// Erreur réseau (API non disponible en mode statique/APK)
|
||
console.warn("API non disponible (mode statique/APK). Les fonctionnalités admin nécessitent un serveur.");
|
||
setClients([]);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const handleDelete = async (id: string) => {
|
||
if (!confirm("Êtes-vous sûr de vouloir supprimer ce client ?")) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const adminPassword = localStorage.getItem("adminPassword") || "";
|
||
const response = await fetch(`/api/admin/clients/${id}`, {
|
||
method: "DELETE",
|
||
headers: {
|
||
Authorization: `Bearer ${adminPassword}`,
|
||
},
|
||
});
|
||
|
||
if (response.ok) {
|
||
fetchClients();
|
||
onRefresh();
|
||
}
|
||
} catch (error) {
|
||
console.error("Erreur lors de la suppression:", error);
|
||
}
|
||
};
|
||
|
||
const getClientUrl = (token: string) => {
|
||
const baseUrl = typeof window !== "undefined" ? window.location.origin : "";
|
||
return `${baseUrl}/accueil?token=${token}`;
|
||
};
|
||
|
||
if (loading) {
|
||
return (
|
||
<div className="flex items-center justify-center py-8">
|
||
<p className="text-gray-600 dark:text-gray-400">Chargement...</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
if (clients.length === 0) {
|
||
return (
|
||
<Card>
|
||
<CardContent className="py-8 text-center space-y-4">
|
||
<p className="text-gray-600 dark:text-gray-400">Aucun client pour le moment.</p>
|
||
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-xl p-4 text-sm text-yellow-800 dark:text-yellow-300">
|
||
<p className="font-semibold mb-1">⚠️ Mode hors ligne</p>
|
||
<p>L'application admin nécessite une connexion au serveur pour fonctionner. Les API routes ne sont pas disponibles en mode statique.</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-4">
|
||
{clients.map((client) => (
|
||
<Card key={client.id}>
|
||
<CardHeader>
|
||
<div className="flex items-start justify-between">
|
||
<div className="flex-1">
|
||
<CardTitle className="text-lg">{client.email}</CardTitle>
|
||
<p className="text-sm text-gray-600 mt-1">
|
||
Bungalow {client.bungalowNumber}
|
||
</p>
|
||
</div>
|
||
<div className="flex gap-2">
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => {
|
||
const url = getClientUrl(client.token);
|
||
navigator.clipboard.writeText(url);
|
||
}}
|
||
>
|
||
<Copy className="h-4 w-4" />
|
||
</Button>
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() =>
|
||
setShowQR(showQR === client.id ? null : client.id)
|
||
}
|
||
>
|
||
<QrCode className="h-4 w-4" />
|
||
</Button>
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => onEdit(client)}
|
||
>
|
||
<Edit className="h-4 w-4" />
|
||
</Button>
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => handleDelete(client.id)}
|
||
>
|
||
<Trash2 className="h-4 w-4" />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-2 text-sm">
|
||
<div>
|
||
<span className="font-medium">WiFi:</span> {client.wifiName}
|
||
</div>
|
||
<div>
|
||
<span className="font-medium">Message:</span>{" "}
|
||
{client.gerantMessage.substring(0, 50)}
|
||
{client.gerantMessage.length > 50 ? "..." : ""}
|
||
</div>
|
||
<div className="text-xs text-gray-500">
|
||
Créé le {new Date(client.createdAt).toLocaleDateString("fr-FR")}
|
||
</div>
|
||
</div>
|
||
{showQR === client.id && (
|
||
<div className="mt-4 pt-4 border-t border-gray-200">
|
||
<QRCodeDisplay url={getClientUrl(client.token)} size={150} />
|
||
</div>
|
||
)}
|
||
</CardContent>
|
||
</Card>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
|