{"version":3,"file":"swatch-journey.js","names":[],"sources":["../resources/javascript/swatch-journey.js"],"sourcesContent":["import Dialog from 'dialog';\nimport { removeItem } from './swatch/local-storage';\n\nconst MAX_SWATCHES = 6;\nconst STORAGE_KEY = 'swatches';\nconst BADGE_TICK =\n    '<svg viewBox=\"0 0 15 12\" width=\"12\" height=\"10\"><path d=\"M14.067.933a1 1 0 0 1 0 1.414l-8.13 ' +\n    '8.13a1 1 0 0 1-1.414 0L.933 6.887a1 1 0 1 1 1.414-1.414L5.523 8.65 ' +\n    '12.653.933a1 1 0 0 1 1.414 0Z\" fill=\"currentColor\"/></svg>';\n\n// DOM references\nconst basketSlots = document.querySelector('[data-swatch-slots]');\nconst basketCount = document.querySelector('[data-swatch-count]');\nconst basketForm = document.querySelector('[data-basket-form]');\nconst basketInput = document.querySelector('[data-swatch-panel-input]');\nconst continueBtn = document.querySelector('.swatch-journey-basket__continue');\n\nlet currentColourCode = null;\nlet selectedMaterials = new Set();\n\n// ── localStorage helpers ──\n\nconst getSwatches = () => {\n    try {\n        return JSON.parse(localStorage.getItem(STORAGE_KEY)) ?? [];\n    } catch {\n        return [];\n    }\n};\n\nconst saveSwatches = swatches => {\n    localStorage.setItem(STORAGE_KEY, JSON.stringify(swatches));\n};\n\nconst getSwatchColour = swatch => {\n    try {\n        return JSON.parse(swatch.value).colour;\n    } catch {\n        return null;\n    }\n};\n\nconst isSwatchInBasket = urlname => {\n    return getSwatches().some(s => getSwatchColour(s) === urlname);\n};\n\nconst removeSwatchByUrlname = urlname => {\n    const swatches = getSwatches().filter(s => getSwatchColour(s) !== urlname);\n    saveSwatches(swatches);\n};\n\nconst isComboInBasket = (colourCode, materialCode) => {\n    return getSwatches().some(\n        s => s.colourCode === colourCode && s.materialCode === materialCode\n    );\n};\n\nconst getRemainingSlots = () => {\n    return MAX_SWATCHES - getSwatches().length;\n};\n\n// ── Colour button badge helpers ──\n\nconst getCountsPerColour = () => {\n    const counts = {};\n    for (const swatch of getSwatches()) {\n        if (swatch.colourCode) {\n            counts[swatch.colourCode] = (counts[swatch.colourCode] || 0) + 1;\n        }\n    }\n    return counts;\n};\n\nconst updateColourBadges = () => {\n    const counts = getCountsPerColour();\n    document.querySelectorAll('.swatch-journey__colour').forEach(btn => {\n        const code = btn.dataset.colourCode;\n        const badge = btn.querySelector('[data-colour-badge]');\n        if (!badge) return;\n\n        // Don't touch the active colour (overlay open) — it shows a tick\n        if (btn.classList.contains('swatch-journey__colour--active')) return;\n\n        const count = counts[code] || 0;\n        if (count > 0) {\n            btn.classList.add('swatch-journey__colour--has-swatches');\n            badge.innerHTML = count === 1 ? BADGE_TICK : 'x' + count;\n        } else {\n            btn.classList.remove('swatch-journey__colour--has-swatches');\n            badge.innerHTML = '';\n        }\n    });\n};\n\n// ── Basket rendering ──\n\nconst renderBasket = () => {\n    let swatches = getSwatches();\n\n    for (const swatch of swatches) {\n        if ('imageHtml' in swatch === false) {\n            removeItem('swatches', swatch.value);\n        }\n    }\n\n    swatches = getSwatches();\n\n    const count = swatches.length;\n\n    basketCount.textContent = `Your free swatches (${count}/${MAX_SWATCHES})`;\n    continueBtn.disabled = count === 0;\n\n    const urlnames = swatches.map(s => getSwatchColour(s)).filter(Boolean);\n    basketInput.value = urlnames.join(',');\n\n    basketSlots.innerHTML = '';\n    for (let i = 0; i < MAX_SWATCHES; i++) {\n        const slot = document.createElement('div');\n        slot.className = 'swatch-journey-basket__slot';\n\n        if (swatches[i]) {\n            slot.style.cssText = swatches[i].backgroundCSS || '';\n            slot.classList.add('swatch-journey-basket__slot--filled');\n            slot.title = swatches[i].title || '';\n\n            if (swatches[i].imageHtml) {\n                slot.insertAdjacentHTML('afterbegin', swatches[i].imageHtml);\n                const img = slot.querySelector('img');\n                img?.classList.add('swatch-journey-basket__slot-image');\n            }\n\n            const urlname = getSwatchColour(swatches[i]);\n            slot.addEventListener('click', () => {\n                removeSwatchByUrlname(urlname);\n                renderBasket();\n            });\n        }\n\n        basketSlots.appendChild(slot);\n    }\n\n    updateColourBadges();\n};\n\n// ── Overlay helpers ──\n\nconst updateAddButton = () => {\n    const addBtn = document.querySelector('[data-overlay-add]');\n    if (!addBtn) return;\n    const count = selectedMaterials.size;\n    addBtn.textContent = `Add ${count} swatch${count !== 1 ? 'es' : ''}`;\n    addBtn.disabled = count === 0;\n};\n\n/**\n * Callback invoked after the D3R overlay opens with server-rendered\n * materials content. Binds material selection and basket logic.\n */\nconst initMaterialsOverlay = () => {\n    const root = document.querySelector('.swatch-journey-overlay');\n    if (!root) return;\n\n    const colourCode = root.dataset.colourCode;\n    currentColourCode = colourCode;\n    selectedMaterials.clear();\n\n    // Mark cards that are already in the basket\n    const cards = root.querySelectorAll('.swatch-journey__material-card');\n    for (const card of cards) {\n        const materialCode = card.dataset.materialCode;\n        const available = card.dataset.available === 'true';\n\n        if (available && isComboInBasket(colourCode, materialCode)) {\n            card.classList.add('swatch-journey__material-card--in-basket');\n            continue;\n        }\n\n        if (!available) continue;\n\n        // Bind selection toggle\n        const btn = card.querySelector('.swatch-journey__material-swatch');\n        btn?.addEventListener('click', () => {\n            if (\n                !card.classList.contains(\n                    'swatch-journey__material-card--selected'\n                )\n            ) {\n                card.classList.add('swatch-journey__material-card--selected');\n                selectedMaterials.add(materialCode);\n            } else {\n                card.classList.remove(\n                    'swatch-journey__material-card--selected'\n                );\n                selectedMaterials.delete(materialCode);\n            }\n            updateAddButton();\n        });\n    }\n\n    // Bind \"Add swatches\" button\n    const addBtn = root.querySelector('[data-overlay-add]');\n    addBtn?.addEventListener('click', addSelectedSwatches);\n};\n\nconst findColourButton = code =>\n    Array.from(document.querySelectorAll('.swatch-journey__colour')).find(\n        el => el.dataset.colourCode === code\n    ) ?? null;\n\nconst onOverlayClose = () => {\n    // Remove active indicator from colour button\n    if (currentColourCode) {\n        const activeBtn = findColourButton(currentColourCode);\n        if (activeBtn) {\n            activeBtn.classList.remove('swatch-journey__colour--active');\n        }\n    }\n\n    currentColourCode = null;\n    selectedMaterials.clear();\n    updateColourBadges();\n};\n\nconst openMaterialsOverlay = colourCode => {\n    // Show tick on the active colour button\n    const activeBtn = findColourButton(colourCode);\n    if (activeBtn) {\n        const badge = activeBtn.querySelector('[data-colour-badge]');\n        activeBtn.classList.remove('swatch-journey__colour--has-swatches');\n        activeBtn.classList.add('swatch-journey__colour--active');\n        if (badge) badge.innerHTML = BADGE_TICK;\n    }\n\n    Dialog.load(\n        '/swatches/materials-overlay?colour_global=' +\n            encodeURIComponent(colourCode),\n        {\n            modifiers: ['sidebar', 'overlay', 'swatch-journey'],\n            // Open immediately with a spinner, fill fabrics when the response lands.\n            loading: 'active',\n            loading_content: '<div class=\"lds-dual-ring\"></div>',\n            stack: true,\n            callback: initMaterialsOverlay,\n            close: onOverlayClose,\n        }\n    );\n};\n\n// ── Add swatches ──\n\nconst addSelectedSwatches = async () => {\n    const capturedColourCode = currentColourCode;\n    if (!capturedColourCode || selectedMaterials.size === 0) {\n        return;\n    }\n\n    const addBtn = document.querySelector('[data-overlay-add]');\n    if (addBtn) {\n        addBtn.disabled = true;\n        addBtn.textContent = 'Adding\\u2026';\n    }\n\n    const materialsToAdd = [...selectedMaterials];\n\n    const results = await Promise.allSettled(\n        materialsToAdd.map(async materialCode => {\n            const response = await fetch(\n                '/swatches/resolve-swatch?colour_global=' +\n                    encodeURIComponent(capturedColourCode) +\n                    '&material_global=' +\n                    encodeURIComponent(materialCode),\n                { headers: { 'X-Requested-With': 'XMLHttpRequest' } }\n            );\n            if (!response.ok) {\n                throw new Error('HTTP ' + response.status);\n            }\n            const data = await response.json();\n            return { materialCode, data };\n        })\n    );\n\n    const resolvedEntries = [];\n\n    for (const result of results) {\n        if (result.status !== 'fulfilled') continue;\n\n        const { materialCode, data } = result.value;\n        if (!data.result || !data.payload?.swatch) continue;\n\n        const swatch = data.payload.swatch;\n        if (isSwatchInBasket(swatch.urlname)) continue;\n\n        resolvedEntries.push({\n            value: JSON.stringify({ colour: swatch.urlname }),\n            title: swatch.title,\n            longTitle: swatch.long_title || swatch.title,\n            categoryName:\n                swatch.material_global_name ||\n                swatch.colour_category_name ||\n                '',\n            url: '/swatch/about?swatch=' + swatch.id,\n            backgroundCSS: swatch.hex_background_css || '',\n            categoryClass: swatch.colour_category_class || '',\n            hex: swatch.hex || '',\n            imageHtml: swatch.image_html || '',\n            prices: '',\n            leadTime: '',\n            colourCode: capturedColourCode,\n            materialCode: materialCode,\n        });\n    }\n\n    if (resolvedEntries.length === 0) {\n        if (addBtn) {\n            addBtn.disabled = false;\n            addBtn.textContent = 'Add 0 swatches';\n        }\n        return;\n    }\n\n    const added = [];\n    const needsReplace = [];\n\n    for (const entry of resolvedEntries) {\n        const current = getSwatches();\n        if (current.length < MAX_SWATCHES) {\n            current.push(entry);\n            saveSwatches(current);\n            added.push(entry);\n        } else {\n            needsReplace.push(entry);\n        }\n    }\n\n    if (needsReplace.length > 0) {\n        const { SwatchReplace } = await import('./swatch/SwatchReplace.js');\n        document.addEventListener(\n            'swatch-journey:replaced',\n            () => {\n                updateAddButton();\n                renderBasket();\n            },\n            { once: true }\n        );\n        new SwatchReplace(needsReplace, 'swatch-journey:replaced', () => {\n            Dialog.close(() => {\n                Dialog.close();\n            });\n        });\n    } else {\n        renderBasket();\n        Dialog.close();\n    }\n};\n\n// ── Event listeners ──\n\n// Only initialise if we're on the swatch journey page\nif (basketSlots && basketCount && basketForm && basketInput && continueBtn) {\n    // Colour swatch clicks\n    document.querySelectorAll('.swatch-journey__colour').forEach(btn => {\n        btn.addEventListener('click', () => {\n            openMaterialsOverlay(btn.dataset.colourCode);\n        });\n    });\n\n    // Basket form submit\n    basketForm.addEventListener('submit', e => {\n        if (getSwatches().length === 0) {\n            e.preventDefault();\n        }\n    });\n\n    // Initial render\n    renderBasket();\n}\n"],"mappings":"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"}