381 lines
13 KiB
Plaintext
381 lines
13 KiB
Plaintext
<!doctype html>
|
|
<html lang="pt-BR">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
|
<title><%= @landing_host&.page_title.presence || 'Atendimento WhatsApp' %></title>
|
|
<link id="pageFavicon" rel="icon" type="image/png" href="<%= @landing_host&.logo_url || 'https://iachat.hoteis1001noites.com.br/assets/images/dashboard/captain/logo.svg' %>" />
|
|
<style>
|
|
:root {
|
|
--bg-1: #040b18;
|
|
--bg-2: #031325;
|
|
--card-bg: rgba(15, 23, 41, 0.65);
|
|
--card-border: rgba(255, 255, 255, 0.08);
|
|
--text-1: #ffffff;
|
|
--text-2: #a1b0c8;
|
|
--btn: <%= @landing_host&.theme_color.presence || '#25D366' %>;
|
|
--btn-text: #ffffff;
|
|
--timer-bg: rgba(255, 255, 255, 0.05);
|
|
--timer-alert: #ef4444;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
min-height: 100vh;
|
|
/* prevent scroll by using 100vh absolute and hidden overflow occasionally, but flex is better */
|
|
min-height: 100dvh;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Inter", Roboto, Helvetica, Arial, sans-serif;
|
|
color: var(--text-1);
|
|
background:
|
|
radial-gradient(circle at top right, rgba(37, 211, 102, 0.12), transparent 40%),
|
|
radial-gradient(circle at bottom left, rgba(16, 92, 172, 0.15), transparent 50%),
|
|
linear-gradient(135deg, var(--bg-1), var(--bg-2));
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
overflow: hidden; /* Força não ter scroll vertical se o conteúdo couber perfeitamente */
|
|
}
|
|
|
|
.page {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 16px;
|
|
}
|
|
|
|
.card {
|
|
width: min(100%, 420px);
|
|
max-height: 95vh;
|
|
background: var(--card-bg);
|
|
border: 1px solid var(--card-border);
|
|
border-radius: 24px;
|
|
padding: clamp(20px, 4vh, 32px) clamp(16px, 4vw, 24px);
|
|
text-align: center;
|
|
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
|
backdrop-filter: blur(16px);
|
|
-webkit-backdrop-filter: blur(16px);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.logo-wrap {
|
|
width: clamp(70px, 18vw, 84px);
|
|
height: clamp(70px, 18vw, 84px);
|
|
margin: 0 auto clamp(12px, 3vh, 18px);
|
|
border-radius: 50%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
background: #ffffff; /* Fundo branco fixo para logos com fundo branco */
|
|
border: 2px solid rgba(255,255,255,0.1);
|
|
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
|
|
flex-shrink: 0;
|
|
overflow: hidden; /* Garante que a imagem não vaze o círculo */
|
|
}
|
|
|
|
.logo-wrap img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover; /* Faz a imagem preencher todo o espaço circular */
|
|
}
|
|
|
|
h1 {
|
|
margin: 0;
|
|
font-size: clamp(24px, 6vw, 32px);
|
|
font-weight: 800;
|
|
line-height: 1.1;
|
|
letter-spacing: -0.02em;
|
|
text-wrap: balance;
|
|
color: var(--text-1);
|
|
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
|
}
|
|
|
|
p.subtitle {
|
|
margin: clamp(8px, 2vh, 12px) 0 clamp(16px, 3vh, 24px);
|
|
font-size: clamp(14px, 3.5vw, 16px);
|
|
color: var(--text-2);
|
|
line-height: 1.4;
|
|
text-wrap: balance;
|
|
}
|
|
|
|
/* Timer Area */
|
|
.timer-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
background: var(--timer-bg);
|
|
border: 1px solid rgba(255,255,255,0.04);
|
|
padding: clamp(8px, 2vh, 12px) 20px;
|
|
border-radius: 12px;
|
|
margin-bottom: clamp(16px, 3vh, 24px);
|
|
width: 100%;
|
|
}
|
|
|
|
.timer-label {
|
|
font-size: 11px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
color: var(--text-2);
|
|
margin-bottom: 4px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.timer-value {
|
|
font-size: clamp(28px, 7vw, 36px);
|
|
font-weight: 800;
|
|
font-variant-numeric: tabular-nums;
|
|
color: var(--btn);
|
|
text-shadow: 0 0 15px rgba(37, 211, 102, 0.3);
|
|
line-height: 1;
|
|
transition: color 0.3s;
|
|
}
|
|
|
|
.timer-value.alert {
|
|
color: var(--timer-alert);
|
|
text-shadow: 0 0 15px rgba(239, 68, 68, 0.4);
|
|
animation: pulse-alert 2s infinite;
|
|
}
|
|
|
|
.wa-button {
|
|
width: 100%;
|
|
border: 0;
|
|
border-radius: 14px;
|
|
padding: clamp(14px, 3.5vh, 18px) 20px;
|
|
font-size: clamp(18px, 4.5vw, 22px);
|
|
font-weight: 800;
|
|
color: var(--btn-text);
|
|
background: var(--btn);
|
|
cursor: pointer;
|
|
position: relative;
|
|
overflow: hidden;
|
|
box-shadow: 0 4px 14px rgba(0,0,0,0.25), 0 0 0 0 transparent;
|
|
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275), box-shadow 0.2s;
|
|
animation: pulse-button 2.5s infinite;
|
|
}
|
|
|
|
/* Shine effect */
|
|
.wa-button::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: -50%;
|
|
left: -50%;
|
|
width: 200%;
|
|
height: 200%;
|
|
background: linear-gradient(
|
|
to right,
|
|
rgba(255, 255, 255, 0) 0%,
|
|
rgba(255, 255, 255, 0.3) 50%,
|
|
rgba(255, 255, 255, 0) 100%
|
|
);
|
|
transform: rotate(30deg);
|
|
animation: shine 4s infinite linear;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.wa-button:active {
|
|
transform: scale(0.97);
|
|
animation: none;
|
|
}
|
|
|
|
.foot {
|
|
margin-top: clamp(12px, 3vh, 18px);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: clamp(11px, 2.5vw, 13px);
|
|
color: #5d6a80;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.foot svg {
|
|
width: 14px;
|
|
height: 14px;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
/* Animations */
|
|
@keyframes pulse-button {
|
|
0% { box-shadow: 0 0 0 0 rgba(37, 211, 102, 0.4); }
|
|
70% { box-shadow: 0 0 0 10px rgba(37, 211, 102, 0); }
|
|
100% { box-shadow: 0 0 0 0 rgba(37, 211, 102, 0); }
|
|
}
|
|
|
|
@keyframes shine {
|
|
0% { left: -100%; }
|
|
20% { left: 100%; }
|
|
100% { left: 100%; }
|
|
}
|
|
|
|
@keyframes pulse-alert {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.6; }
|
|
}
|
|
|
|
/* Extremely small height screen adjustments (iPhone SE landscape) */
|
|
@media (max-height: 500px) {
|
|
body { overflow-y: auto; }
|
|
.card { padding: 16px; margin: 16px 0; }
|
|
.logo-wrap { width: 40px; height: 40px; margin-bottom: 8px;}
|
|
.timer-container { margin-bottom: 12px; padding: 6px; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<% if @landing_host.nil? %>
|
|
<div class="page">
|
|
<div class="card">
|
|
<h1>Página não encontrada</h1>
|
|
<p class="subtitle">Verifique a URL digitada e tente novamente.</p>
|
|
</div>
|
|
</div>
|
|
<% else %>
|
|
<div class="page">
|
|
<div class="card">
|
|
<div class="logo-wrap" title="logo">
|
|
<img src="<%= @landing_host.logo_url.presence || 'https://iachat.hoteis1001noites.com.br/assets/images/dashboard/captain/logo.svg' %>" alt="logo" />
|
|
</div>
|
|
<h1><%= @landing_host.page_title %></h1>
|
|
|
|
<p class="subtitle"><%= @landing_host.page_subtitle&.gsub("\n", "<br>")&.html_safe %></p>
|
|
|
|
<div class="timer-container">
|
|
<span class="timer-label">Oferta expira em</span>
|
|
<span class="timer-value" id="countdownTimer">10:00</span>
|
|
</div>
|
|
|
|
<button id="whatsButton" class="wa-button" type="button"><%= @landing_host.button_text.presence || 'Falar no WhatsApp' %></button>
|
|
|
|
<div class="foot">
|
|
<svg xmlns="http://www.w3.org/.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 15H13V17H11V15ZM11 7H13V13H11V7Z"></path></svg>
|
|
Página segura e atendimento humano
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
const config = {
|
|
hostname: "<%= j @landing_host.hostname %>",
|
|
phone: "<%= j @landing_host.whatsapp_number.to_s.gsub(/[^\d]/, '') %>",
|
|
message: "<%= j @landing_host.initial_message.to_s %>",
|
|
defaultSource: "<%= j @landing_host.default_source.to_s %>",
|
|
defaultCampanha: "<%= j @landing_host.default_campanha.to_s %>",
|
|
};
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
const clickKey = "lp_click_id_" + window.location.hostname;
|
|
|
|
// --- Timer Logic ---
|
|
function startTimer() {
|
|
const timerElement = document.getElementById("countdownTimer");
|
|
if (!timerElement) return;
|
|
|
|
// 10 minutes from now (in seconds)
|
|
let totalSeconds = 10 * 60;
|
|
|
|
// Check if we already have a timer running in session storage to persist across refresh
|
|
const sessionKey = "lp_timer_" + window.location.hostname;
|
|
const savedTime = sessionStorage.getItem(sessionKey);
|
|
const savedTimestamp = sessionStorage.getItem(sessionKey + "_ts");
|
|
|
|
if (savedTime && savedTimestamp) {
|
|
const elapsed = Math.floor((Date.now() - parseInt(savedTimestamp)) / 1000);
|
|
const remaining = parseInt(savedTime) - elapsed;
|
|
if (remaining > 0) {
|
|
totalSeconds = remaining;
|
|
}
|
|
}
|
|
|
|
const interval = setInterval(() => {
|
|
if (totalSeconds <= 0) {
|
|
clearInterval(interval);
|
|
timerElement.innerText = "00:00";
|
|
timerElement.classList.add("alert"); // Change color to red/alert
|
|
return;
|
|
}
|
|
|
|
const minutes = Math.floor(totalSeconds / 60);
|
|
const seconds = totalSeconds % 60;
|
|
|
|
const formattedMinutes = minutes.toString().padStart(2, '0');
|
|
const formattedSeconds = seconds.toString().padStart(2, '0');
|
|
|
|
timerElement.innerText = `${formattedMinutes}:${formattedSeconds}`;
|
|
|
|
// Persist in case of refresh
|
|
sessionStorage.setItem(sessionKey, totalSeconds.toString());
|
|
sessionStorage.setItem(sessionKey + "_ts", Date.now().toString());
|
|
|
|
if (totalSeconds <= 60) {
|
|
timerElement.classList.add("alert"); // Final minute warning
|
|
}
|
|
|
|
totalSeconds--;
|
|
}, 1000);
|
|
}
|
|
|
|
startTimer();
|
|
// -------------------
|
|
|
|
function getClickId() {
|
|
const fromUrl = params.get("click_id") || params.get("clickid") || params.get("utm_id") || params.get("gclid");
|
|
if (fromUrl) {
|
|
localStorage.setItem(clickKey, fromUrl);
|
|
return fromUrl;
|
|
}
|
|
const existing = localStorage.getItem(clickKey);
|
|
if (existing) return existing;
|
|
const generated = `lp-${Date.now()}-${Math.floor(Math.random() * 100000)}`;
|
|
localStorage.setItem(clickKey, generated);
|
|
return generated;
|
|
}
|
|
|
|
function currentSource() {
|
|
return params.get("utm_source") || params.get("source") || config.defaultSource || "direto";
|
|
}
|
|
|
|
function currentCampanha() {
|
|
return params.get("utm_campaign") || params.get("campanha") || config.defaultCampanha || "site";
|
|
}
|
|
|
|
async function sendTrack() {
|
|
const payload = {
|
|
hostname: config.hostname || window.location.hostname,
|
|
lp: window.location.href,
|
|
click_id: getClickId(),
|
|
source: currentSource(),
|
|
campanha: currentCampanha(),
|
|
};
|
|
|
|
try {
|
|
await fetch("/track/click", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(payload),
|
|
keepalive: true,
|
|
});
|
|
} catch (_) {}
|
|
}
|
|
|
|
async function openWhatsapp() {
|
|
await sendTrack();
|
|
const text = encodeURIComponent(config.message);
|
|
window.location.href = `https://wa.me/${config.phone}?text=${text}`;
|
|
}
|
|
|
|
document.getElementById("whatsButton").addEventListener("click", openWhatsapp);
|
|
})();
|
|
</script>
|
|
<% end %>
|
|
</body>
|
|
</html>
|