144 lines
6.4 KiB
React
144 lines
6.4 KiB
React
import { useState, useEffect } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { getOrdersList } from '../../services/billing_api';
|
|
import { AlertCircle, Loader, FileText, X } from 'lucide-react';
|
|
|
|
// Importation des composants
|
|
import DashboardServiceCard from '../../components/dashboard/DashboardServiceCard';
|
|
import NewServiceCard from '../../components/dashboard/NewServiceCard';
|
|
import NotificationModal from '../../components/ui/NotificationModal';
|
|
import WebServiceSubscriptionManager from '../../components/dashboard/WebServiceSubscriptionManager';
|
|
|
|
export default function Dashboard() {
|
|
const navigate = useNavigate();
|
|
const [orders, setOrders] = useState([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [error, setError] = useState(null);
|
|
|
|
const [activeSubscriptionModal, setActiveSubscriptionModal] = useState(null);
|
|
const [customAlert, setCustomAlert] = useState(null);
|
|
|
|
const triggerAlert = (title, message, type = "info") => setCustomAlert({ title, message, type });
|
|
|
|
const fetchInventory = async () => {
|
|
setIsLoading(true);
|
|
try {
|
|
const data = await getOrdersList();
|
|
|
|
if (data.list) {
|
|
// LE FILTRE CHIRURGICAL PAR PREFIXE
|
|
const filteredOrders = data.list.filter(order => {
|
|
const title = (order.title || '').toLowerCase();
|
|
const type = (order.type || '').toLowerCase();
|
|
|
|
const isGhostProduct =
|
|
type === 'domain' ||
|
|
title.startsWith('domain ') ||
|
|
title.startsWith('domaine ') ||
|
|
title.startsWith('enregistrement ');
|
|
|
|
return !isGhostProduct;
|
|
});
|
|
|
|
setOrders(filteredOrders);
|
|
} else {
|
|
setOrders([]);
|
|
}
|
|
} catch (err) {
|
|
setError(err.message || "Impossible de récupérer la télémétrie des services.");
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchInventory();
|
|
}, []);
|
|
|
|
// 🌟 Plus besoin de charger les IPs, on ouvre juste la modale comptable !
|
|
const handleManageSubscription = (order) => {
|
|
// 1. Détection du type de service
|
|
const titleLower = (order.title || '').toLowerCase();
|
|
const isVPS = titleLower.includes('vps') || titleLower.includes('compute');
|
|
const isCloud = titleLower.includes('cloud') || titleLower.includes('nextcloud');
|
|
const isDB = titleLower.includes('db') || titleLower.includes('base') || titleLower.includes('sql');
|
|
|
|
// C'est un hébergement web s'il ne correspond à aucun des cas ci-dessus
|
|
const isWeb = !isVPS && !isCloud && !isDB;
|
|
|
|
// 2. Logique de blocage
|
|
if (isWeb) {
|
|
// On ouvre la modale comptable uniquement pour le WEB
|
|
setActiveSubscriptionModal(order);
|
|
} else {
|
|
// On affiche une notification pour les autres types d'instances
|
|
triggerAlert(
|
|
"Action non disponible",
|
|
"La modification autonome d'abonnement est actuellement exclusive aux Hébergements Web. Pour restructurer cette instance, veuillez contacter les ingénieurs via le Centre de Support.",
|
|
"info"
|
|
);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="w-full max-w-6xl p-6 mx-auto relative">
|
|
<header className="mb-8">
|
|
<h1 className="text-3xl font-black text-white tracking-wider">TABLEAU DE <span className="text-cyan-400">BORD</span></h1>
|
|
<p className="text-gray-400 mt-2">Gestion financière et accréditations de vos infrastructures.</p>
|
|
</header>
|
|
|
|
{isLoading && (
|
|
<div className="flex items-center space-x-3 text-cyan-400">
|
|
<Loader className="w-6 h-6 animate-spin" />
|
|
<span>Synchronisation avec le registre comptable...</span>
|
|
</div>
|
|
)}
|
|
|
|
{error && (
|
|
<div className="flex items-center space-x-3 text-red-400 bg-red-400/10 border border-red-400 p-4 rounded-lg">
|
|
<AlertCircle className="w-6 h-6" />
|
|
<span>{error}</span>
|
|
</div>
|
|
)}
|
|
|
|
{!isLoading && !error && (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
|
{orders.map((order) => (
|
|
<DashboardServiceCard
|
|
key={order.id}
|
|
order={order}
|
|
onClick={() => handleManageSubscription(order)}
|
|
/>
|
|
))}
|
|
<NewServiceCard onClick={() => navigate('/store')} />
|
|
</div>
|
|
)}
|
|
|
|
{/* 🌟 LA MODALE DE GESTION D'ABONNEMENT */}
|
|
{activeSubscriptionModal && (
|
|
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
|
<div className="bg-gray-900 border border-cyan-500/50 shadow-2xl shadow-cyan-500/10 rounded-lg max-w-xxl w-full p-6 text-gray-200">
|
|
<div className="flex justify-between items-center mb-6 border-b border-gray-800 pb-4">
|
|
<h3 className="text-xl font-bold text-white tracking-wider flex items-center gap-3">
|
|
<FileText className="w-6 h-6 text-cyan-400" />
|
|
GESTION DE L'ABONNEMENT
|
|
</h3>
|
|
<button onClick={() => setActiveSubscriptionModal(null)} className="p-2 text-gray-500 hover:text-white bg-gray-900 hover:bg-gray-800 rounded-lg transition-colors">
|
|
<X className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
|
|
<WebServiceSubscriptionManager
|
|
order={activeSubscriptionModal}
|
|
onClose={() => setActiveSubscriptionModal(null)}
|
|
onRefresh={fetchInventory}
|
|
onAlert={triggerAlert}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<NotificationModal notification={customAlert} onClose={() => setCustomAlert(null)} />
|
|
</div>
|
|
);
|
|
} |