add dashboard, home, login, layout, api
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getClientProfile, getClientOrders, getOrderService } from '../../services/api';
|
||||
|
||||
export default function Dashboard() {
|
||||
const [profile, setProfile] = useState(null);
|
||||
const [orders, setOrders] = useState([]);
|
||||
const [error, setError] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchDashboardData = async () => {
|
||||
try {
|
||||
// On lance les deux requêtes en même temps pour aller plus vite
|
||||
const profileData = await getClientProfile();
|
||||
const ordersData = await getClientOrders();
|
||||
|
||||
setProfile(profileData);
|
||||
// FOSSBilling renvoie une liste paginée, on prend le tableau 'list'
|
||||
setOrders(ordersData.list || []);
|
||||
} catch (err) {
|
||||
setError(err.message || "Erreur de synchronisation avec le serveur central.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchDashboardData();
|
||||
}, []);
|
||||
|
||||
const cardStyle = {
|
||||
backgroundColor: '#1A1A1A',
|
||||
border: '1px solid #333',
|
||||
padding: '20px',
|
||||
borderRadius: '4px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '10px'
|
||||
};
|
||||
|
||||
const handleManageInstance = async (orderId) => {
|
||||
try {
|
||||
console.log(`[SYS] Demande d'accès au service #${orderId}...`);
|
||||
const serviceData = await getOrderService(orderId);
|
||||
|
||||
if (serviceData && serviceData.server && serviceData.server.login_url) {
|
||||
window.open(serviceData.server.login_url, '_blank');
|
||||
}
|
||||
else if (serviceData && serviceData.server) {
|
||||
// L'URL d'action du formulaire de connexion HestiaCP
|
||||
const hestiaLoginUrl = "https://panel.gise.be/login/";
|
||||
const username = serviceData.username;
|
||||
const password = serviceData.password;
|
||||
|
||||
if (!username || !password) {
|
||||
alert("Identifiants introuvables. Le serveur est-il bien provisionné ?");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[SYS] Création du pont SSO vers HestiaCP...");
|
||||
|
||||
// 1. On crée un formulaire invisible
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = hestiaLoginUrl;
|
||||
form.target = '_blank'; // Pour ouvrir dans un nouvel onglet
|
||||
|
||||
// 2. On crée le champ utilisateur (Hestia attend le nom 'user')
|
||||
const userField = document.createElement('input');
|
||||
userField.type = 'hidden';
|
||||
userField.name = 'user';
|
||||
userField.value = username;
|
||||
|
||||
// 3. On crée le champ mot de passe (Hestia attend le nom 'password')
|
||||
const passField = document.createElement('input');
|
||||
passField.type = 'hidden';
|
||||
passField.name = 'password';
|
||||
passField.value = password;
|
||||
|
||||
// 4. On assemble et on injecte dans la page
|
||||
form.appendChild(userField);
|
||||
form.appendChild(passField);
|
||||
document.body.appendChild(form);
|
||||
|
||||
// 5. On valide le formulaire (BAM ! Connexion)
|
||||
form.submit();
|
||||
|
||||
// 6. On efface les traces du formulaire fantôme pour la sécurité
|
||||
document.body.removeChild(form);
|
||||
|
||||
} else {
|
||||
alert("Configuration serveur introuvable pour cette instance.");
|
||||
}
|
||||
} catch (err) {
|
||||
alert(`[ERREUR D'ACCÈS] : ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '40px', color: '#E0E0E0', fontFamily: 'monospace', backgroundColor: '#121212', minHeight: '100vh' }}>
|
||||
|
||||
{/* HEADER DU DASHBOARD */}
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: '1px solid #333', paddingBottom: '20px', marginBottom: '30px' }}>
|
||||
<h2 style={{ color: '#00E5FF', margin: 0 }}>CENTRE DE CONTRÔLE GISE</h2>
|
||||
{profile && (
|
||||
<div style={{ textAlign: 'right' }}>
|
||||
<div>Opérateur : <span style={{ color: '#FFF' }}>{profile.email}</span></div>
|
||||
<div>Crédits : <span style={{ color: '#00FF00' }}>{profile.balance} {profile.currency}</span></div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{loading && <p style={{ color: '#888' }}>[ Synchronisation des données en cours... ]</p>}
|
||||
|
||||
{error && (
|
||||
<div style={{ backgroundColor: 'rgba(255, 68, 68, 0.1)', color: '#FF4444', padding: '15px', border: '1px solid #FF4444', marginBottom: '20px' }}>
|
||||
[ ERREUR ] : {error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ZONE DES SERVICES ACTIFS */}
|
||||
{!loading && !error && (
|
||||
<>
|
||||
<h3 style={{ color: '#FFF', marginBottom: '20px' }}>INFRASTRUCTURE ACTIVE</h3>
|
||||
|
||||
{orders.length === 0 ? (
|
||||
<div style={{ padding: '30px', textAlign: 'center', border: '1px dashed #333', color: '#888' }}>
|
||||
Aucun service actif détecté. <br/><br/>
|
||||
<button style={{ backgroundColor: '#00E5FF', color: '#000', border: 'none', padding: '10px 20px', cursor: 'pointer', fontFamily: 'monospace', fontWeight: 'bold' }}>
|
||||
+ DÉPLOYER UN NOUVEAU SERVICE
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: '20px' }}>
|
||||
{orders.map((order) => (
|
||||
<div key={order.id} style={cardStyle}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<strong style={{ color: '#FFF', fontSize: '1.1rem' }}>{order.title}</strong>
|
||||
<span style={{
|
||||
color: order.status === 'active' ? '#00FF00' : '#FF4444',
|
||||
fontSize: '0.8rem', textTransform: 'uppercase', border: `1px solid ${order.status === 'active' ? '#00FF00' : '#FF4444'}`, padding: '2px 6px'
|
||||
}}>
|
||||
{order.status}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ fontSize: '0.9rem', color: '#A0A0A0' }}>Renouvellement : {order.expires_at || 'N/A'}</div>
|
||||
<div style={{ fontSize: '0.9rem', color: '#A0A0A0' }}>Montant : {order.total} {order.currency}</div>
|
||||
|
||||
<button
|
||||
onClick={() => handleManageInstance(order.id)}
|
||||
style={{ marginTop: '10px', backgroundColor: 'transparent', color: '#00E5FF', border: '1px solid #00E5FF', padding: '8px', cursor: 'pointer', fontFamily: 'monospace' }}>
|
||||
GÉRER L'INSTANCE
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user