PHP WebShell
Текущая директория: /var/www/bitcardoApp/user/common
Просмотр файла: footer.php
<style>
/* Make the FAB truly top-most and clickable everywhere */
.chat-fab{
position: fixed;
right: 16px;
bottom: 86px; /* above your fixed-bottom footer */
width: 56px;
height: 56px;
border-radius: 50%;
background: #076289;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
box-shadow: 0 6px 18px rgba(0,0,0,.2);
z-index: 2147483647; /* HUGE: above any widget/iframe/tooltips */
pointer-events: auto; /* ensure the anchor receives clicks */
}
.chat-fab:hover{ filter: brightness(0.95); }
.chat-fab i{ font-size: 1.4rem; line-height: 1; }
.chat-fab-badge{
position: absolute;
top: -6px;
right: -6px;
min-width: 20px;
height: 20px;
padding: 0 6px;
border-radius: 10px;
background: #dc3545;
color: #fff;
font-size: 12px;
line-height: 20px;
text-align: center;
box-shadow: 0 2px 8px rgba(0,0,0,.15);
}
@media (min-width: 768px){
.chat-fab{ display: none; }
}
/* If you show an "Opening chat…" overlay, keep it high too */
.chat-fab-overlay{
position: fixed; inset: 0;
display: none;
align-items: center; justify-content: center;
background: rgba(255,255,255,.8);
backdrop-filter: blur(2px);
z-index: 2147483600;
font-weight: 600;
color: #000;
}
.chat-fab.loading + .chat-fab-overlay{ display: flex; }
small {
font: arial;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, "Noto Sans", "Liberation Sans",
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
sans-serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
"Liberation Mono", "Courier New", monospace;
}
/* Make offline overlay see-through but still block clicks */
#offlineOverlay{
background: rgba(255,255,255,0.1) !important; /* was 0.96 */
/* optional: soften the blur a bit too */
backdrop-filter: blur(1.5px) !important;
}
/* Keep the card readable even with lower overlay opacity */
#offlineOverlay .offline-overlay__card{
background: rgba(255,255,255,0.9);
}
</style>
<div class="mt-5"></div>
<footer class="mt-5 d-md-none fixed-bottom bg-white border-top shadow-sm">
<div class="d-flex justify-content-around text-center py-2 mb-2">
<a href="../../user/dashboard/index.php" class="text-decoration-none text-dark">
<div class="d-flex flex-column align-items-center">
<i class="bi bi-house-door-fill"></i>
<small>Home</small>
</div>
</a>
<a href="../../user/wallets/wallets.php" class="text-decoration-none text-dark">
<div class="d-flex flex-column align-items-center">
<i class="bi bi-wallet2"></i>
<small>Wallets</small>
</div>
</a>
<a href="../../user/dashboard/index.php#convert" class="text-decoration-none text-dark">
<div class="d-flex flex-column align-items-center">
<i class="bi bi-shuffle"></i>
<small>Convert</small>
</div>
</a>
<a href="../../user/data/rates.php" class="text-decoration-none text-dark">
<div class="d-flex flex-column align-items-center">
<i class="bi bi-graph-up"></i>
<small>Rates</small>
</div>
</a>
<a href="../../user/account/account.php" class="text-decoration-none text-dark">
<div class="d-flex flex-column align-items-center">
<i class="bi bi-person-circle"></i>
<small>Account</small>
</div>
</a>
</div>
</footer>
<!-- Back to top -->
<button id="backToTop" class="btn btn-dark">Back to top</button>
<!-- Floating Chat FAB (wallet → Grupo SSO) -->
<div style="position:fixed; right:16px; bottom:86px; width:56px; height:56px; z-index:2147483646; pointer-events:none;">
<!-- 🔴 Only change here: added id="chatFab" -->
<a href="/chat/sso/" id="chatFab" class="chat-fab" style="pointer-events:auto;">
<i class="bi bi-chat-dots-fill"></i>
<span class="chat-fab-badge d-none" id="chatUnreadCount">0</span>
</a>
</div>
<div id="chatFabOverlay" class="chat-fab-overlay" aria-hidden="true">Opening chat…</div>
<script>
// Optional: Later you can fetch unread count and show it here
// fetch('/chat/unread-count').then(r => r.json()).then(d => {
// if (d.count > 0) {
// const b = document.getElementById('chatUnreadCount');
// b.textContent = d.count > 99 ? '99+' : d.count;
// b.classList.remove('d-none');
// }
// });
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Owl Carousel JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js"></script>
<script>
// Back to top logic
const backToTopBtn = document.getElementById('backToTop');
window.addEventListener('scroll', () => {
backToTopBtn.style.display = window.scrollY > 100 ? 'block' : 'none';
});
backToTopBtn.addEventListener('click', () => {
window.scrollTo({ top: 0, behavior: 'smooth' });
});
// Currency swap demo
function swapCurrencies() {
const currencyFrom = document.getElementById("currencyFrom");
const currencyTo = document.getElementById("currencyTo");
const amountFrom = document.getElementById("amountFrom");
const amountTo = document.getElementById("amountTo");
const tempCurrency = currencyFrom.value;
currencyFrom.value = currencyTo.value;
currencyTo.value = tempCurrency;
const tempAmount = amountFrom.value;
amountFrom.value = amountTo.value;
amountTo.value = tempAmount;
}
// SSO: show a quick overlay and prevent double-clicks while redirecting
(function(){
const fab = document.getElementById('chatFab');
if (!fab) return;
fab.addEventListener('click', function(){
this.classList.add('loading');
this.style.pointerEvents = 'none';
// Note: we do NOT preventDefault, so browser still follows /chat/sso/
});
})();
// Owl carousel init
$(document).ready(function(){
$(".owl-carousel").owlCarousel({
loop: false,
margin: 10,
nav: true,
dots: false,
autoplay: false,
responsive: {
0: { items: 2 },
600: { items: 2 },
1000:{ items: 4 }
}
});
});
</script>
<!-- CHECK INTERNET -->
<script>
(function(){
// ---------- CONFIG ----------
const PING_URL = '/health/ping.php'; // <-- change if your ping lives elsewhere
const FAST_MS = 3000; // probe interval when online
const FASTER_MS = 2000; // probe interval when offline
const TIMEOUT_MS = 3000; // per-probe timeout
// ---------- ENSURE UI ELEMENTS EXIST ----------
function ensureEl(id, html){
let el = document.getElementById(id);
if (!el){
const wrapper = document.createElement('div');
wrapper.innerHTML = html.trim();
el = wrapper.firstElementChild;
document.body.appendChild(el);
}
return el;
}
const overlay = ensureEl('offlineOverlay', `
<div id="offlineOverlay" class="offline-overlay" aria-live="polite" aria-hidden="true"
style="position:fixed;inset:0;display:none;align-items:center;justify-content:center;text-align:center;padding:24px;background:rgba(255,255,255,.96);backdrop-filter:blur(2px);z-index:2147483647;">
<div class="offline-overlay__card" role="alert"
style="max-width:340px;width:100%;border:1px solid #eee;border-radius:12px;background:#fff;box-shadow:0 10px 30px rgba(0,0,0,.08);padding:20px;">
<div class="offline-spinner" aria-hidden="true"
style="width:28px;height:28px;margin:0 auto 10px;border:3px solid #ddd;border-top-color:#076289;border-radius:50%;animation:spin 1s linear infinite;"></div>
<div class="offline-overlay__title" style="font-weight:700;margin-bottom:6px;color:#111;">You’re offline</div>
<p class="offline-overlay__text" style="color:#333;margin:0;">We’ll reconnect automatically. <br/> Actions are disabled for now.</p>
</div>
</div>
`);
const toast = ensureEl('onlineToast', `
<div id="onlineToast" class="online-toast"
style="position:fixed;left:50%;transform:translateX(-50%);bottom:100px;background:#16a34a;color:#fff;font-weight:600;padding:10px 14px;border-radius:999px;box-shadow:0 8px 22px rgba(0,0,0,.15);display:none;z-index:2147483600;">
Back online
</div>
`);
// Spinner keyframes (once)
(function addSpin(){
if (document.getElementById('offlineSpinKeyframes')) return;
const style = document.createElement('style');
style.id = 'offlineSpinKeyframes';
style.textContent = '@keyframes spin{to{transform:rotate(360deg)}}';
document.head.appendChild(style);
})();
// ---------- HELPERS ----------
function showOverlay(){ overlay.style.display='flex'; overlay.setAttribute('aria-hidden','false'); document.documentElement.classList.add('app-offline'); }
function hideOverlay(){ overlay.style.display='none'; overlay.setAttribute('aria-hidden','true'); document.documentElement.classList.remove('app-offline'); }
function showToast(ms=1500){
toast.style.display='block';
clearTimeout(showToast._t);
showToast._t = setTimeout(()=> toast.style.display='none', ms);
}
async function probe(url, timeoutMs){
const ctrl = new AbortController();
const t = setTimeout(()=> ctrl.abort(), timeoutMs);
try{
const res = await fetch(url + (url.includes('?') ? '&' : '?') + '_=' + Date.now(), {
method: 'GET', // HEAD can be blocked on some hosts
cache: 'no-store',
credentials: 'same-origin',
signal: ctrl.signal
});
return res.ok; // 200/204 is fine
}catch(_){ return false; }
finally{ clearTimeout(t); }
}
let lastOnline = null;
let checking = false;
let pollId = null;
function setPoll(ms){
if (pollId) clearInterval(pollId);
pollId = setInterval(()=> { if (!document.hidden) evaluate(true); }, ms);
}
async function evaluate(immediate=false){
if (checking) return; checking = true;
// Trust immediate offline signal if browser provides it
if (typeof navigator.onLine === 'boolean' && !navigator.onLine){
goOffline('nav-offline');
checking = false;
return;
}
// Confirm with network probe
const ok = await probe(PING_URL, TIMEOUT_MS);
if (ok){
goOnline();
} else {
goOffline('probe-fail');
}
checking = false;
}
function goOnline(){
if (lastOnline === false) showToast();
hideOverlay();
lastOnline = true;
setPoll(FAST_MS);
}
function goOffline(_reason){
showOverlay();
lastOnline = false;
setPoll(FASTER_MS);
}
// ---------- EVENTS ----------
window.addEventListener('online', () => evaluate(true));
window.addEventListener('offline', () => goOffline('event'));
document.addEventListener('visibilitychange', () => { if (!document.hidden) evaluate(true); });
const conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if (conn && typeof conn.addEventListener === 'function'){
conn.addEventListener('change', () => evaluate(true));
}
// Block chat click while offline
const chatFab = document.getElementById('chatFab');
if (chatFab){
chatFab.addEventListener('click', function(e){
if (overlay.style.display === 'flex'){
e.preventDefault();
this.animate(
[{ transform:'translateX(0)' }, { transform:'translateX(-4px)' }, { transform:'translateX(4px)' }, { transform:'translateX(0)' }],
{ duration: 250, iterations: 1 }
);
}
});
}
// ---------- START ----------
setPoll(FAST_MS);
evaluate(true);
})();
</script>
<style>
/* Optional: disable pointer interactions on page when offline via a class */
html.app-offline { pointer-events: none; }
html.app-offline #offlineOverlay { pointer-events: all; } /* allow overlay buttons if you add any */
</style>
</body>
</html>
Выполнить команду
Для локальной разработки. Не используйте в интернете!