update v1.1

This commit is contained in:
2025-05-03 23:33:02 +00:00
parent 3afa5e666b
commit 635d1a4ce1
7 changed files with 1069 additions and 24 deletions

View File

@@ -127,27 +127,6 @@ function initProductDetails() {
});
}
// Show product details modal
function showProductDetails(pageNum) {
const details = productDetails[pageNum];
if (details) {
document.getElementById('modalTitle').textContent = details.title;
document.getElementById('modalDescription').textContent = details.description;
document.getElementById('productModal').classList.add('show');
}
}
function hideProductDetails() {
document.getElementById('productModal').classList.remove('show');
}
// Close modal when clicking outside
document.getElementById('productModal').addEventListener('click', function(e) {
if (e.target === this) {
hideProductDetails();
}
});
// Initialize
initProductDetails();
// Product details functionality moved to products.html
// This file only handles flipbook navigation
updatePages();

575
js/products.js Normal file
View File

@@ -0,0 +1,575 @@
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();
}
});
});