rebuild api fossbilling
This commit is contained in:
+95
-45
@@ -1,11 +1,13 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { getClientOrders } from '../../services/api';
|
||||
import { AlertCircle, Loader } from 'lucide-react';
|
||||
import { AlertCircle, Loader, FileText, X } from 'lucide-react';
|
||||
|
||||
// Importation des composants isolés
|
||||
// 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();
|
||||
@@ -13,54 +15,82 @@ export default function Dashboard() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
// Chargement des données à l'ouverture du Sas
|
||||
useEffect(() => {
|
||||
const fetchInventory = async () => {
|
||||
try {
|
||||
const data = await getClientOrders();
|
||||
|
||||
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 [activeSubscriptionModal, setActiveSubscriptionModal] = useState(null);
|
||||
const [customAlert, setCustomAlert] = useState(null);
|
||||
|
||||
const isGhostProduct =
|
||||
type === 'domain' ||
|
||||
title.startsWith('domain ') ||
|
||||
title.startsWith('domaine ') ||
|
||||
title.startsWith('enregistrement ');
|
||||
|
||||
return !isGhostProduct;
|
||||
});
|
||||
const triggerAlert = (title, message, type = "info") => setCustomAlert({ title, message, type });
|
||||
|
||||
setOrders(filteredOrders);
|
||||
} else {
|
||||
setOrders([]);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err.message || "Impossible de récupérer la télémétrie des services.");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
const fetchInventory = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const data = await getClientOrders();
|
||||
|
||||
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">
|
||||
|
||||
<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">Aperçu de vos accréditations réseau et infrastructures.</p>
|
||||
<p className="text-gray-400 mt-2">Gestion financière et accréditations de vos infrastructures.</p>
|
||||
</header>
|
||||
|
||||
{/* GESTION DES ERREURS & CHARGEMENT */}
|
||||
{isLoading && (
|
||||
<div className="flex items-center space-x-3 text-cyan-400">
|
||||
<Loader className="w-6 h-6 animate-spin" />
|
||||
<span>Synchronisation avec l'orchestrateur en cours...</span>
|
||||
<span>Synchronisation avec le registre comptable...</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -71,24 +101,44 @@ export default function Dashboard() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* GRILLE DES SERVICES */}
|
||||
{!isLoading && !error && (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
|
||||
{/* Boucle sur les composants isolés */}
|
||||
{orders.map((order) => (
|
||||
<DashboardServiceCard
|
||||
key={order.id}
|
||||
order={order}
|
||||
onClick={() => navigate(`/services/${order.id}`)}
|
||||
<DashboardServiceCard
|
||||
key={order.id}
|
||||
order={order}
|
||||
onClick={() => handleManageSubscription(order)}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Le composant carte d'ajout */}
|
||||
<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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user