Files
ludikevent_crm/templates/root/console.twig
Serreau Jovann 4c14932fee ```
 feat(Devis.php): Ajoute adresses de facturation et de livraison au devis.

🔒️ fix(IntranetLocked.php): Autorise l'accès à la route st_control en mode debug.

 feat(CustomerAddress.php): Gère les adresses de facturation et livraison.

 feat: Ajoute la console superadmin pour le contrôle système.

 feat(DevisController.php): Supprime la génération PDF temporaire.

 feat(st_control.js): Ajoute la logique de contrôle système via JS.

 feat: Crée les templates CGV, Cookies, Hébergement et RGPD.

🎨 style(app.scss): Ajoute un style de fond pour la console.

 feat: Ajoute le template pour les informations d'hébergement.

 feat: Crée un template de mail d'alerte pour les accès root.

 feat: Crée le template RGPD (données personnelles).

🐛 fix(ErrorListener.php): Gère les erreurs 404 en prod (JSON/HTML).

 feat: Ajoute les mentions légales.

 feat(DevisPdfService.php): Améliore la génération PDF du devis.

 feat(admin.js): Charge dynamiquement les produits dans le select.

 feat(add.twig): Ajoute un sélecteur de produit et d'autres champs.

 chore(config): Ajoute INTRANET_LOCK à l'env.
```
2026-01-19 13:52:41 +01:00

160 lines
11 KiB
Twig

