Files
landing/js/products.js
2025-05-03 23:33:02 +00:00

575 lines
22 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
});
});