diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 44cd264..c3daca9 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -14,7 +14,8 @@ "Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(''''Last sync:'''', d[''''last_sync'''']\\); print\\(''''Products:'''', len\\(d[''''products'''']\\)\\); print\\(''''Sample names:''''\\); [print\\('''' -'''', p[''''name''''][:80]\\) for p in d[''''products''''][:5]]\")", "Bash(PYTHON=\"/c/Users/hocke/Documents/GitHub/pokemon-stock-checker/.venv/Scripts/python.exe\")", "Bash(\"$PYTHON\" -c \":*)", - "Bash(1 grep:*)" + "Bash(1 grep:*)", + "Bash(taskkill /F /IM python.exe)" ] } } diff --git a/config.py b/config.py index 98f0bf5..7581fb2 100644 --- a/config.py +++ b/config.py @@ -36,7 +36,7 @@ SORT_BY_NEWEST = True # Which sites to monitor # Note: PokemonCenter has strong bot protection (Imperva) - may need manual workarounds # Note: Walmart has aggressive bot protection (PerimeterX) - may need stealth mode -SITES_ENABLED = ["target", "gamestop"] # Options: "pokemoncenter", "target", "gamestop", "bestbuy" (disabled - needs rework), "walmart" +SITES_ENABLED = ["target", "gamestop", "bestbuy"] # Options: "pokemoncenter", "target", "gamestop", "bestbuy" (disabled - needs rework), "walmart" # PokemonCenter URLs to monitor POKEMON_CENTER_URLS = [ diff --git a/dashboard/static/app.js b/dashboard/static/app.js index 95f8611..a1be244 100644 --- a/dashboard/static/app.js +++ b/dashboard/static/app.js @@ -6,6 +6,8 @@ const API_BASE = '/api'; let currentPage = 'dashboard'; let charts = {}; let currentEventFilter = null; // { type: 'new_drop'|'restock', period: 'today'|'week' } +let currentProductPage = 1; +const PRODUCTS_PER_PAGE = 50; // Initialize document.addEventListener('DOMContentLoaded', () => { @@ -81,6 +83,7 @@ function initEventListeners() { if (el) { el.addEventListener('change', () => { currentEventFilter = null; // Clear event filter when using regular filters + currentProductPage = 1; loadProducts(); }); } @@ -106,6 +109,7 @@ function clearAllFilters() { document.getElementById('filterStock').value = ''; document.getElementById('filterFavorites').checked = false; currentEventFilter = null; + currentProductPage = 1; loadProducts(); } @@ -296,12 +300,14 @@ async function loadActivityFeed() { // Navigate to products filtered by event type function goToFilteredProducts(eventType, period) { currentEventFilter = { type: eventType, period: period }; + currentProductPage = 1; navigateTo('products'); } // Clear event filter function clearEventFilter() { currentEventFilter = null; + currentProductPage = 1; loadProducts(); } @@ -311,8 +317,9 @@ async function loadProducts() { const category = document.getElementById('filterCategory')?.value || ''; const inStock = document.getElementById('filterStock')?.value || ''; const favoritesOnly = document.getElementById('filterFavorites')?.checked || false; + const offset = (currentProductPage - 1) * PRODUCTS_PER_PAGE; - let url = '/products?limit=50'; + let url = `/products?limit=${PRODUCTS_PER_PAGE}&offset=${offset}`; if (site) url += `&site=${site}`; if (category) url += `&category=${encodeURIComponent(category)}`; if (inStock) url += `&in_stock=${inStock}`; @@ -333,6 +340,7 @@ async function loadProducts() { if (data.products.length === 0) { grid.innerHTML = '
No products found
'; + renderPagination(0); return; } @@ -376,6 +384,36 @@ async function loadProducts() { `; }).join(''); + + renderPagination(data.total || 0); +} + +function renderPagination(total) { + const container = document.getElementById('productsPagination'); + if (!container) return; + + const totalPages = Math.ceil(total / PRODUCTS_PER_PAGE); + if (totalPages <= 1) { + container.innerHTML = ''; + return; + } + + const start = (currentProductPage - 1) * PRODUCTS_PER_PAGE + 1; + const end = Math.min(currentProductPage * PRODUCTS_PER_PAGE, total); + + container.innerHTML = ` + + `; +} + +function changeProductPage(page) { + currentProductPage = page; + loadProducts(); + document.getElementById('page-products').scrollIntoView({ behavior: 'smooth' }); } // Handle product image errors by showing store icon diff --git a/dashboard/static/style.css b/dashboard/static/style.css index 2afcd54..4084576 100644 --- a/dashboard/static/style.css +++ b/dashboard/static/style.css @@ -859,6 +859,42 @@ h3 { background: var(--border-color); } +/* Pagination */ +#productsPagination { + margin-top: 20px; +} + +.pagination { + display: flex; + align-items: center; + justify-content: center; + gap: 15px; +} + +.btn-page { + padding: 8px 18px; + background: var(--bg-card); + color: var(--text-primary); + border: 1px solid var(--border-color); + border-radius: 6px; + cursor: pointer; + font-size: 14px; +} + +.btn-page:hover:not(:disabled) { + background: var(--border-color); +} + +.btn-page:disabled { + opacity: 0.4; + cursor: default; +} + +.page-info { + color: var(--text-secondary); + font-size: 14px; +} + /* Settings */ .settings-section { max-width: 600px; diff --git a/dashboard/templates/index.html b/dashboard/templates/index.html index 0942b3d..2947d87 100644 --- a/dashboard/templates/index.html +++ b/dashboard/templates/index.html @@ -110,6 +110,7 @@
Loading products...
+