575 lines
22 KiB
JavaScript
575 lines
22 KiB
JavaScript
async function showCryptoModal(eurAmount) {
|
||
document.getElementById('cryptoModal').classList.remove('hidden');
|
||
|
||
// Update payment amount with loading state
|
||
const paymentAmountEl = document.getElementById('paymentAmount');
|
||
paymentAmountEl.textContent = 'Расчет суммы...';
|
||
|
||
try {
|
||
const ltcAmount = await convertEurToLtc(eurAmount);
|
||
paymentAmountEl.textContent = `Сумма к оплате: ${ltcAmount} LTC`;
|
||
} catch (error) {
|
||
console.error('Ошибка расчета суммы:', error);
|
||
paymentAmountEl.textContent = 'Ошибка расчета суммы';
|
||
}
|
||
}
|
||
|
||
function hideCryptoModal() {
|
||
document.getElementById('cryptoModal').classList.add('hidden');
|
||
}
|
||
|
||
// Product details data
|
||
|
||
function showBlackBoxProductDetails(productName) {
|
||
console.log('showBlackBoxProductDetails called with:', productName);
|
||
|
||
// Verify productsData exists and has the product
|
||
if (!productsData) {
|
||
console.error('productsData is not defined!');
|
||
return;
|
||
}
|
||
if (!productsData[productName]) {
|
||
console.error('Product not found in productsData:', productName);
|
||
return;
|
||
}
|
||
|
||
const modal = document.getElementById('productModal');
|
||
if (!modal) {
|
||
console.error('Modal element not found!');
|
||
return;
|
||
}
|
||
|
||
// Force remove any inline display:none styles
|
||
modal.style.display = 'flex';
|
||
|
||
const titleEl = document.getElementById('modalTitle');
|
||
const descEl = document.getElementById('modalDescription');
|
||
|
||
if (titleEl) titleEl.textContent = productName;
|
||
if (descEl) descEl.textContent = productsData[productName].description;
|
||
|
||
// Ensure modal is visible
|
||
modal.classList.remove('hidden');
|
||
|
||
// Debug modal state after changes
|
||
setTimeout(() => {
|
||
console.log('Modal state after show:', {
|
||
classList: Array.from(modal.classList),
|
||
computedDisplay: window.getComputedStyle(modal).display,
|
||
computedOpacity: window.getComputedStyle(modal).opacity,
|
||
computedVisibility: window.getComputedStyle(modal).visibility,
|
||
computedZIndex: window.getComputedStyle(modal).zIndex,
|
||
computedPointerEvents: window.getComputedStyle(modal).pointerEvents
|
||
});
|
||
}, 50);
|
||
}
|
||
|
||
function hideBlackBoxProductDetails() {
|
||
const modal = document.getElementById('productModal');
|
||
modal.classList.add('hidden');
|
||
console.log('Product modal hidden');
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
console.log('DOMContentLoaded - Adding event listeners');
|
||
|
||
// Debug: Log all elements with onclick handlers
|
||
const detailButtons = document.querySelectorAll('[onclick^="showProductDetails"]');
|
||
console.log('Found', detailButtons.length, 'detail buttons');
|
||
detailButtons.forEach(btn => {
|
||
const originalOnClick = btn.onclick;
|
||
btn.onclick = function(e) {
|
||
console.log('Detail button clicked:', {
|
||
element: e.target,
|
||
product: e.target.getAttribute('onclick').match(/'([^']+)'/)[1],
|
||
stack: new Error().stack
|
||
});
|
||
return originalOnClick.call(this, e);
|
||
};
|
||
});
|
||
|
||
// Connect all buy buttons to show crypto modal
|
||
const buyButtons = document.querySelectorAll('.buy-btn');
|
||
console.log('Found', buyButtons.length, 'buy buttons');
|
||
buyButtons.forEach(btn => {
|
||
btn.addEventListener('click', function(e) {
|
||
console.log('Buy button clicked', e.target);
|
||
// Find the parent glass-card to get the product name and price
|
||
const productCard = e.target.closest('.glass-card');
|
||
if (productCard) {
|
||
const productNameElement = productCard.querySelector('h3');
|
||
if (productNameElement) {
|
||
const productName = productNameElement.textContent.trim();
|
||
const product = productsData[productName];
|
||
if (product && product.price) {
|
||
showCryptoModal(product.price);
|
||
} else {
|
||
console.error('Product price not found for:', productName);
|
||
// Optionally show the modal without price calculation or show an error message
|
||
showCryptoModal(0); // Pass 0 or handle error in showCryptoModal
|
||
}
|
||
} else {
|
||
console.error('Product name element not found in card');
|
||
showCryptoModal(0);
|
||
}
|
||
} else {
|
||
console.error('Product card not found for buy button');
|
||
showCryptoModal(0);
|
||
}
|
||
});
|
||
});
|
||
|
||
// Debug modal close button
|
||
const modalClose = document.querySelector('.modal-close');
|
||
if (modalClose) {
|
||
console.log('Found modal close button');
|
||
modalClose.addEventListener('click', function(e) {
|
||
console.log('Modal close clicked');
|
||
hideBlackBoxProductDetails();
|
||
});
|
||
}
|
||
|
||
const dropdownItems = document.querySelectorAll('.dropdown-item');
|
||
const menuButtons = document.querySelectorAll('.dropdown-item button');
|
||
const contentAreas = document.querySelectorAll('.content-area');
|
||
|
||
function activateCategory(index) {
|
||
// Remove active class from all menu items and content areas
|
||
dropdownItems.forEach(item => item.classList.remove('active'));
|
||
contentAreas.forEach(area => area.classList.remove('active'));
|
||
|
||
// Add active class to the selected menu item and content area
|
||
dropdownItems[index].classList.add('active');
|
||
const targetId = menuButtons[index].getAttribute('data-target');
|
||
const targetContentArea = document.getElementById(targetId);
|
||
if (targetContentArea) {
|
||
targetContentArea.classList.add('active');
|
||
}
|
||
|
||
// Rotate icon for active item
|
||
menuButtons.forEach((button, btnIndex) => {
|
||
const icon = button.querySelector('i'); // Get icon reference here
|
||
if (index === btnIndex) {
|
||
icon.style.transform = 'rotate(90deg)';
|
||
icon.classList.add('active-arrow');
|
||
} else {
|
||
icon.style.transform = 'rotate(0deg)';
|
||
icon.classList.remove('active-arrow');
|
||
}
|
||
});
|
||
}
|
||
|
||
// Initialize the first category as active
|
||
activateCategory(0);
|
||
|
||
menuButtons.forEach((button, index) => {
|
||
const icon = button.querySelector('i'); // Get icon reference here
|
||
|
||
button.addEventListener('click', () => {
|
||
activateCategory(index);
|
||
});
|
||
|
||
// Handle hover for icon rotation on desktop
|
||
// Handle arrow rotation and glow effect
|
||
button.addEventListener('click', () => {
|
||
const isActive = button.parentElement.classList.contains('active');
|
||
icon.style.transform = isActive ? 'rotate(90deg)' : 'rotate(0deg)';
|
||
|
||
if (isActive) {
|
||
icon.classList.add('active-arrow');
|
||
} else {
|
||
icon.classList.remove('active-arrow');
|
||
}
|
||
});
|
||
|
||
// Desktop hover effects
|
||
if (window.innerWidth >= 768) {
|
||
button.addEventListener('mouseenter', () => {
|
||
if (!button.parentElement.classList.contains('active')) {
|
||
icon.style.transform = 'rotate(90deg)';
|
||
}
|
||
button.style.transform = 'translateX(5px)';
|
||
});
|
||
|
||
button.addEventListener('mouseleave', () => {
|
||
if (!button.parentElement.classList.contains('active')) {
|
||
icon.style.transform = 'rotate(0deg)';
|
||
}
|
||
button.style.transform = '';
|
||
});
|
||
}
|
||
});
|
||
|
||
|
||
// Add click handlers for product cards (if needed, currently handled by onclick)
|
||
// document.querySelectorAll('.product-card').forEach(card => {
|
||
// card.addEventListener('click', () => {
|
||
// const productName = card.querySelector('h3').textContent;
|
||
// showProductDetails(productName);
|
||
// });
|
||
// });
|
||
|
||
// Close modal when clicking outside
|
||
document.getElementById('productModal').addEventListener('click', (e) => {
|
||
if (e.target === document.getElementById('productModal')) {
|
||
hideBlackBoxProductDetails();
|
||
}
|
||
});
|
||
|
||
// Close crypto modal when clicking outside
|
||
document.getElementById('cryptoModal').addEventListener('click', (e) => {
|
||
if (e.target === document.getElementById('cryptoModal')) {
|
||
hideCryptoModal();
|
||
}
|
||
});
|
||
});
|
||
|
||
// Функция для получения курса LTC/EUR с Kraken
|
||
async function getKrakenRate() {
|
||
try {
|
||
const response = await fetch('https://api.kraken.com/0/public/Ticker?pair=LTCEUR');
|
||
const data = await response.json();
|
||
const price = parseFloat(data.result.XLTCZEUR.c[0]);
|
||
return price;
|
||
} catch (error) {
|
||
console.error('Ошибка при получении курса с Kraken:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// Функция для получения курса LTC/EUR с CoinGecko
|
||
async function getCoinGeckoRate() {
|
||
try {
|
||
const response = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=litecoin&vs_currencies=eur');
|
||
const data = await response.json();
|
||
const price = parseFloat(data.litecoin.eur);
|
||
return price;
|
||
} catch (error) {
|
||
console.error('Ошибка при получении курса с CoinGecko:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// Функция для получения курса LTC/EUR с Bybit
|
||
async function getBybitRate() {
|
||
try {
|
||
const response = await fetch('https://api.bybit.com/v2/public/tickers?symbol=LTCUSDT');
|
||
const data = await response.json();
|
||
const ltcUsdtPrice = parseFloat(data.result[0].last_price);
|
||
const eurResponse = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=tether&vs_currencies=eur');
|
||
const eurData = await eurResponse.json();
|
||
const usdtEurRate = parseFloat(eurData.tether.eur);
|
||
const ltcEurPrice = ltcUsdtPrice * usdtEurRate;
|
||
return ltcEurPrice;
|
||
} catch (error) {
|
||
console.error('Ошибка при получении курса с Bybit:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// Функция для получения среднего курса LTC/EUR
|
||
async function getAverageRate() {
|
||
const rates = await Promise.all([getKrakenRate(), getCoinGeckoRate(), getBybitRate()]);
|
||
const validRates = rates.filter(rate => rate !== null);
|
||
if (validRates.length === 0) {
|
||
throw new Error('Не удалось получить курсы с бирж.');
|
||
}
|
||
const sum = validRates.reduce((acc, rate) => acc + rate, 0);
|
||
return sum / validRates.length;
|
||
}
|
||
|
||
// Функция для конвертации суммы в евро в LTC
|
||
async function convertEurToLtc(eurAmount) {
|
||
try {
|
||
const averageRate = await getAverageRate();
|
||
const ltcAmount = eurAmount / averageRate;
|
||
console.log(`Средний курс LTC/EUR: €${averageRate.toFixed(2)}`);
|
||
console.log(`${eurAmount} EUR ≈ ${ltcAmount.toFixed(8)} LTC`);
|
||
return ltcAmount.toFixed(8);
|
||
} catch (error) {
|
||
console.error('Ошибка при конвертации:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// Function to update the payment amount in the crypto modal
|
||
async function updatePaymentAmount(eurAmount) {
|
||
const paymentAmountElement = document.getElementById('paymentAmount');
|
||
if (paymentAmountElement) {
|
||
paymentAmountElement.textContent = 'Расчет суммы...'; // Show loading state
|
||
const ltcAmount = await convertEurToLtc(eurAmount);
|
||
if (ltcAmount !== null) {
|
||
paymentAmountElement.textContent = `Сумма к оплате: ${ltcAmount} LTC`;
|
||
} else {
|
||
paymentAmountElement.textContent = 'Не удалось рассчитать сумму';
|
||
}
|
||
}
|
||
}
|
||
|
||
function showCryptoModal(productPrice) {
|
||
document.getElementById('cryptoModal').classList.remove('hidden');
|
||
// Call the function to update the payment amount when the modal is shown
|
||
updatePaymentAmount(productPrice);
|
||
}
|
||
|
||
function hideCryptoModal() {
|
||
document.getElementById('cryptoModal').classList.add('hidden');
|
||
}
|
||
|
||
// Product details data
|
||
// Product details data with prices
|
||
const productsData = {
|
||
"BlackBox VPN": {
|
||
description: "Базовый бокс с VPN функционалом. 512MB RAM. Создаёт Wi-Fi точку с защищённым VPN. Включает: безопасный браузинг, VPN сервер, анонимный e-mail, доставку обновлений.",
|
||
price: 99
|
||
},
|
||
"BlackBox Privacy Messenger/Cloud": {
|
||
description: "Встроенный Matrix Messenger или Nextcloud. 1 GB RAM. Полный контроль над вашими данными. Защищённые чаты и файловое хранилище.",
|
||
price: 199
|
||
},
|
||
"BlackBox 4GB": {
|
||
description: "Мощный бокс с увеличенной памятью. 4GB RAM. Все функции базовой модели + удалённый рабочий стол (Workspace). Полный контроль над вашими данными.",
|
||
price: 299
|
||
},
|
||
"BlackBox Workstation": {
|
||
description: "Полноценная рабочая станция. Все функции предыдущих моделей. Поддержка виртуальных машин и контейнеров.",
|
||
price: 499
|
||
},
|
||
"BlackBox AI": {
|
||
description: "Включает все технологии BlackBox. Приватный искусственный интеллект. Максимальная автономность и защита. Локальная обработка данных.",
|
||
price: 2999
|
||
},
|
||
"BlackBox Shop": {
|
||
description: "Создание магазина в Telegram через бота. Загрузка товаров, описание, цена. Оплата за товары через криптовалюту. Полная анонимность продавца и покупателя.",
|
||
price: 499 // Assuming a base price for the shop
|
||
},
|
||
"Защита данных": {
|
||
description: "Полная защита ваших персональных данных. Включает: мониторинг утечек, защиту от фишинга, безопасное хранение паролей, регулярные обновления безопасности.",
|
||
price: 49 // per month
|
||
},
|
||
"Облачное хранилище": {
|
||
description: "Защищенное хранилище файлов с end-to-end шифрованием. Доступ с любого устройства. Автоматическое резервное копирование. Совместимость со всеми популярными форматами.",
|
||
price: 29 // per month
|
||
},
|
||
"Приватный чат": {
|
||
description: "Полностью анонимные переписки с end-to-end шифрованием. Нет логов сообщений. Поддержка групповых чатов. Совместимость с другими мессенджерами.",
|
||
price: 19 // per month
|
||
},
|
||
"Анонимный email": {
|
||
description: "Полностью анонимная почта без привязки к личности. Временные адреса. Шифрование всех входящих/исходящих сообщений. Защита от спама.",
|
||
price: 39 // per month
|
||
},
|
||
"Крипто-кошелек": {
|
||
description: "Изолированный cold-wallet для хранения и операций криптовалютой с максимальной изоляцией от internet-угроз. Поддержка основных блокчейнов.",
|
||
price: 59 // per month
|
||
},
|
||
"Децентрализованный хостинг": {
|
||
description: "Размещение сайтов и приложений без центрального сервера. Полная анонимность владельца. Защита от DDoS. Автоматическое масштабирование.",
|
||
price: 79 // per month
|
||
}
|
||
};
|
||
|
||
function showBlackBoxProductDetails(productName) {
|
||
console.log('showBlackBoxProductDetails called with:', productName);
|
||
|
||
// Verify productsData exists and has the product
|
||
if (!productsData) {
|
||
console.error('productsData is not defined!');
|
||
return;
|
||
}
|
||
if (!productsData[productName]) {
|
||
console.error('Product not found in productsData:', productName);
|
||
return;
|
||
}
|
||
|
||
const modal = document.getElementById('productModal');
|
||
if (!modal) {
|
||
console.error('Modal element not found!');
|
||
return;
|
||
}
|
||
|
||
// Force remove any inline display:none styles
|
||
modal.style.display = 'flex';
|
||
|
||
const titleEl = document.getElementById('modalTitle');
|
||
const descEl = document.getElementById('modalDescription');
|
||
|
||
if (titleEl) titleEl.textContent = productName;
|
||
if (descEl) descEl.textContent = productsData[productName].description;
|
||
|
||
// Ensure modal is visible
|
||
modal.classList.remove('hidden');
|
||
|
||
// Debug modal state after changes
|
||
setTimeout(() => {
|
||
console.log('Modal state after show:', {
|
||
classList: Array.from(modal.classList),
|
||
computedDisplay: window.getComputedStyle(modal).display,
|
||
computedOpacity: window.getComputedStyle(modal).opacity,
|
||
computedVisibility: window.getComputedStyle(modal).visibility,
|
||
computedZIndex: window.getComputedStyle(modal).zIndex,
|
||
computedPointerEvents: window.getComputedStyle(modal).pointerEvents
|
||
});
|
||
}, 50);
|
||
}
|
||
|
||
function hideBlackBoxProductDetails() {
|
||
const modal = document.getElementById('productModal');
|
||
modal.classList.add('hidden');
|
||
console.log('Product modal hidden');
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
console.log('DOMContentLoaded - Adding event listeners');
|
||
|
||
// Debug: Log all elements with onclick handlers
|
||
const detailButtons = document.querySelectorAll('[onclick^="showProductDetails"]');
|
||
console.log('Found', detailButtons.length, 'detail buttons');
|
||
detailButtons.forEach(btn => {
|
||
const originalOnClick = btn.onclick;
|
||
btn.onclick = function(e) {
|
||
console.log('Detail button clicked:', {
|
||
element: e.target,
|
||
product: e.target.getAttribute('onclick').match(/'([^']+)'/)[1],
|
||
stack: new Error().stack
|
||
});
|
||
return originalOnClick.call(this, e);
|
||
};
|
||
});
|
||
|
||
// Connect all buy buttons to show crypto modal and pass product price
|
||
const buyButtons = document.querySelectorAll('.buy-btn');
|
||
console.log('Found', buyButtons.length, 'buy buttons');
|
||
buyButtons.forEach(btn => {
|
||
btn.addEventListener('click', function(e) {
|
||
console.log('Buy button clicked', e.target);
|
||
// Find the parent glass-card to get the product name and price
|
||
const productCard = e.target.closest('.glass-card');
|
||
if (productCard) {
|
||
const productNameElement = productCard.querySelector('h3');
|
||
if (productNameElement) {
|
||
const productName = productNameElement.textContent.trim();
|
||
const product = productsData[productName];
|
||
if (product && product.price) {
|
||
showCryptoModal(product.price);
|
||
} else {
|
||
console.error('Product price not found for:', productName);
|
||
// Optionally show the modal without price calculation or show an error message
|
||
showCryptoModal(0); // Pass 0 or handle error in showCryptoModal
|
||
}
|
||
} else {
|
||
console.error('Product name element not found in card');
|
||
showCryptoModal(0);
|
||
}
|
||
} else {
|
||
console.error('Product card not found for buy button');
|
||
showCryptoModal(0);
|
||
}
|
||
});
|
||
});
|
||
|
||
|
||
// Debug modal close button
|
||
const modalClose = document.querySelector('.modal-close');
|
||
if (modalClose) {
|
||
console.log('Found modal close button');
|
||
modalClose.addEventListener('click', function(e) {
|
||
console.log('Modal close clicked');
|
||
hideBlackBoxProductDetails();
|
||
});
|
||
}
|
||
|
||
const dropdownItems = document.querySelectorAll('.dropdown-item');
|
||
const menuButtons = document.querySelectorAll('.dropdown-item button');
|
||
const contentAreas = document.querySelectorAll('.content-area');
|
||
|
||
function activateCategory(index) {
|
||
// Remove active class from all menu items and content areas
|
||
dropdownItems.forEach(item => item.classList.remove('active'));
|
||
contentAreas.forEach(area => area.classList.remove('active'));
|
||
|
||
// Add active class to the selected menu item and content area
|
||
dropdownItems[index].classList.add('active');
|
||
const targetId = menuButtons[index].getAttribute('data-target');
|
||
const targetContentArea = document.getElementById(targetId);
|
||
if (targetContentArea) {
|
||
targetContentArea.classList.add('active');
|
||
}
|
||
|
||
// Rotate icon for active item
|
||
menuButtons.forEach((button, btnIndex) => {
|
||
const icon = button.querySelector('i'); // Get icon reference here
|
||
if (index === btnIndex) {
|
||
icon.style.transform = 'rotate(90deg)';
|
||
icon.classList.add('active-arrow');
|
||
} else {
|
||
icon.style.transform = 'rotate(0deg)';
|
||
icon.classList.remove('active-arrow');
|
||
}
|
||
});
|
||
}
|
||
|
||
// Initialize the first category as active
|
||
activateCategory(0);
|
||
|
||
menuButtons.forEach((button, index) => {
|
||
const icon = button.querySelector('i'); // Get icon reference here
|
||
|
||
button.addEventListener('click', () => {
|
||
activateCategory(index);
|
||
});
|
||
|
||
// Handle hover for icon rotation on desktop
|
||
// Handle arrow rotation and glow effect
|
||
button.addEventListener('click', () => {
|
||
const isActive = button.parentElement.classList.contains('active');
|
||
icon.style.transform = isActive ? 'rotate(90deg)' : 'rotate(0deg)';
|
||
|
||
if (isActive) {
|
||
icon.classList.add('active-arrow');
|
||
} else {
|
||
icon.classList.remove('active-arrow');
|
||
}
|
||
});
|
||
|
||
// Desktop hover effects
|
||
if (window.innerWidth >= 768) {
|
||
button.addEventListener('mouseenter', () => {
|
||
if (!button.parentElement.classList.contains('active')) {
|
||
icon.style.transform = 'rotate(90deg)';
|
||
}
|
||
button.style.transform = 'translateX(5px)';
|
||
});
|
||
|
||
button.addEventListener('mouseleave', () => {
|
||
if (!button.parentElement.classList.contains('active')) {
|
||
icon.style.transform = 'rotate(0deg)';
|
||
}
|
||
button.style.transform = '';
|
||
});
|
||
}
|
||
});
|
||
|
||
|
||
// Add click handlers for product cards (if needed, currently handled by onclick)
|
||
// document.querySelectorAll('.product-card').forEach(card => {
|
||
// card.addEventListener('click', () => {
|
||
// const productName = card.querySelector('h3').textContent;
|
||
// showProductDetails(productName);
|
||
// });
|
||
// });
|
||
|
||
// Close modal when clicking outside
|
||
document.getElementById('productModal').addEventListener('click', (e) => {
|
||
if (e.target === document.getElementById('productModal')) {
|
||
hideBlackBoxProductDetails();
|
||
}
|
||
});
|
||
|
||
// Close crypto modal when clicking outside
|
||
document.getElementById('cryptoModal').addEventListener('click', (e) => {
|
||
if (e.target === document.getElementById('cryptoModal')) {
|
||
hideCryptoModal();
|
||
}
|
||
});
|
||
}); |