Nous contacter
Une question ? Besoin d’un renseignement ?
import React, { useState, useEffect } from 'react'; import { PieChart, Pie, Cell, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { Leaf, Recycle, TreeDeciduous, Users, Download, Share2, LogOut, LayoutDashboard, History, User, Building2, Database, Wand2, Copy, CheckCircle2, Award, Lock, Mail, ArrowRight, ShieldCheck, Calendar, FileSpreadsheet, ArrowUpRight, Filter, Clock } from 'lucide-react'; const clientDatabase = { "acme": { id: "acme", name: "Acme Corp", email: "contact@acme-logistique.fr", sector: "Industrie & Logistique", serviceData: [ { name: 'Recyclage papier', value: 60, color: '#56b954' }, { name: 'Recyclage carton', value: 30, color: '#004924' }, { name: 'Destruction confidentielle', value: 10, color: '#e8d3bd' } ], monthlyData: [ { name: 'Mars', volume: 1.2 }, { name: 'Avril', volume: 1.5 }, { name: 'Mai', volume: 2.1 }, { name: 'Juin', volume: 1.8 }, { name: 'Juillet', volume: 2.4 }, { name: 'Août', volume: 2.7 } ], historyLogs: [ { id: "LOG-9021", date: "24/08/2026", type: "Collecte Carton & Papier", volume: "2.7 Tonnes", rawVolume: 2.7, co2: "45 kg", insertionHours: "22h", agent: "Équipe Rennes Nord", status: "Validé" }, { id: "LOG-8843", date: "15/07/2026", type: "Destruction Confidentielle", volume: "0.8 Tonnes", rawVolume: 0.8, co2: "15 kg", insertionHours: "10h", agent: "Équipe Spécialisée LFE", status: "Validé" }, { id: "LOG-8612", date: "02/06/2026", type: "Collecte Papiers de Bureau", volume: "1.8 Tonnes", rawVolume: 1.8, co2: "30 kg", insertionHours: "15h", agent: "Équipe Centre", status: "Validé" }, { id: "LOG-8304", date: "19/05/2026", type: "Collecte Carton Global", volume: "2.1 Tonnes", rawVolume: 2.1, co2: "35 kg", insertionHours: "18h", agent: "Équipe Rennes Nord", status: "Validé" }, { id: "LOG-8109", date: "10/04/2026", type: "Collecte Papier & Carton", volume: "1.5 Tonnes", rawVolume: 1.5, co2: "25 kg", insertionHours: "12h", agent: "Équipe Ouest", status: "Validé" }, { id: "LOG-7920", date: "05/03/2026", type: "Destruction d'archives", volume: "1.2 Tonnes", rawVolume: 1.2, co2: "20 kg", insertionHours: "10h", agent: "Équipe Spécialisée LFE", status: "Validé" } ], metrics: { volume: "14,5", volumeUnit: "Tonnes", volumeSub: "Papiers et/ou cartons", co2: "250", co2Unit: "kg", co2Sub: "d'équivalent CO₂ évités", social: "120", socialUnit: "heures", socialSub: "de travail générées pour des salariés en parcours d'insertion" } }, "bretagne_tech": { id: "bretagne_tech", name: "Bretagne Tech & Co", email: "rse@bretagnetech.io", sector: "Services Numériques", serviceData: [ { name: 'Recyclage papier', value: 75, color: '#56b954' }, { name: 'Recyclage carton', value: 15, color: '#004924' }, { name: 'Destruction confidentielle', value: 10, color: '#e8d3bd' } ], monthlyData: [ { name: 'Mars', volume: 0.8 }, { name: 'Avril', volume: 1.0 }, { name: 'Mai', volume: 1.4 }, { name: 'Juin', volume: 1.3 }, { name: 'Juillet', volume: 1.9 }, { name: 'Août', volume: 2.2 } ], historyLogs: [ { id: "LOG-9012", date: "22/08/2026", type: "Collecte Papiers Administratifs", volume: "2.2 Tonnes", rawVolume: 2.2, co2: "40 kg", insertionHours: "18h", agent: "Équipe Rennes Centre", status: "Validé" }, { id: "LOG-8810", date: "12/07/2026", type: "Collecte Papiers & Cartons", volume: "1.9 Tonnes", rawVolume: 1.9, co2: "35 kg", insertionHours: "16h", agent: "Équipe Rennes Centre", status: "Validé" }, { id: "LOG-8555", date: "28/06/2026", type: "Destruction Sécurisée DSI", volume: "1.3 Tonnes", rawVolume: 1.3, co2: "25 kg", insertionHours: "12h", agent: "Équipe Spécialisée", status: "Validé" }, { id: "LOG-8240", date: "14/05/2026", type: "Collecte Papiers de Bureau", volume: "1.4 Tonnes", rawVolume: 1.4, co2: "25 kg", insertionHours: "12h", agent: "Équipe Rennes Centre", status: "Validé" }, { id: "LOG-8011", date: "03/04/2026", type: "Collecte Papiers Administratifs", volume: "1.0 Tonnes", rawVolume: 1.0, co2: "18 kg", insertionHours: "9h", agent: "Équipe Ouest", status: "Validé" }, { id: "LOG-7850", date: "10/03/2026", type: "Collecte Bureautique", volume: "0.8 Tonnes", rawVolume: 0.8, co2: "15 kg", insertionHours: "8h", agent: "Équipe Ouest", status: "Validé" } ], metrics: { volume: "8,6", volumeUnit: "Tonnes", volumeSub: "Papiers administratifs", co2: "160", co2Unit: "kg", co2Sub: "d'équivalent CO₂ évités", social: "75", socialUnit: "heures", socialSub: "de travail générées pour des salariés en parcours d'insertion" } }, "armor_logistique": { id: "armor_logistique", name: "Armor Logistique", email: "logistique@armor-trans.fr", sector: "Transport & Supply Chain", serviceData: [ { name: 'Recyclage papier', value: 20, color: '#56b954' }, { name: 'Recyclage carton', value: 70, color: '#004924' }, { name: 'Destruction confidentielle', value: 10, color: '#e8d3bd' } ], monthlyData: [ { name: 'Mars', volume: 3.5 }, { name: 'Avril', volume: 4.1 }, { name: 'Mai', volume: 3.9 }, { name: 'Juin', volume: 4.5 }, { name: 'Juillet', volume: 5.2 }, { name: 'Août', volume: 6.0 } ], historyLogs: [ { id: "LOG-9050", date: "25/08/2026", type: "Collecte Massive Cartons", volume: "6.0 Tonnes", rawVolume: 6.0, co2: "100 kg", insertionHours: "45h", agent: "Équipe Logistique Sud", status: "Validé" }, { id: "LOG-8890", date: "18/07/2026", type: "Collecte Cartons Entrepôt", volume: "5.2 Tonnes", rawVolume: 5.2, co2: "90 kg", insertionHours: "40h", agent: "Équipe Logistique Sud", status: "Validé" }, { id: "LOG-8600", date: "30/06/2026", type: "Tri et Conditionnement", volume: "4.5 Tonnes", rawVolume: 4.5, co2: "80 kg", insertionHours: "35h", agent: "Équipe Centre", status: "Validé" }, { id: "LOG-8310", date: "12/05/2026", type: "Collecte Emballages", volume: "3.9 Tonnes", rawVolume: 3.9, co2: "70 kg", insertionHours: "30h", agent: "Équipe Logistique Sud", status: "Validé" }, { id: "LOG-8050", date: "20/04/2026", type: "Collecte Cartons Standard", volume: "4.1 Tonnes", rawVolume: 4.1, co2: "75 kg", insertionHours: "32h", agent: "Équipe Logistique Sud", status: "Validé" }, { id: "LOG-7800", date: "05/03/2026", type: "Collecte Entrepôt", volume: "3.5 Tonnes", rawVolume: 3.5, co2: "65 kg", insertionHours: "28h", agent: "Équipe Logistique Sud", status: "Validé" } ], metrics: { volume: "27,2", volumeUnit: "Tonnes", volumeSub: "Cartons d'emballage", co2: "480", co2Unit: "kg", co2Sub: "d'équivalent CO₂ évités", social: "210", socialUnit: "heures", socialSub: "de travail générées pour des salariés en parcours d'insertion" } } }; export default function App() { const [isAuthenticated, setIsAuthenticated] = useState(false); const [selectedClientId, setSelectedClientId] = useState("acme"); const [clientData, setClientData] = useState(clientDatabase["acme"]); const [activeTab, setActiveTab] = useState("dashboard"); const [timeRange, setTimeRange] = useState("1y"); const [loginEmail, setLoginEmail] = useState("contact@acme-logistique.fr"); const [loginPassword, setLoginPassword] = useState("********"); const [loginError, setLoginError] = useState(""); const [isLoggingIn, setIsLoggingIn] = useState(false); const [isLoaded, setIsLoaded] = useState(false); const [isGeneratingPost, setIsGeneratingPost] = useState(false); const [postContent, setPostContent] = useState(''); const [postCopied, setPostCopied] = useState(false); const [isGeneratingInsight, setIsGeneratingInsight] = useState(false); const [insightContent, setInsightContent] = useState(''); const getFilteredData = () => { if (!clientData) return clientData; let multiplier = 1; let filteredMonths = [...clientData.monthlyData]; let filteredLogs = [...clientData.historyLogs]; if (timeRange === "1w") { multiplier = 0.08; filteredMonths = filteredMonths.slice(-1); filteredLogs = filteredLogs.slice(0, 1); } else if (timeRange === "1m") { multiplier = 0.25; filteredMonths = filteredMonths.slice(-1); filteredLogs = filteredLogs.slice(0, 2); } else if (timeRange === "1q") { multiplier = 0.5; filteredMonths = filteredMonths.slice(-3); filteredLogs = filteredLogs.slice(0, 3); } else { multiplier = 1; } const baseVol = parseFloat(clientData.metrics.volume.replace(',', '.')); const filteredVol = (baseVol * multiplier).toFixed(1).replace('.', ','); const filteredCo2 = Math.round(parseInt(clientData.metrics.co2) * multiplier); const filteredSocial = Math.round(parseInt(clientData.metrics.social) * multiplier); return { ...clientData, monthlyData: filteredMonths, historyLogs: filteredLogs, metrics: { ...clientData.metrics, volume: filteredVol, co2: filteredCo2.toString(), social: filteredSocial.toString() } }; }; const currentFilteredData = getFilteredData(); const handleLogin = (e) => { e.preventDefault(); setLoginError(""); setIsLoggingIn(true); setTimeout(() => { const foundEntry = Object.entries(clientDatabase).find( ([_, data]) => data.email.toLowerCase() === loginEmail.toLowerCase().trim() ); if (foundEntry) { const [clientId, data] = foundEntry; setSelectedClientId(clientId); setClientData(data); setIsAuthenticated(true); setIsLoaded(true); setActiveTab("dashboard"); } else { setLoginError("Identifiants non reconnus. Essayez avec un email de démonstration (ex: contact@acme-logistique.fr)"); } setIsLoggingIn(false); }, 800); }; const handleDemoLogin = (clientId) => { const data = clientDatabase[clientId]; setLoginEmail(data.email); setSelectedClientId(clientId); setClientData(data); setIsAuthenticated(true); setIsLoaded(true); setActiveTab("dashboard"); }; const handleLogout = () => { setIsAuthenticated(false); setIsLoaded(false); setPostContent(''); setActiveTab("dashboard"); }; useEffect(() => { if (isAuthenticated && isLoaded && activeTab === "dashboard") { generateInsights(currentFilteredData); } }, [isAuthenticated, clientData, activeTab]); const generateInsights = async (currentClient) => { setIsGeneratingInsight(true); try { const summaryMonths = currentClient.monthlyData.map(m => `${m.name}: ${m.volume}T`).join(', '); const prompt = `Tu es un expert data spécialisé en environnement. Voici les données de recyclage de l'entreprise ${currentClient.name} (${currentClient.sector}) : ${summaryMonths}. Analyse brièvement cette tendance en 2 phrases maximum, de manière très encourageante et professionnelle, pour un tableau de bord B2B de 'La Feuille d'Érable'.`; const payload = { contents: [{ parts: [{ text: prompt }] }] }; const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-3-flash-preview:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates?.[0]?.content?.parts?.[0]?.text) { setInsightContent(result.candidates[0].content.parts[0].text); } } catch (e) { console.error(e); setInsightContent(`Félicitations à ${currentClient.name} pour votre engagement continu !`); } finally { setIsGeneratingInsight(false); } }; const generateLinkedInPost = async () => { setIsGeneratingPost(true); setPostContent(''); try { const prompt = `Agis comme un Community Manager expert en communication RSE. Rédige un post LinkedIn engageant et professionnel pour l'entreprise '${currentFilteredData.name}' qui est fière d'être partenaire de 'La Feuille d'Érable'. Utilise ces données d'impact : ${currentFilteredData.metrics.volume} tonnes de matières recyclées, ${currentFilteredData.metrics.co2} kg d'équivalent CO2 évités, et ${currentFilteredData.metrics.social} heures de travail d'insertion générées. Ton enthousiaste avec émojis et hashtags pertinents.`; const payload = { contents: [{ parts: [{ text: prompt }] }] }; const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-3-flash-preview:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates?.[0]?.content?.parts?.[0]?.text) { setPostContent(result.candidates[0].content.parts[0].text); } } catch (e) { console.error(e); setPostContent("Erreur de connexion à l'assistant IA."); } finally { setIsGeneratingPost(false); } }; const copyToClipboard = () => { navigator.clipboard.writeText(postContent); setPostCopied(true); setTimeout(() => setPostCopied(false), 2000); }; const getAnimationClass = (delay) => { return `transition-all duration-700 ease-out transform ${ isLoaded ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8' } ${delay}`; }; if (!isAuthenticated) { return (
Connectez-vous pour accéder à vos indicateurs d'impact RSE personnalisés
Comptes de démonstration disponibles :
Voici votre impact global grâce à votre partenariat avec La Feuille d'Érable. {clientData.sector}
{currentFilteredData.metrics.volumeSub}
{currentFilteredData.metrics.co2Sub}
{currentFilteredData.metrics.socialSub}
{insightContent}
)}La communication RSE est essentielle. Exportez vos résultats personnalisés en un clic pour les partager avec vos équipes, vos clients ou sur vos réseaux sociaux professionnels.
{postContent}
{clientData.name} x LFE
Sélectionnez ci-dessous une période pour filtrer instantanément vos données d'impact et consulter le journal détaillé des interventions pour {clientData.name}.
Dernière intervention & flux récents
{timeRange === '1w' && }Bilan des 30 derniers jours
{timeRange === '1m' && }3 derniers mois d'activité
{timeRange === '1q' && }Bilan complet des 12 derniers mois
{timeRange === '1y' && }{currentFilteredData.historyLogs.length} collectes
Filtre actif : {timeRange === '1w' ? '1 Semaine' : timeRange === '1m' ? '1 Mois' : timeRange === '1q' ? '1 Trimestre' : '1 An'}{currentFilteredData.metrics.volume} {currentFilteredData.metrics.volumeUnit}
Conforme aux objectifs RSE{currentFilteredData.metrics.social} heures
Validation sociale certifiée| ID Opération | Date | Type de service / Flux | Volume | CO2 Évité | Insertion | Équipe LFE | Statut |
|---|---|---|---|---|---|---|---|
| {log.id} | {log.date} | {log.type} | {log.volume} | {log.co2} | {log.insertionHours} | {log.agent} |
|
Informations relatives à votre structure et paramètres de connexion au Club LFE.
{clientData.sector} • Partenaire certifié La Feuille d'Érable
Nettoyage écoresponsable d’entretien courant des locaux professionnels à Rennes.
Entreprise d’insertion spécialisée dans le nettoyage écologique. Nous accompagnons les entreprises, collectivités, syndics et structures éducatives dans l’entretien durable de leurs locaux à Rennes et dans le département d’Ille-et-Vilaine.
Nos prestations couvrent toutes les étapes du nettoyage professionnel, du diagnostic propreté aux services sur-mesure qui en découlent.
Diagnostic propreté
Le diagnostic propreté permet de comprendre votre organisation quotidienne et d'adapter nos interventions à la vie de votre structure. Il détaille nos préconisations et les scénarios envisageables.Travaux spéciaux
La rénovation, la remise en état après chantier, sont des techniques qui consistent à nettoyer un local en profondeur pour lui redonner son aspect d’origine.Service qualité
Auclair garantit la qualité du nettoyage courant de vos locaux avec des produits naturels et/ou écolabellisés.Nettoyage des vitres
Le nettoyage des vitres nécessite un véritable savoir-faire. Nos laveurs de vitres interviennent rapidement et en toute discrétion.Spécialiste du nettoyage écologique, Auclair intervient dans différents secteurs professionnels sur Rennes et le département d’Ille-et-Vilaine.
Bureaux et locaux professionnels
Copropriétés et espaces communs
Administration et collectivité
Établissements scolaires et publics
Fin de chantier et évenementiel
Auclair a mis en place une démarche RSE plaçant l’humain et l’environnement au centre de son action :
Rejoignez notre réseau professionnel
Nos dernières actualités !