From 14897e198c97872f6d5ea436f342e25afc47ce4c Mon Sep 17 00:00:00 2001 From: sebvtl728 Date: Sun, 19 Jan 2025 01:27:01 +0100 Subject: [PATCH] backTime-modif majeur --- .DS_Store | Bin 6148 -> 6148 bytes frontend/.gitignore | 2 + frontend/package-lock.json | 13 ++ frontend/package.json | 1 + frontend/src/components/CriticalAlert.jsx | 77 +++++---- frontend/src/components/Pages/Backtime.css | 178 ++++++++++++++++++--- frontend/src/components/Pages/Backtime.jsx | 174 +++++++++++++------- frontend/src/components/SwitchControl.css | 0 frontend/src/components/SwitchControl.jsx | 37 +++++ 9 files changed, 356 insertions(+), 126 deletions(-) create mode 100644 frontend/src/components/SwitchControl.css create mode 100644 frontend/src/components/SwitchControl.jsx diff --git a/.DS_Store b/.DS_Store index 649816c8d6dd015a31f7bd82c3ecf8100678041b..03ec99ae3d3efaf280dc69e84efba857ad1a116a 100644 GIT binary patch delta 19 acmZoMXffEZkde*IR7b(kVDoauSTO)R%LS(Z delta 19 acmZoMXffEZkde*MOh>`kWb<;ySTO)R#09AU diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf3..3b0b403 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -22,3 +22,5 @@ dist-ssr *.njsproj *.sln *.sw? + +.env \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index add3140..65aa9e0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,6 +13,7 @@ "@mui/icons-material": "^6.3.0", "@mui/material": "^6.3.0", "axios": "^1.7.9", + "dotenv": "^16.4.7", "react": "^18.3.1", "react-dom": "^18.3.1", "react-helmet": "^6.1.0", @@ -4451,6 +4452,18 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 8292390..44f8e0e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,6 +15,7 @@ "@mui/icons-material": "^6.3.0", "@mui/material": "^6.3.0", "axios": "^1.7.9", + "dotenv": "^16.4.7", "react": "^18.3.1", "react-dom": "^18.3.1", "react-helmet": "^6.1.0", diff --git a/frontend/src/components/CriticalAlert.jsx b/frontend/src/components/CriticalAlert.jsx index 82586fe..f3aa7b6 100644 --- a/frontend/src/components/CriticalAlert.jsx +++ b/frontend/src/components/CriticalAlert.jsx @@ -1,54 +1,53 @@ import React, { useEffect, useState } from "react"; +import { useLocation } from "react-router-dom"; import "./CriticalAlert.css"; const CriticalAlert = () => { + const location = useLocation(); const [isActive, setIsActive] = useState(false); const [opacity, setOpacity] = useState(1); - const [showAlert, setShowAlert] = useState(false); useEffect(() => { - const alertStatus = localStorage.getItem("criticalAlertActive"); - const startTime = localStorage.getItem("criticalAlertStartTime"); + const updateOpacity = () => { + const alertStatus = localStorage.getItem("criticalAlertActive"); + const startTime = localStorage.getItem("criticalAlertStartTime"); + const totalDuration = parseInt(localStorage.getItem("totalDuration") || "15", 10); - if (alertStatus === "yes" && startTime) { - setIsActive(true); - setShowAlert(true); // Affichage initial de l'alerte - - // Disparition automatique de l'alerte après 2 secondes - setTimeout(() => { - setShowAlert(false); - }, 1000); - - // Calcul du temps écoulé - const startTimestamp = parseInt(startTime, 10); - const now = Date.now(); - const elapsedDays = Math.floor((now - startTimestamp) / (1000 * 60 * 60 * 24)); - - if (elapsedDays >= 15) { - setOpacity(0); // Site totalement transparent après 15 jours - } else { - setOpacity(1 - elapsedDays / 15); + if (location.pathname === "/backtime") { + setOpacity(1); + return; } - } - }, []); + + if (alertStatus === "yes" && startTime) { + setIsActive(true); + + const startTimestamp = parseInt(startTime, 10); + const now = Date.now(); + const elapsedTime = now - startTimestamp; + const totalTime = totalDuration * 24 * 60 * 60 * 1000; + const remainingTime = totalTime - elapsedTime; + + if (remainingTime <= 0) { + setOpacity(0); + } else { + const newOpacity = 1 - elapsedTime / totalTime; + setOpacity(newOpacity); + } + } + }; + + updateOpacity(); + const interval = setInterval(updateOpacity, 10000); + + return () => clearInterval(interval); + }, [location]); return ( - <> - {showAlert && ( -
-
-

⚠️ Alerte Mise a jours ⚠️

-

Contacter votre webmaster - défaut Mise à jours du système

-
-
- )} - - {isActive && ( - - )} - + isActive && location.pathname !== "/backtime" && ( + + ) ); }; diff --git a/frontend/src/components/Pages/Backtime.css b/frontend/src/components/Pages/Backtime.css index 83a2b54..0b3b355 100644 --- a/frontend/src/components/Pages/Backtime.css +++ b/frontend/src/components/Pages/Backtime.css @@ -1,22 +1,101 @@ +/* 🔥 Design moderne pour la page Backtime */ .backtime-container { - text-align: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + background: linear-gradient(135deg, #1e1e2f, #3b3b58); + color: white; + font-family: "Poppins", sans-serif; padding: 20px; } -.switch-container { - display: flex; - align-items: center; - justify-content: center; - gap: 15px; - margin-top: 20px; +h2 { + font-size: 2rem; + margin-bottom: 20px; + text-transform: uppercase; + letter-spacing: 2px; + color: #f9f9f9; } -/* Style du switch */ +button { + padding: 10px 20px; + font-size: 1rem; + font-weight: bold; + text-transform: uppercase; + border: none; + cursor: pointer; + transition: all 0.3s ease-in-out; + border-radius: 5px; +} + +.logout-button { + background: #e74c3c; + color: white; +} + +.logout-button:hover { + background: #c0392b; +} + +.countdown { + margin-top: 20px; + padding: 15px; + background: rgba(255, 255, 255, 0.1); + border-radius: 10px; + box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.2); + text-align: center; + font-size: 1.5rem; + font-weight: bold; +} + +.countdown h3 { + margin-bottom: 10px; + color: #f1c40f; +} + +.time-setting { + margin-top: 20px; + display: flex; + flex-direction: column; + align-items: center; +} + +.time-setting label { + font-size: 1.2rem; + margin-bottom: 5px; +} + +.time-setting input { + width: 60px; + padding: 5px; + font-size: 1.2rem; + text-align: center; + border: none; + border-radius: 5px; + background: rgba(255, 255, 255, 0.1); + color: white; +} + +.switch-container { + margin-top: 20px; + display: flex; + align-items: center; + gap: 15px; +} + +.switch-container span { + font-size: 1rem; + font-weight: bold; +} + +/* 🎚️ Switch */ .switch { position: relative; display: inline-block; - width: 50px; - height: 25px; + width: 60px; + height: 30px; } .switch input { @@ -34,42 +113,89 @@ bottom: 0; background-color: #ccc; transition: 0.4s; - border-radius: 25px; + border-radius: 30px; } .slider:before { position: absolute; content: ""; - height: 18px; - width: 18px; + height: 22px; + width: 22px; left: 4px; - bottom: 3px; + bottom: 4px; background-color: white; transition: 0.4s; border-radius: 50%; } input:checked + .slider { - background-color: #4CAF50; + background-color: #2ecc71; } input:checked + .slider:before { - transform: translateX(25px); + transform: translateX(26px); } -/* Voyant lumineux */ -.status-indicator { - padding: 8px 15px; - border-radius: 5px; +/* 🔐 Modernisation du formulaire de connexion */ +.login-container { + background: rgba(0, 0, 0, 0.8); /* Fond semi-transparent pour un effet élégant */ + padding: 30px; + border-radius: 12px; + text-align: center; + box-shadow: 0px 10px 25px rgba(0, 0, 0, 0.3); /* Ombre plus profonde pour effet moderne */ + backdrop-filter: blur(10px); /* Effet flou pour un look premium */ + width: 320px; + transition: all 0.3s ease-in-out; +} + +.login-container:hover { + transform: scale(1.02); /* Effet léger d’agrandissement au survol */ +} + +.login-container h2 { + font-size: 1.8rem; + margin-bottom: 15px; + color: #f1c40f; /* Couleur dorée pour mettre en avant le titre */ font-weight: bold; } -.active { - background-color: green; - color: white; +.login-container input, +.login-button { + width: 100%; /* Assure que les deux éléments prennent la même largeur */ + max-width: 280px; /* Définit une largeur max pour éviter qu'ils deviennent trop grands */ + display: block; /* Évite les décalages */ + margin: 0 auto; /* Centre les éléments */ } -.inactive { - background-color: red; - color: white; +.login-container input { + padding: 12px; + font-size: 1rem; + border: none; + border-radius: 8px; + background: rgba(255, 255, 255, 0.1); + color: white; + text-align: center; + outline: none; +} + +.login-container input::placeholder { + color: #ddd; + font-style: italic; +} + +.login-button { + background: linear-gradient(135deg, #3498db, #2980b9); + color: white; + padding: 12px; + border-radius: 8px; + font-size: 1rem; + font-weight: bold; + cursor: pointer; + text-transform: uppercase; + margin-top: 10px; /* Ajoute un petit espace entre le champ et le bouton */ +} + +.login-button:hover { + background: linear-gradient(135deg, #2980b9, #1c6ea4); + transform: scale(1.05); } \ No newline at end of file diff --git a/frontend/src/components/Pages/Backtime.jsx b/frontend/src/components/Pages/Backtime.jsx index 69b9d05..d5db733 100644 --- a/frontend/src/components/Pages/Backtime.jsx +++ b/frontend/src/components/Pages/Backtime.jsx @@ -1,60 +1,145 @@ import React, { useState, useEffect } from "react"; -import { Helmet } from "react-helmet"; // Permet de gérer les balises -import "./Backtime.css"; - -const PASSWORD_HASH = "240be518fabd2724ddb6f04eeb1da5967448d7e831c08c8fa822809f74c720a9"; +import { Helmet } from "react-helmet"; +import SwitchControl from "../SwitchControl"; // ✅ Import du SwitchControl +import "./Backtime.css"; const Backtime = () => { const [isAuthenticated, setIsAuthenticated] = useState(false); const [inputPassword, setInputPassword] = useState(""); + const [timeRemaining, setTimeRemaining] = useState("Chargement..."); + const [passwordHash, setPasswordHash] = useState(""); + const [totalDuration, setTotalDuration] = useState(() => { + return parseInt(localStorage.getItem("totalDuration"), 10) || 15; // ✅ Utiliser la durée stockée + }); useEffect(() => { - const storedAuth = localStorage.getItem("backtimeAuth"); - if (storedAuth === "true") { - setIsAuthenticated(true); + try { + const envPasswordHash = import.meta.env.VITE_PASSWORD_HASH || ""; + setPasswordHash(envPasswordHash); + console.log("✅ DEBUG : Mot de passe attendu depuis .env :", envPasswordHash); + + const storedAuth = localStorage.getItem("backtimeAuth"); + if (storedAuth === "true") { + setIsAuthenticated(true); + } + + updateTimeRemaining(); // ✅ Mise à jour immédiate du chrono + const interval = setInterval(updateTimeRemaining, 1000); + return () => clearInterval(interval); + } catch (error) { + console.error("❌ Erreur dans useEffect :", error); } }, []); - const hashPassword = async (password) => { - const encoder = new TextEncoder(); - const data = encoder.encode(password); - const hashBuffer = await crypto.subtle.digest("SHA-256", data); - return Array.from(new Uint8Array(hashBuffer)) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); - }; + useEffect(() => { + localStorage.setItem("totalDuration", totalDuration); + adjustStartTime(); + updateTimeRemaining(); // ✅ Mise à jour immédiate dès modification de la durée + }, [totalDuration]); - const handleLogin = async () => { - const hashedInput = await hashPassword(inputPassword); - if (hashedInput === PASSWORD_HASH) { - localStorage.setItem("backtimeAuth", "true"); - setIsAuthenticated(true); + useEffect(() => { + updateTimeRemaining(); // ✅ Exécute `updateTimeRemaining()` immédiatement après modification + }, [totalDuration]); + + const adjustStartTime = () => { + const existingStartTime = localStorage.getItem("criticalAlertStartTime"); + + if (!existingStartTime) { + console.log("⏳ Initialisation de `criticalAlertStartTime`."); + localStorage.setItem("criticalAlertStartTime", Date.now().toString()); } else { - alert("Mot de passe incorrect !"); + const startTimestamp = parseInt(existingStartTime, 10); + const now = Date.now(); + let elapsedTime = now - startTimestamp; + + if (elapsedTime < 0) elapsedTime = 0; + + const newTotalTime = totalDuration * 24 * 60 * 60 * 1000; + const adjustedStartTime = now - elapsedTime; + + console.log(`🔄 Correction ` + + `Ancien Start Time = ${startTimestamp}, ` + + `Nouveau Start Time = ${adjustedStartTime}, ` + + `Temps Écoulé = ${elapsedTime}`); + + localStorage.setItem("criticalAlertStartTime", adjustedStartTime.toString()); } }; - const handleLogout = () => { - localStorage.removeItem("backtimeAuth"); - setIsAuthenticated(false); + const updateTimeRemaining = () => { + try { + const startTime = localStorage.getItem("criticalAlertStartTime"); + + if (!startTime) { + setTimeRemaining("Aucune alerte activée"); + return; + } + + const startTimestamp = parseInt(startTime, 10); + const now = Date.now(); + let elapsedTime = now - startTimestamp; + + if (elapsedTime < 0) elapsedTime = 0; + + const totalTime = totalDuration * 24 * 60 * 60 * 1000; + const remainingTime = totalTime - elapsedTime; + + console.log(`🕒 DEBUG : Temps écoulé = ${elapsedTime}, Temps total = ${totalTime}, Temps restant = ${remainingTime}`); + + if (remainingTime <= 0) { + setTimeRemaining("Le site est complètement blanc !"); + } else { + const days = Math.floor(remainingTime / (1000 * 60 * 60 * 24)); + const hours = Math.floor((remainingTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((remainingTime % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((remainingTime % (1000 * 60)) / 1000); + setTimeRemaining(`${days}j ${hours}h ${minutes}m ${seconds}s`); + } + } catch (error) { + console.error("❌ Erreur dans updateTimeRemaining :", error); + } + }; + + const handleDurationChange = (e) => { + const newDuration = parseInt(e.target.value, 10); + if (!isNaN(newDuration) && newDuration > 0) { + console.log("🔄 Mise à jour de la durée à :", newDuration); + setTotalDuration(newDuration); + } }; return (
- {/* 🚫 Interdit l'indexation par Google */} - Page introuvable + + Gestion du module d'alerte + {isAuthenticated ? ( <>

Gestion du module d'alerte critique

- + +
+ + +
+
+ +
+

Temps restant avant blanchiment total :

+

{timeRemaining}

+
) : (
@@ -65,44 +150,11 @@ const Backtime = () => { value={inputPassword} onChange={(e) => setInputPassword(e.target.value)} /> - +
)}
); }; -const SwitchControl = () => { - const [isActive, setIsActive] = useState(false); - - useEffect(() => { - const alertStatus = localStorage.getItem("criticalAlertActive"); - setIsActive(alertStatus === "yes"); - }, []); - - const toggleAlert = () => { - if (!isActive) { - localStorage.setItem("criticalAlertActive", "yes"); - localStorage.setItem("criticalAlertStartTime", Date.now().toString()); - } else { - localStorage.removeItem("criticalAlertActive"); - localStorage.removeItem("criticalAlertStartTime"); - } - setIsActive(!isActive); - window.location.reload(); - }; - - return ( -
- - - {isActive ? "Module Actif" : "Module Inactif"} - -
- ); -}; - export default Backtime; \ No newline at end of file diff --git a/frontend/src/components/SwitchControl.css b/frontend/src/components/SwitchControl.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/components/SwitchControl.jsx b/frontend/src/components/SwitchControl.jsx new file mode 100644 index 0000000..03e20b7 --- /dev/null +++ b/frontend/src/components/SwitchControl.jsx @@ -0,0 +1,37 @@ +import React, { useState, useEffect } from "react"; +import "./SwitchControl.css"; + +const SwitchControl = () => { + const [isActive, setIsActive] = useState(false); + + useEffect(() => { + const alertStatus = localStorage.getItem("criticalAlertActive"); + setIsActive(alertStatus === "yes"); + }, []); + + const toggleAlert = () => { + if (!isActive) { + localStorage.setItem("criticalAlertActive", "yes"); + localStorage.setItem("criticalAlertStartTime", Date.now().toString()); + } else { + localStorage.removeItem("criticalAlertActive"); + localStorage.removeItem("criticalAlertStartTime"); + } + setIsActive(!isActive); + window.location.reload(); + }; + + return ( +
+ + + {isActive ? "Module Actif" : "Module Inactif"} + +
+ ); +}; + +export default SwitchControl; \ No newline at end of file