| Server IP : 65.108.144.40 / Your IP : 216.73.217.165 Web Server : Apache/2.4.52 (Ubuntu) System : Linux ubuntu-8gb-hel1-1 5.15.0-173-generic #183-Ubuntu SMP Fri Mar 6 13:29:34 UTC 2026 x86_64 User : dev ( 1000) PHP Version : 8.2.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /var/www/html/coopermain/wp-content/themes/cooper/vue/ |
Upload File : |
<template>
<div class="tyre-wizard">
<div v-if="currentStep !== 5" class="tyre-wizard-header">
<div class="content">
<a :href="siteUrl" class="tyre-wizard-header-logo"></a>
<div class="tyre-wizard-nav">
<ul class="tyre-wizard-nav-items">
<li
class="tyre-wizard-nav-item-single"
:class="currentStep == 1 ? 'active' : ''"
>
<span>Step One</span>
<span class="step-name"> Off Road Frequency </span>
</li>
<li
class="tyre-wizard-nav-item-single"
:class="currentStep == 2 ? 'active' : ''"
>
<span>Step Two</span>
<span class="step-name"> Adventure Type </span>
</li>
<li
class="tyre-wizard-nav-item-single"
:class="currentStep == 3 ? 'active' : ''"
>
<span>Step Three</span>
<span class="step-name"> Towing Capacity </span>
</li>
<li
class="tyre-wizard-nav-item-single"
:class="currentStep == 4 ? 'active' : ''"
>
<span>Step Four</span>
<span class="step-name"> Tyre Size </span>
</li>
</ul>
</div>
</div>
</div>
<template v-if="currentStep == 5">
<div class="tyre-wizard-results-header">
<svg
width="1440"
height="370"
viewBox="0 0 1440 370"
xmlns="http://www.w3.org/2000/svg"
class="icon"
>
<path
d="M0-20h1440v390s-356-17.571-720-17.571S0 370 0 370V-20z"
></path>
</svg>
<div class="tyre-wizard-results-header-logo">
<a :href="siteUrl" class=""></a>
</div>
</div>
</template>
<div class="tyre-wizard-step">
<div v-for="data in getCurrentStepData" :key="data.stepNumber">
<div
class="step-subtitle"
:class="currentStep == 5 ? 'results-header' : ''"
>
{{ data.stepSubtitle }}
</div>
<div
class="step-title"
:class="currentStep == 5 ? 'results-header' : ''"
>
{{ data.stepTitle }}
</div>
<div class="step-subtitle" v-if="data.stepInstructions">
{{ data.stepInstructions }}
</div>
<div
class="step-options"
v-if="currentStep !== 5"
:class="currentStep === 3 ? 'two-columns' : ''"
>
<div
v-for="value in data.stepValues"
:key="value.value"
class="option-single"
:class="[value.valueIconType, getActiveClass(value.value)]"
@click="
handleStepValue(value.value);
toggleActive(value.value);
"
>
<div class="step-icon" v-if="value.valueIconType == 'text'">
<div class="subtitle">
{{ value.valueIconSubtitle }}
<span class="title">{{ value.valueIconTitle }}</span>
</div>
<div class="description">{{ value.valueDescription }}</div>
</div>
<div class="step-icon" v-if="value.valueIconType == 'icon'">
<div
class="icon-single"
:class="[value.valueIconTitle, value.valueIconType]"
></div>
<div class="description icon-description">
{{ value.valueDescription }}
</div>
</div>
</div>
<template v-if="currentStep == 4">
<size-finder @fitment-set="setFitment" tyreWizard />
</template>
</div>
</div>
<div class="wizard-results grid-container" v-if="currentStep == 5">
<div
v-for="product in productData.slice(0, 5)"
:key="product.title"
class="sorted-product"
>
<div class="left-side">
<img :src="product.image[0]" />
<span class="product-title">{{ product.title }}</span>
</div>
<div class="right-side">
<span class="product-compatible" v-if="product.compatible">
Compatible size Found
</span>
<span class="product-compatible check-size" v-else>
check our size options
</span>
<!-- <span v-html="product.price" v-if="product.compatible"></span>-->
<span class="product-learn-more"
><a :href="product.link" target="_blank"></a>Learn More</span
>
</div>
</div>
<a
class="results-control see-all-products"
href="/product-category/4x4-tyres/"
>
<span>See all our 4x4 Tyres</span>
</a>
<div class="results-control restart-wizard" @click="reset()">
<span>Restart 4x4 wizard</span>
</div>
</div>
</div>
<div class="tyre-wizard-footer">
<div class="content grid-container">
<button
class="button-back"
:class="currentStep == 1 ? 'disabled' : ''"
@click="prevStep()"
>
Back
</button>
<button
class="button-next"
:class="
currentData[currentStep] == undefined ||
currentData[currentStep].length == 0
? 'disabled'
: ''
"
@click="nextStep()"
>
Next
</button>
</div>
</div>
</div>
</template>
<script>
import SizeFinder from "./sizeFinder.vue";
export default {
components: { SizeFinder },
props: {
siteUrl: String,
},
data: function () {
return {
currentStep: 1,
totalSteps: 5,
currentData: {
1: "",
2: [],
3: "",
4: "",
},
active: "",
productData: "",
wizardData: {
steps: [
{
stepNumber: 1,
stepSubtitle: "Off road frequency",
stepTitle: "How often do you go off road",
stepValues: [
{
valueIconType: "text",
valueIconTitle: "year",
valueIconSubtitle: "2x",
valueDescription: "Twice a year",
value: 1,
},
{
valueIconType: "text",
valueIconTitle: "year",
valueIconSubtitle: "12x",
valueDescription: "Once a month",
value: 2,
},
{
valueIconType: "text",
valueIconTitle: "year",
valueIconSubtitle: "52x",
valueDescription: "Every Weekend",
value: "touring",
},
{
valueIconType: "text",
valueIconTitle: "year",
valueIconSubtitle: "365x",
valueDescription: "Everyday/ Competition",
value: "touring+",
},
],
},
{
stepNumber: 2,
stepSubtitle: "Off road experiences",
stepTitle: "What are your most common offroad experiences",
stepInstructions: "(pick up to two)",
stepValues: [
{
valueIconType: "icon",
valueIconTitle: "sand",
valueDescription: "Sand",
value: "sand",
},
{
valueIconType: "icon",
valueIconTitle: "mud",
valueDescription: "Mud",
value: "mud",
},
{
valueIconType: "icon",
valueIconTitle: "dirt",
valueDescription: "Dirt/Gravel",
value: "dirt/gravel",
},
{
valueIconType: "icon",
valueIconTitle: "rock",
valueDescription: "Rock",
value: "rock",
},
],
},
{
stepNumber: 3,
stepSubtitle: "towing capacity",
stepTitle: "Will you be towing a trailer",
stepValues: [
{
valueIconType: "icon",
valueIconTitle: "cross",
valueDescription: "No",
value: 1,
},
{
valueIconType: "icon",
valueIconTitle: "tick",
valueDescription: "Yes",
value: "towing",
},
],
},
{
stepNumber: 4,
stepSubtitle: "size",
stepTitle: "What Tyre Size is your vehicle?",
},
{
stepNumber: 5,
stepSubtitle: "results",
stepTitle: "Tyres recommended for you",
},
],
},
};
},
methods: {
// Populate currentData, supports assignment and deletion for values which are toggleable based off currentStep
handleStepValue: function (value) {
// Handle single input steps
if (this.currentStep !== 2) {
let x = {};
x[this.currentStep] = value;
Object.assign(this.currentData, x);
}
// Step 2 allows for multiple values
else {
let choiceArray =
this.currentData[this.currentStep] == undefined
? []
: this.currentData[this.currentStep];
// If data has not been set
if (choiceArray.length == 0) {
choiceArray.push(value);
this.currentData[this.currentStep] = [...new Set(choiceArray)];
} else {
// if the value already exists in the array, remove it
if (choiceArray.includes(value)) {
choiceArray = choiceArray.filter((x) => {
return x !== value;
});
this.currentData[this.currentStep] = [...new Set(choiceArray)];
} else if (choiceArray.length < 2) {
choiceArray.push(value);
this.currentData[this.currentStep] = [...new Set(choiceArray)];
}
}
}
},
// Toggle the currently selected element classes for a step
toggleActive(value) {
// If we need multiple active elements, currently only utilised on step 2
if (this.currentStep == 2) {
// If both value and step data are empty set active as empty array
if (
value == undefined &&
this.currentData[this.currentStep] == undefined
) {
this.active = [];
}
// Otherwise, set our active array to existing data
if (this.currentData[this.currentStep] !== undefined) {
this.active = this.currentData[this.currentStep];
}
}
// Single active element
else {
if (value !== undefined) {
this.active = value;
}
}
},
// Step forwards 1 step, unless user is on the final step
nextStep() {
if (
this.currentData[this.currentStep] == undefined ||
this.currentData[this.currentStep].length == 0
) {
return;
}
if (this.currentStep < this.totalSteps) {
this.currentStep++;
this.toggleActive(this.currentData[this.currentStep]);
this.top();
}
},
// Step backwards 1 step, unless user is on first step
prevStep() {
if (this.currentStep !== 1) {
this.currentStep--;
this.toggleActive(this.currentData[this.currentStep]);
this.top();
}
},
// Pass emitted data from child size-finder component and trigger compatibility check
setFitment(fitment) {
this.handleStepValue(fitment);
this.toggleActive(fitment);
this.checkCompatibility();
this.filteredProducts();
this.currentStep++;
this.top();
},
// Toggle element class based on current active data
getActiveClass(value) {
if (this.currentStep == 2) {
if (this.active.includes(value)) return "active";
} else if (value == this.active) {
return "active";
} else {
return "";
}
},
// Loop over each product and compare to current selected value
checkCompatibility() {
this.productData.forEach((x) => {
x.compatible = false;
x.sizes.forEach((y) => {
if (y == this.currentData[4]) {
x.compatible = true;
return;
}
});
});
},
// Loop over our products and assign a score based on input
filteredProducts() {
this.productData.forEach((x) => {
let score = 0;
x.ratings.forEach((y) => {
// @TODO fix this stupid hack - will need to refactor active handling based off data.value
if (
(y == "touring" && this.currentData[1] == "touring") ||
(y == "touring" && this.currentData[1] == "touring+")
) {
score++;
}
if (y == this.currentData[2][0]) {
score++;
}
if (y == this.currentData[2][1]) {
score++;
}
if (y == this.currentData[3]) {
score += 5;
}
x.score = score;
});
});
// attempt to sort current product array based off score and compatibility
this.productData.sort((a, b) => {
if (a.compatible !== b.compatible) {
if (b.compatible) return 1;
if (!b.compatible) return -1;
}
if (a.compatible == b.compatible) {
return b.score - a.score;
}
});
},
// Reset tyre wizard data
reset() {
this.currentStep = 1;
this.active = "";
this.currentData = {
1: "",
2: [],
3: "",
4: "",
};
},
// Helper to scroll to top of wizard
top() {
document.querySelector(".tyre-wizard").scrollTo(0, 0);
},
},
computed: {
getCurrentStepData() {
return this.wizardData.steps.filter((x) => {
return x.stepNumber == this.currentStep;
});
},
},
mounted: function () {
this.fetch = Promise.all([
fetch("/wp-json/cooper/v1/wizardProducts", {
method: "GET",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
accept: "application/json",
},
}).then((response) => {
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
return response.json();
}),
]).then((results) => {
let formattedResults = JSON.parse(results);
formattedResults.forEach((x) => {
// Remove " | " and split results to an array
x.ratings = x.ratings.replace(/ \| /g, ",").split(",");
// set base compatible value to access later
x.compatible = false;
// convert object to array to map over later
x.sizes = Object.values(x.sizes).map((y) => {
return y;
});
});
this.productData = formattedResults;
});
},
watch: {},
};
</script>