{"id":20,"date":"2025-02-24T09:08:26","date_gmt":"2025-02-24T09:08:26","guid":{"rendered":"https:\/\/dev.haico.cc\/?page_id=20"},"modified":"2025-03-07T14:31:25","modified_gmt":"2025-03-07T14:31:25","slug":"bike-configurator","status":"publish","type":"page","link":"https:\/\/dev.haico.cc\/index.php\/bike-configurator\/","title":{"rendered":"Bike configurator"},"content":{"rendered":"    <div id=\"bike-configurator\">\n        <h2>Customize Your Bike<\/h2>\n\n        <!-- Main Layout -->\n        <div id=\"configurator-layout\">\n            <!-- Left Sidebar: Selected Specs -->\n            <div id=\"selected-specs\">\n                <h3>Selected Components<\/h3>\n                <ul id=\"selected-components\"><\/ul>\n                <p><strong>Total Price:<\/strong> <span id=\"total-price\">$0<\/span><\/p>\n                <p><strong>Total Weight:<\/strong> <span id=\"total-weight\">0 kg<\/span><\/p>\n            <\/div>\n\n            <!-- Center: Bike Preview -->\n            <div id=\"preview-container\">\n                <div id=\"bike-preview\">\n                    <img decoding=\"async\" id=\"frame-layer\" class=\"layer\" src=\"\" alt=\"Bike Frame\" style=\"position: absolute; z-index: 8;\">\n                <\/div>\n\n                <!-- Tabs Navigation -->\n                <ul id=\"configurator-tabs\">\n                    <li class=\"tab active\" data-step=\"frames\">Frame<\/li>\n                    <li class=\"tab\" data-step=\"groupsets\">Groupset<\/li>\n                    <li class=\"tab\" data-step=\"wheels\">Wheels<\/li>\n                    <li class=\"tab\" data-step=\"tyres\">Tyres<\/li>\n                    <li class=\"tab\" data-step=\"stems\">Stem<\/li>\n                    <li class=\"tab\" data-step=\"handlebars\">Handlebars<\/li>\n                    <li class=\"tab\" data-step=\"seatposts\">Seatpost<\/li>\n                    <li class=\"tab\" data-step=\"saddles\">Saddle<\/li>\n                    <li class=\"tab\" data-step=\"summary\">Summary<\/li>\n                    <li class=\"tab\" data-step=\"save-email\">Save & Email<\/li>\n                <\/ul>\n\n                <!-- Dynamic Step Content -->\n                <div id=\"step-content\"><\/div>\n            <\/div>\n\n            <!-- Right Sidebar: Available Options -->\n            <div id=\"options-panel\">\n                <h3>Available Options<\/h3>\n                <div id=\"component-options\"><\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n   <script>\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n    let currentStep = \"frames\";\n    let selectedComponents = {};\n    let totalPrice = 0;\n    let totalWeight = 0;\n\n    function loadStep(step) {\n        document.getElementById(\"step-content\").innerHTML = `<p>Loading ${step} options...<\/p>`;\n\n        fetch(\"https:\/\/dev.haico.cc\/wp-admin\/admin-ajax.php?action=get_step_options&step=\" + step)\n            .then(response => response.json())\n            .then(data => {\n                let optionsHTML = `<label>Select ${step}:<\/label><select id=\"select-${step}\">`;\n                optionsHTML += `<option value=\"\">Select an option<\/option>`;\n\n                data.options.forEach(item => {\n                    optionsHTML += `<option value=\"${item.id}\" \n                        data-price=\"${item.price}\" \n                        data-weight=\"${item.weight}\" \n                        data-image=\"${item.image}\" \n                        data-xy='${JSON.stringify(item.xy)}' \n                        data-zindex=\"${item.zIndex}\">${item.name}<\/option>`;\n                });\n\n                optionsHTML += `<\/select>`;\n                document.getElementById(\"component-options\").innerHTML = optionsHTML;\n\n                document.getElementById(`select-${step}`).addEventListener(\"change\", function () {\n                    let selectedOption = this.options[this.selectedIndex];\n                    let componentId = selectedOption.value;\n                    let componentName = selectedOption.text;\n                    let componentPrice = parseFloat(selectedOption.getAttribute(\"data-price\") || 0);\n                    let componentWeight = parseFloat(selectedOption.getAttribute(\"data-weight\") || 0);\n                    let componentImage = selectedOption.getAttribute(\"data-image\");\n                    let componentXY = JSON.parse(selectedOption.getAttribute(\"data-xy\") || \"{}\");\n                    let componentZIndex = selectedOption.getAttribute(\"data-zindex\") || 0;\n\n                    if (componentId) {\n                        selectedComponents[step] = { \n                            id: componentId, \n                            name: componentName, \n                            price: componentPrice, \n                            weight: componentWeight, \n                            image: componentImage, \n                            xy: componentXY, \n                            zIndex: componentZIndex \n                        };\n\n                        updateSummary();\n                        updatePreview(step, componentImage, componentXY, componentZIndex);\n                    }\n                });\n            });\n    }\n\n    function updateSummary() {\n        let summaryHTML = \"\";\n        totalPrice = 0;\n        totalWeight = 0;\n\n        Object.keys(selectedComponents).forEach(step => {\n            summaryHTML += `<li>${selectedComponents[step].name} - $${selectedComponents[step].price}, ${selectedComponents[step].weight}kg<\/li>`;\n            totalPrice += selectedComponents[step].price;\n            totalWeight += selectedComponents[step].weight;\n        });\n\n        document.getElementById(\"selected-components\").innerHTML = summaryHTML;\n        document.getElementById(\"total-price\").innerText = `$${totalPrice.toFixed(2)}`;\n        document.getElementById(\"total-weight\").innerText = `${totalWeight.toFixed(2)} kg`;\n    }\n\n    function updatePreview(component, imageUrl, xy, zIndex) {\n        if (!imageUrl) return;\n\n        \/\/ Remove old component image of the same type\n        document.querySelectorAll(`.${component}-layer`).forEach(el => el.remove());\n\n        let imgElement = document.createElement(\"img\");\n        imgElement.src = imageUrl;\n        imgElement.className = `${component}-layer`;\n        imgElement.style.position = \"absolute\";\n        imgElement.style.left = (xy.x || 0) + \"px\";\n        imgElement.style.top = (xy.y || 0) + \"px\";\n        imgElement.style.zIndex = zIndex;\n\n        document.getElementById(\"bike-preview\").appendChild(imgElement);\n    }\n\n    document.querySelectorAll(\".tab\").forEach(tab => {\n        tab.addEventListener(\"click\", function () {\n            document.querySelectorAll(\".tab\").forEach(t => t.classList.remove(\"active\"));\n            this.classList.add(\"active\");\n\n            currentStep = this.getAttribute(\"data-step\");\n            loadStep(currentStep);\n        });\n    });\n\n    loadStep(currentStep);\n});\n<\/script>\n    <p><\/p>","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"full-wid","meta":{"footnotes":""},"class_list":["post-20","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/dev.haico.cc\/index.php\/wp-json\/wp\/v2\/pages\/20","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev.haico.cc\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/dev.haico.cc\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/dev.haico.cc\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.haico.cc\/index.php\/wp-json\/wp\/v2\/comments?post=20"}],"version-history":[{"count":3,"href":"https:\/\/dev.haico.cc\/index.php\/wp-json\/wp\/v2\/pages\/20\/revisions"}],"predecessor-version":[{"id":29,"href":"https:\/\/dev.haico.cc\/index.php\/wp-json\/wp\/v2\/pages\/20\/revisions\/29"}],"wp:attachment":[{"href":"https:\/\/dev.haico.cc\/index.php\/wp-json\/wp\/v2\/media?parent=20"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}