mtextylelastedweb / js /catalog.js
ibrohm's picture
Initial deploy via assistant API
7b3aac2 verified
// ========================================
// CATALOG.JS — Filter, Sort, Search, Paginate
// ========================================
const ITEMS_PER_PAGE = 12;
let currentFilters = { category: null, sizes: [], colors: [], minPrice: undefined, maxPrice: undefined, hasDiscount: false };
let currentSort = 'default';
let currentPage = 1;
let currentView = 'grid';
document.addEventListener('DOMContentLoaded', () => {
parseURLParams();
buildFilterUI();
applyAndRender();
setupEventListeners();
setupMobileFilter();
});
function parseURLParams() {
const params = new URLSearchParams(window.location.search);
if (params.get('category')) currentFilters.category = params.get('category');
if (params.get('search')) {
const si = document.getElementById('searchInput');
if (si) si.value = params.get('search');
}
if (params.get('filter') === 'discount') currentFilters.hasDiscount = true;
if (params.get('filter') === 'new') currentSort = 'newest';
if (params.get('sort')) currentSort = params.get('sort');
// Update page title
if (currentFilters.category && CATEGORIES[currentFilters.category]) {
document.getElementById('catalogTitle').textContent = CATEGORIES[currentFilters.category].name;
document.getElementById('catalogSubtitle').textContent = `${CATEGORIES[currentFilters.category].icon} ${CATEGORIES[currentFilters.category].name} kategoriyasidagi mahsulotlar`;
}
}
function buildFilterUI() {
// Categories
const catContainer = document.getElementById('filterCategory');
catContainer.innerHTML = `<div class="filter-option ${!currentFilters.category ? 'active' : ''}" data-cat="">
<div class="filter-checkbox"></div><span>Barchasi</span>
</div>`;
Object.entries(CATEGORIES).forEach(([slug, cat]) => {
const count = getProductsByCategory(slug).length;
catContainer.innerHTML += `<div class="filter-option ${currentFilters.category === slug ? 'active' : ''}" data-cat="${slug}">
<div class="filter-checkbox"></div><span>${cat.icon} ${cat.name} (${count})</span>
</div>`;
});
catContainer.querySelectorAll('.filter-option').forEach(el => {
el.addEventListener('click', () => {
catContainer.querySelectorAll('.filter-option').forEach(e => e.classList.remove('active'));
el.classList.add('active');
currentFilters.category = el.dataset.cat || null;
currentPage = 1;
applyAndRender();
});
});
// Sizes
const sizeContainer = document.getElementById('filterSizes');
SIZES.forEach(size => {
const btn = document.createElement('button');
btn.className = 'size-btn';
btn.textContent = size;
btn.addEventListener('click', () => {
btn.classList.toggle('active');
if (btn.classList.contains('active')) currentFilters.sizes.push(size);
else currentFilters.sizes = currentFilters.sizes.filter(s => s !== size);
currentPage = 1;
applyAndRender();
});
sizeContainer.appendChild(btn);
});
// Colors
const colorContainer = document.getElementById('filterColors');
Object.entries(COLORS_MAP).forEach(([key, val]) => {
const btn = document.createElement('button');
btn.className = 'color-btn';
btn.style.background = val.hex;
btn.title = val.name;
btn.addEventListener('click', () => {
btn.classList.toggle('active');
if (btn.classList.contains('active')) currentFilters.colors.push(key);
else currentFilters.colors = currentFilters.colors.filter(c => c !== key);
currentPage = 1;
applyAndRender();
});
colorContainer.appendChild(btn);
});
// Discount toggle
const discEl = document.getElementById('filterDiscount');
if (currentFilters.hasDiscount) discEl.classList.add('active');
discEl.addEventListener('click', () => {
discEl.classList.toggle('active');
currentFilters.hasDiscount = discEl.classList.contains('active');
currentPage = 1;
applyAndRender();
});
}
function setupEventListeners() {
// Sort
document.getElementById('sortSelect').addEventListener('change', (e) => {
currentSort = e.target.value;
applyAndRender();
});
// Price filter
document.getElementById('applyPrice').addEventListener('click', () => {
const min = document.getElementById('priceMin').value;
const max = document.getElementById('priceMax').value;
currentFilters.minPrice = min ? parseInt(min) : undefined;
currentFilters.maxPrice = max ? parseInt(max) : undefined;
currentPage = 1;
applyAndRender();
});
// Clear filters
document.getElementById('clearFilters').addEventListener('click', clearAllFilters);
// View toggle
document.getElementById('gridViewBtn')?.addEventListener('click', () => { setView('grid'); });
document.getElementById('listViewBtn')?.addEventListener('click', () => { setView('list'); });
// Navbar search
const si = document.getElementById('searchInput');
if (si) {
si.addEventListener('input', debounce(() => { currentPage = 1; applyAndRender(); }, 300));
}
}
function setupMobileFilter() {
const mobileBtn = document.getElementById('mobileFilterBtn');
const sidebar = document.getElementById('filterSidebar');
const overlay = document.getElementById('filterOverlay');
if (window.innerWidth <= 768) mobileBtn.style.display = 'inline-flex';
window.addEventListener('resize', () => {
mobileBtn.style.display = window.innerWidth <= 768 ? 'inline-flex' : 'none';
});
mobileBtn?.addEventListener('click', () => {
sidebar.classList.add('active');
overlay.classList.add('active');
});
overlay?.addEventListener('click', () => {
sidebar.classList.remove('active');
overlay.classList.remove('active');
});
}
function setView(view) {
currentView = view;
const grid = document.getElementById('productsGrid');
grid.classList.toggle('list-view', view === 'list');
document.getElementById('gridViewBtn')?.classList.toggle('active', view === 'grid');
document.getElementById('listViewBtn')?.classList.toggle('active', view === 'list');
}
function clearAllFilters() {
currentFilters = { category: null, sizes: [], colors: [], minPrice: undefined, maxPrice: undefined, hasDiscount: false };
currentSort = 'default';
currentPage = 1;
document.getElementById('priceMin').value = '';
document.getElementById('priceMax').value = '';
document.getElementById('sortSelect').value = 'default';
document.querySelectorAll('.filter-option.active, .size-btn.active, .color-btn.active').forEach(el => el.classList.remove('active'));
document.querySelector('[data-cat=""]')?.classList.add('active');
const si = document.getElementById('searchInput');
if (si) si.value = '';
applyAndRender();
}
function applyAndRender() {
let products = [...PRODUCTS];
// Search
const query = document.getElementById('searchInput')?.value?.trim();
if (query) products = searchProducts(query);
// Filter
products = filterProducts(products, currentFilters);
// Sort
products = sortProducts(products, currentSort);
// Update count
document.getElementById('productCount').textContent = `${products.length} ta mahsulot`;
// Pagination
const totalPages = Math.ceil(products.length / ITEMS_PER_PAGE);
const start = (currentPage - 1) * ITEMS_PER_PAGE;
const pageProducts = products.slice(start, start + ITEMS_PER_PAGE);
// Render products
const grid = document.getElementById('productsGrid');
const noResults = document.getElementById('noResults');
grid.innerHTML = '';
if (pageProducts.length === 0) {
grid.style.display = 'none';
noResults.style.display = 'block';
} else {
grid.style.display = '';
noResults.style.display = 'none';
pageProducts.forEach(p => grid.appendChild(renderProductCard(p)));
}
renderPagination(totalPages);
}
function renderPagination(totalPages) {
const container = document.getElementById('pagination');
container.innerHTML = '';
if (totalPages <= 1) return;
for (let i = 1; i <= totalPages; i++) {
const btn = document.createElement('button');
btn.className = `btn btn-sm ${i === currentPage ? 'btn-primary' : 'btn-outline'}`;
btn.textContent = i;
btn.addEventListener('click', () => {
currentPage = i;
applyAndRender();
window.scrollTo({ top: 0, behavior: 'smooth' });
});
container.appendChild(btn);
}
}
function debounce(fn, ms) {
let timer;
return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); };
}