{% extends 'base.twig' %}
{% block title %}Console SuperAdmin - SiteConseil{% endblock %}
{% block body %}
<div class="min-h-screen bg-console font-mono text-slate-300">
{# --- BARRE ROOT CONSOLE v1.0 --- #}
<div class="bg-slate-900 border-b-2 border-red-700 px-6 py-4 shadow-2xl">
<div class="flex flex-col md:flex-row md:justify-between md:items-center gap-4">
<div class="flex flex-col">
<h1 class="text-white font-black text-2xl tracking-tighter uppercase leading-none">
Root Console <span class="text-red-600">v1.0</span>
</h1>
<span class="text-[11px] text-slate-400 font-bold uppercase tracking-[0.3em] mt-1">
Siteconseil Privileged Access
</span>
</div>
<div class="flex items-center gap-6">
<div class="hidden sm:flex items-center gap-2 border border-green-500/50 bg-green-500/10 px-3 py-1 rounded shadow-[0_0_15px_rgba(34,197,94,0.2)]">
<span class="h-2 w-2 bg-green-500 rounded-full animate-ping"></span>
<span class="text-[10px] text-green-500 font-black uppercase tracking-widest">Access Granted</span>
</div>
<div class="flex items-center gap-3 bg-black/30 px-4 py-2 rounded border border-slate-800">
<div class="flex flex-col items-end">
<span class="text-[9px] text-slate-500 uppercase font-bold tracking-widest">Operator IP</span>
<span class="text-sm text-green-500 font-bold tracking-widest">
{{ app.request.headers.get('cf-connecting-ip') ?? app.request.clientIp }}
</span>
</div>
</div>
</div>
</div>
</div>
{# --- BODY DOUBLE COLONNE --- #}
<div class="flex flex-col lg:flex-row h-[calc(100vh-84px)] overflow-hidden">
{# COLONNE GAUCHE #}
<div class="w-full lg:w-2/3 p-8 border-r border-slate-800 overflow-y-auto bg-slate-900/10">
{# BLOCK : SERVICE HEALTH #}
<div class="mb-12">
<h2 class="text-xs font-bold text-slate-500 uppercase tracking-widest mb-6 flex items-center gap-2">
<span class="w-2 h-2 bg-green-500 rounded-full"></span>
External Service Health
</h2>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
{# Stripe #}
<div class="bg-black/40 border border-slate-800 p-4 rounded flex items-center justify-between group">
<span class="text-xs font-bold text-slate-400 group-hover:text-indigo-400">STRIPE API</span>
<div class="flex items-center gap-2">
<span class="text-[10px] font-bold uppercase {{ stripeStatus == 1 ? 'text-green-500' : 'text-red-500 animate-pulse' }}">
{{ stripeStatus == 1 ? 'Online' : 'Offline' }}
</span>
<div class="w-1.5 h-1.5 rounded-full {{ stripeStatus == 1 ? 'bg-green-500' : 'bg-red-500' }}"></div>
</div>
</div>
{# Signature #}
<div class="bg-black/40 border border-slate-800 p-4 rounded flex items-center justify-between group">
<span class="text-xs font-bold text-slate-400 group-hover:text-blue-400">SIGNATURE</span>
<div class="flex items-center gap-2">
<span class="text-[10px] font-bold uppercase {{ signatureStatus == 1 ? 'text-green-500' : 'text-red-500 animate-pulse' }}">
{{ signatureStatus == 1 ? 'Online' : 'Offline' }}
</span>
<div class="w-1.5 h-1.5 rounded-full {{ signatureStatus == 1 ? 'bg-green-500' : 'bg-red-500' }}"></div>
</div>
</div>
{# Esysearch #}
<div class="bg-black/40 border border-slate-800 p-4 rounded flex items-center justify-between group">
<span class="text-xs font-bold text-slate-400 group-hover:text-orange-400">ESYSEARCH</span>
<div class="flex items-center gap-2">
<span class="text-[10px] font-bold uppercase {{ searchClient == 1 ? 'text-green-500' : 'text-red-500 animate-pulse' }}">
{{ searchClient == 1 ? 'Online' : 'Offline' }}
</span>
<div class="w-1.5 h-1.5 rounded-full {{ searchClient == 1 ? 'bg-green-500' : 'bg-red-500' }}"></div>
</div>
</div>
</div>
</div>
{# BLOCK : CRITICAL COMMANDS #}
<div class="mb-12">
<h2 class="text-xs font-bold text-slate-500 uppercase tracking-widest mb-6 flex items-center gap-2">
<span class="w-2 h-2 bg-red-600 rounded-full"></span>
Critical Command Center
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-red-950/20 border border-red-900/50 p-6 rounded-lg group hover:bg-red-900/30 transition-all shadow-lg text-center">
<h3 class="text-red-500 font-bold uppercase text-sm mb-4">Maintenance Mode</h3>
<button id="btn-suspend" class="w-full bg-red-700 hover:bg-red-600 text-white font-black py-3 rounded uppercase text-[11px] tracking-[0.2em] active:scale-95 transition-transform">Suspendre l'accès</button>
</div>
<div class="bg-green-950/20 border border-green-900/50 p-6 rounded-lg group hover:bg-green-900/30 transition-all shadow-lg text-center">
<h3 class="text-green-500 font-bold uppercase text-sm mb-4">Live Mode</h3>
<button id="btn-enable" class="w-full bg-green-700 hover:bg-green-600 text-white font-black py-3 rounded uppercase text-[11px] tracking-[0.2em] active:scale-95 transition-transform">Réactiver l'accès</button>
</div>
</div>
</div>
{# BLOCK : OPTIMIZATION #}
<div class="mb-8">
<h2 class="text-xs font-bold text-slate-500 uppercase tracking-widest mb-6 flex items-center gap-2">
<span class="w-2 h-2 bg-blue-600 rounded-full"></span>
System Optimization
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-slate-900/40 border border-slate-800 p-6 rounded-lg group hover:border-blue-900/50 transition-all">
<h3 class="text-blue-500 font-bold uppercase text-sm mb-4 font-mono">cache:clear</h3>
<button id="btn-cache" class="w-full bg-slate-800 hover:bg-blue-700 text-white font-bold py-2 rounded uppercase text-[10px] tracking-widest">Run Command</button>
</div>
<div class="bg-slate-900/40 border border-slate-800 p-6 rounded-lg group hover:border-purple-900/50 transition-all">
<h3 class="text-purple-500 font-bold uppercase text-sm mb-4 font-mono">liip:cache:clear</h3>
<button id="btn-liip" class="w-full bg-slate-800 hover:bg-purple-700 text-white font-bold py-2 rounded uppercase text-[10px] tracking-widest">Run Command</button>
</div>
</div>
</div>
</div>
{# --- COLONNE DROITE : LE TERMINAL --- #}
<div class="w-full lg:w-1/3 bg-black p-0 flex flex-col h-full shadow-inner border-l border-slate-800">
<div class="bg-slate-800/50 px-4 py-2 flex items-center justify-between border-b border-slate-700">
<div class="flex gap-1.5">
<div class="w-2.5 h-2.5 rounded-full bg-red-500/20 border border-red-500/50"></div>
<div class="w-2.5 h-2.5 rounded-full bg-yellow-500/20 border border-yellow-500/50"></div>
<div class="w-2.5 h-2.5 rounded-full bg-green-500/20 border border-green-500/50"></div>
</div>
<span class="text-[10px] uppercase text-slate-500 font-bold tracking-widest">Live System Logs</span>
</div>
<div id="terminal-logs" class="p-6 font-mono text-[11px] leading-relaxed overflow-y-auto h-full space-y-1 scrollbar-thin scrollbar-thumb-slate-800">
<p class="text-slate-600">[{{ "now"|date('H:i:s') }}] INITIALIZING ROOT INTERFACE...</p>
<p class="text-slate-600">[{{ "now"|date('H:i:s') }}] SESSION_USER: <span class="text-white">SITECONSEIL_ADMIN</span></p>
<p class="text-slate-600">[{{ "now"|date('H:i:s') }}] DOMAIN_VALIDATION: <span class="text-green-500 font-bold">SUCCESSFUL</span></p>
<p class="text-slate-600">[{{ "now"|date('H:i:s') }}] IP_OPERATOR_VAL: <span class="text-green-500 font-bold">SUCCESSFUL</span></p>
<p class="text-slate-600">[{{ "now"|date('H:i:s') }}] SECRET_KEY_VAL: <span class="text-green-500 font-bold">SUCCESSFUL</span></p>
{# Statuts des services en 1/0 #}
<p class="text-slate-600">[{{ "now"|date('H:i:s') }}] STRIPE_VAL: <span class="{{ stripeStatus == 1 ? 'text-green-500' : 'text-red-500' }} font-bold">{{ stripeStatus == 1 ? 'ONLINE' : 'OFFLINE' }}</span></p>
<p class="text-slate-600">[{{ "now"|date('H:i:s') }}] SIGNATURE_VAL: <span class="{{ signatureStatus == 1 ? 'text-green-500' : 'text-red-500' }} font-bold">{{ signatureStatus == 1 ? 'ONLINE' : 'OFFLINE' }}</span></p>
<p class="text-slate-600">[{{ "now"|date('H:i:s') }}] ESYSEARCH_VAL: <span class="{{ searchClient == 1 ? 'text-green-500' : 'text-red-500' }} font-bold">{{ searchClient == 1 ? 'ONLINE' : 'OFFLINE' }}</span></p>
<div class="py-3">
<p class="text-green-400 font-bold bg-green-500/10 px-3 py-1.5 border-l-2 border-green-500 uppercase tracking-tighter">
*** Access granted to system core ***
</p>
</div>
<div id="dynamic-logs" class="space-y-1"></div>
<p class="text-white mt-4">> <span class="animate-pulse">_</span></p>
</div>
</div>
</div>
</div>
<script nonce="{{ csp_nonce('script') }}" src="/st_control.js"></script>
{% endblock %}