first commit

This commit is contained in:
O K
2025-09-07 12:50:02 +03:00
commit ba8c1e6957
10 changed files with 843 additions and 0 deletions

117
views/js/front.js Normal file
View File

@@ -0,0 +1,117 @@
/**
* Product Discount Countdown Module
*
* This script initializes countdown timers on the product page.
* It handles the initial page load and the dynamic updates that occur
* when a customer changes a product combination (attribute).
*/
// A global array to keep track of our active timer intervals.
// This is crucial for cleanup when the product block is updated via AJAX.
let productCountdownIntervals = [];
/**
* Scans the DOM for countdown containers and initializes them.
* This function is designed to be called on page load and after AJAX updates.
*/
function initializeProductCountdowns() {
// 1. Clear any previously running timers.
// This prevents multiple timers from running after a product combination change.
productCountdownIntervals.forEach(intervalId => clearInterval(intervalId));
productCountdownIntervals = [];
// 2. Find all countdown containers on the page that need to be processed.
const countdownContainers = document.querySelectorAll('.product-countdown-container');
countdownContainers.forEach(container => {
// Check if this specific container has already been initialized to avoid race conditions.
if (container.dataset.initialized === 'true') {
return;
}
const timerElement = container.querySelector('.countdown-timer');
if (!timerElement) return;
// Mark as initialized
container.dataset.initialized = 'true';
const targetTimestamp = parseInt(container.dataset.timestamp, 10);
const onExpireAction = container.dataset.onExpire;
const expiredText = container.dataset.expiredText;
// Get translated units from hidden spans
const units = {
day: container.querySelector('[data-unit="day"]').textContent,
days: container.querySelector('[data-unit="days"]').textContent,
hr: container.querySelector('[data-unit="hr"]').textContent,
min: container.querySelector('[data-unit="min"]').textContent,
sec: container.querySelector('[data-unit="sec"]').textContent
};
function updateTimer() {
const now = Math.floor(new Date().getTime() / 1000);
const diff = targetTimestamp - now;
if (diff <= 0) {
clearInterval(interval);
handleExpiry();
return;
}
const d = Math.floor(diff / (60 * 60 * 24));
const h = Math.floor((diff % (60 * 60 * 24)) / (60 * 60));
const m = Math.floor((diff % (60 * 60)) / 60);
const s = Math.floor(diff % 60);
const parts = [];
if (d > 0) {
parts.push(`${d} ${d > 1 ? units.days : units.day}`);
}
// Always show hours, minutes, and seconds for a better countdown experience
parts.push(`${String(h).padStart(2, '0')}${units.hr}`);
parts.push(`${String(m).padStart(2, '0')}${units.min}`);
parts.push(`${String(s).padStart(2, '0')}${units.sec}`);
timerElement.textContent = parts.join(' ');
}
function handleExpiry() {
switch (onExpireAction) {
case 'reload':
location.reload();
break;
case 'message':
container.querySelector('.countdown-wrapper').innerHTML = `<span class="badge badge-secondary">${expiredText}</span>`;
break;
case 'hide':
default:
container.style.display = 'none';
break;
}
}
const interval = setInterval(updateTimer, 1000);
// Add the new interval ID to our global array for tracking.
productCountdownIntervals.push(interval);
updateTimer(); // Initial call to display the timer immediately
});
}
// --- Event Listeners ---
// 1. Run the initializer on the initial page load.
document.addEventListener('DOMContentLoaded', () => {
initializeProductCountdowns();
});
// 2. Run the initializer whenever PrestaShop updates the product block via AJAX.
// The `prestashop` object is globally available in modern themes.
if (typeof prestashop !== 'undefined') {
prestashop.on('updateProduct', (data) => {
// We use a small timeout to ensure the DOM has been fully updated by PrestaShop's scripts
// before our script runs and looks for the new container. 100ms is usually safe.
setTimeout(() => {
initializeProductCountdowns();
}, 100);
});
}