diff --git a/wwwroot/poc-checkout.html b/wwwroot/poc-checkout.html index c843b6f..102861a 100644 --- a/wwwroot/poc-checkout.html +++ b/wwwroot/poc-checkout.html @@ -943,6 +943,96 @@ border-color: #ccc; } + /* ========================================== + BARCODE SCANNER + ========================================== */ + .scan-btn { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + width: 100%; + padding: 14px 20px; + margin-top: 12px; + font-size: 13px; + font-weight: 600; + color: var(--color-teal); + background: color-mix(in srgb, var(--color-teal) 8%, white); + border: 2px dashed var(--color-teal); + border-radius: 6px; + cursor: pointer; + transition: all 200ms ease; + } + + .scan-btn:hover { + background: color-mix(in srgb, var(--color-teal) 15%, white); + border-style: solid; + } + + .scan-btn.scanning { + border-color: #1976d2; + color: #1976d2; + background: color-mix(in srgb, #1976d2 8%, white); + animation: pulse-border 1.5s ease-in-out infinite; + } + + @keyframes pulse-border { + 0%, 100% { border-color: #1976d2; } + 50% { border-color: #64b5f6; } + } + + .scan-btn svg { + width: 18px; + height: 18px; + fill: currentColor; + } + + .scanner-input-hidden { + position: absolute; + left: -9999px; + opacity: 0; + } + + /* Debug codes in sidebar */ + .debug-codes { + display: flex; + flex-direction: column; + gap: 4px; + padding: 12px 16px; + border-top: 1px solid var(--color-border); + font-size: 11px; + color: var(--color-text-secondary); + } + + .debug-codes strong { + color: var(--color-text); + margin-bottom: 4px; + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.5px; + } + + .debug-codes div { + display: flex; + align-items: center; + gap: 6px; + } + + .debug-codes code { + font-family: var(--font-mono); + font-size: 10px; + background: var(--color-surface); + padding: 2px 6px; + border-radius: 3px; + cursor: pointer; + user-select: all; + } + + .debug-codes code:hover { + background: var(--color-teal); + color: white; + } + @@ -992,6 +1082,13 @@
Styling
Olaplex
+
+ Test EAN-koder: +
5012345678900 Olaplex No.4
+
8710447489109 Redken Shampoo
+
3474636610143 Kérastase
+
0000000000000 Ukendt
+
@@ -1176,6 +1273,14 @@
+ + + + + @@ -1653,6 +1758,226 @@ document.addEventListener('keydown', e => { if (e.key === 'Escape') closePanel(); }); + + // ========================================== + // BARCODE SCANNER + // ========================================== + + // Mock product database for scanning + const scanProducts = { + '5012345678900': { + name: 'Olaplex No.4 Bond Maintenance Shampoo', + price: 299, + size: '250ml' + }, + '8710447489109': { + name: 'Redken All Soft Shampoo', + price: 249, + size: '300ml' + }, + '3474636610143': { + name: 'Kérastase Elixir Ultime', + price: 425, + size: '100ml' + }, + '0850018802239': { + name: 'Olaplex No.7 Bonding Oil', + price: 319, + size: '30ml' + } + }; + + // Scanner elements + const scanButton = document.getElementById('scanButton'); + const scannerInput = document.getElementById('scannerInput'); + + let isScanning = false; + let scannedCode = ''; + let scanTimeout = null; + + // Start scanning + scanButton.addEventListener('click', () => { + if (isScanning) return; + + isScanning = true; + scannedCode = ''; + scanButton.classList.add('scanning'); + scanButton.innerHTML = ` + + SCANNING... + `; + scannerInput.value = ''; + scannerInput.focus(); + }); + + // Handle scanner input + scannerInput.addEventListener('input', (e) => { + scannedCode = e.target.value; + + if (scanTimeout) clearTimeout(scanTimeout); + + // After 200ms of no input, consider scan complete + scanTimeout = setTimeout(() => { + if (scannedCode.length >= 8) { + processScannedCode(scannedCode); + } + }, 200); + }); + + // Handle Enter key from scanner + scannerInput.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === 'Tab') { + e.preventDefault(); + if (scannedCode.length >= 8) { + clearTimeout(scanTimeout); + processScannedCode(scannedCode); + } + } + }); + + // Handle blur - reset if no code scanned + scannerInput.addEventListener('blur', () => { + if (isScanning && scannedCode.length === 0) { + setTimeout(() => { + if (isScanning && scannedCode.length === 0) { + resetScanner(); + } + }, 300); + } + }); + + // Reset scanner to ready state + function resetScanner() { + isScanning = false; + scannedCode = ''; + scanButton.classList.remove('scanning'); + scanButton.innerHTML = ` + + SCAN PRODUKT + `; + } + + // Process scanned code + async function processScannedCode(code) { + // Show loading state + scanButton.innerHTML = ` + + HENTER... + `; + + // Simulate API delay + await new Promise(r => setTimeout(r, 600)); + + // Look up product + const foundProduct = scanProducts[code] || null; + + if (foundProduct) { + // Add to cart + addScannedProductToCart(foundProduct, code); + + // Show success briefly + scanButton.style.borderColor = '#43a047'; + scanButton.style.color = '#43a047'; + scanButton.innerHTML = ` + + TILFØJET! + `; + + setTimeout(() => { + scanButton.style.borderColor = ''; + scanButton.style.color = ''; + resetScanner(); + }, 800); + } else { + // Show not found + scanButton.style.borderColor = '#f59e0b'; + scanButton.style.color = '#f59e0b'; + scanButton.innerHTML = ` + + IKKE FUNDET + `; + + setTimeout(() => { + scanButton.style.borderColor = ''; + scanButton.style.color = ''; + resetScanner(); + }, 1500); + } + } + + // Add scanned product to cart visually + function addScannedProductToCart(product, ean) { + const cartSectionItems = document.querySelector('.cart-section:last-of-type .cart-section-items'); + + const newItem = document.createElement('div'); + newItem.className = 'cart-item'; + newItem.setAttribute('onclick', 'toggleCartItem(this)'); + newItem.setAttribute('data-base-price', product.price); + newItem.innerHTML = ` +
+
+ + 1 + +
+
+
${product.name}
+
${product.size}
+
+
+
${product.price} kr
+
${product.price} kr
+
-0 kr rabat
+
+ +
+
+
+
+
Pris
+ +
+
+
Rabat
+
+ +
+ + +
+
+
+
+
+ `; + + // Insert at end of items list + cartSectionItems.appendChild(newItem); + + // Flash the new item + newItem.style.animation = 'flash 0.5s ease'; + + // Re-attach discount type handlers + newItem.querySelectorAll('.discount-type-btn').forEach(btn => { + btn.addEventListener('click', (e) => { + e.stopPropagation(); + toggleDiscountType(btn); + }); + }); + } + + // Add animations + const scannerStyle = document.createElement('style'); + scannerStyle.textContent = ` + @keyframes flash { + 0% { background-color: rgba(0, 137, 123, 0.2); } + 100% { background-color: transparent; } + } + @keyframes spin { + to { transform: rotate(360deg); } + } + `; + document.head.appendChild(scannerStyle);