diff --git a/assets/css/styles.css b/assets/css/styles.css index 2082053..cc049e0 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -2017,10 +2017,6 @@ select { bottom: 100%; } -.left-0 { - left: 0px; -} - .left-2 { left: 0.5rem; } @@ -2777,6 +2773,11 @@ html { background-color: rgb(89 10 12/var(--tw-bg-opacity)); } +.hover\:bg-stone-300:hover { + --tw-bg-opacity: 1; + background-color: rgb(214 211 209/var(--tw-bg-opacity)); +} + .hover\:bg-stone-500:hover { --tw-bg-opacity: 1; background-color: rgb(120 113 108/var(--tw-bg-opacity)); @@ -2787,21 +2788,6 @@ html { background-color: rgb(87 83 78/var(--tw-bg-opacity)); } -.hover\:bg-stone-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(245 245 244/var(--tw-bg-opacity)); -} - -.hover\:bg-stone-200:hover { - --tw-bg-opacity: 1; - background-color: rgb(231 229 228/var(--tw-bg-opacity)); -} - -.hover\:bg-stone-300:hover { - --tw-bg-opacity: 1; - background-color: rgb(214 211 209/var(--tw-bg-opacity)); -} - .hover\:text-white:hover { --tw-text-opacity: 1; color: rgb(255 255 255/var(--tw-text-opacity)); diff --git a/autocart_assets/css/filter-panel.css b/autocart_assets/css/filter-panel.css index 43a558d..be92b3e 100644 --- a/autocart_assets/css/filter-panel.css +++ b/autocart_assets/css/filter-panel.css @@ -209,7 +209,7 @@ li.mdc-list-item:hover { #slide-out-filters{ transition: 300ms ease-in-out; - translate: -100%; + /* translate: -100%; */ } @@ -238,4 +238,12 @@ li.mdc-list-item:hover { .sticky-container{ position: static; } +/* + #applied-filters-container{ + position: fixed; + bottom: 0px; + z-index: 50; + width: 100%; + right: 0; + } */ } \ No newline at end of file diff --git a/autocart_assets/js/FinanceForm.js b/autocart_assets/js/FinanceForm.js index 6c94fda..9bf1c3e 100644 --- a/autocart_assets/js/FinanceForm.js +++ b/autocart_assets/js/FinanceForm.js @@ -1,523 +1,555 @@ class FinanceForm { - constructor(vehicle,appointmentForm, notifyParentCallback) { - this.notifyParentCallback = notifyParentCallback; - this.inputs = [ - 'loanTerm', - 'intRate', - 'downPayment', - 'tradeValue', - 'paymentFrequency', - 'rate', - 'customRateValue', - ]; - this.modalDiv = null; - this.name = 'financeForm'; - this.appointmentForm = appointmentForm; - this.frequencyMap = { - 12: 'Monthly', - 26: 'Bi-Weekly', - 52: 'Weekly', - }; - - this.vehicle = vehicle; - - // Default values - this.loanTerm = 12; - this.intRate = 7.99; - this.downPayment = 0; - this.tradeValue = 0; - this.paymentFrequency = 26; - - // Check if values exist in localStorage, and if so, override default values - const storedValues = - JSON.parse(localStorage.getItem(`autocart_${this.name}`)) || {}; - if (storedValues) { - this.loanTerm = parseInt(storedValues.loanTerm) || this.loanTerm; - this.intRate = parseFloat(storedValues.customRateValue) || this.intRate; - this.downPayment = parseInt(storedValues.downPayment) || this.downPayment; - this.tradeValue = parseInt(storedValues.tradeValue) || this.tradeValue; - this.paymentFrequency = - parseInt(storedValues.paymentFrequency) || this.paymentFrequency; - } - - // Calculate other values based on the provided vehicle and overridden inputs - let amount = parseFloat(this.vehicle.advertise_price) || 0; - let months = parseFloat(this.loanTerm) || 0; - let down = parseFloat(this.downPayment) || 0; - let trade = parseFloat(this.tradeValue) || 0; - let totalDown = down + trade; - let annInterest = parseFloat(this.intRate) || 0; - let monInt = annInterest / 1200; - let financeTotal = amount - totalDown; - let numberOfPayments = months / (12 / this.paymentFrequency); - - // Fix calculation for total cost of credit - let interest = financeTotal * monInt * numberOfPayments; - this.totalCostOfCredit = interest.toFixed(2); - - this.totalObligation = ( - financeTotal + parseFloat(this.totalCostOfCredit) - ).toFixed(2); - - this.payment = - ( - (monInt + monInt / (Math.pow(1 + monInt, months) - 1)) * - (amount - (totalDown || 0)) - ).toFixed(2) / - (this.paymentFrequency / 12); - - // Notify parent callback with the updated values - this.notifyParentCallback(this); - - // Initialize the form - this.initForm(); - this.initializeFormInputs(); - } - - generateLoanTermOptions(vehicleAge) { - const defaultOptions = [ - { year: 2, terms: [12, 24, 36, 48, 60, 72, 84, 96] }, - { year: 5, terms: [12, 24, 36, 48, 60, 72, 84] }, - { year: 7, terms: [12, 24, 36, 48, 60, 72] }, - { year: 8, terms: [12, 24, 36, 48, 60] }, - { year: 10, terms: [12, 24, 36, 48] } + constructor(vehicle,appointmentForm, notifyParentCallback) { + this.notifyParentCallback = notifyParentCallback; + this.inputs = [ + 'loanTerm', + 'intRate', + 'downPayment', + 'tradeValue', + 'paymentFrequency', + 'rate', + 'customRateValue', ]; + this.modalDiv = null; + this.name = 'financeForm'; + this.appointmentForm = appointmentForm; + this.frequencyMap = { + 12: 'Monthly', + 26: 'Bi-Weekly', + 52: 'Weekly', + }; - const selectedOptions = defaultOptions.find(option => vehicleAge <= option.year); - - if (selectedOptions) { - const optionsHTML = selectedOptions.terms.map(term => ``).join('\n'); - return optionsHTML; - } else { - return ''; + if (!vehicle.advertise_price) { + vehicle['advertise_price'] = 0; + this.inputs.push('advertise_price') } - } - - - initForm() { - // console.log('initForm') - this.modalDiv = document.createElement('div'); - const currentYear = new Date().getFullYear(); - const vehicleYear = this.vehicle.year; - const vehicleAge = currentYear - vehicleYear; - const loanTermOptions = this.generateLoanTermOptions(vehicleAge); - // const modalDiv = document.createElement('div'); - this.modalDiv.innerHTML = ` -
-
- - - - -
- -
- - -
-

Let’s Structure a Deal That Works For You

-

- We understand that purchasing a vehicle is a big decision, so we want you to be paying a price that you’re comfortable with. - Let’s structure a deal that works for you below: -

- - -
Finance Option
-

- ${this.payment} / ${this.frequencyMap[this.paymentFrequency]} -

-

${this.intRate}% APR for ${this.loanTerm} Months

-
- -
-
-
+ this.vehicle = vehicle; + + // Default values + this.loanTerm = 12; + this.intRate = 7.99; + this.downPayment = 0; + this.tradeValue = 0; + this.paymentFrequency = 26; + + // Check if values exist in localStorage, and if so, override default values + const storedValues = + JSON.parse(localStorage.getItem(`autocart_${this.name}`)) || {}; + if (storedValues) { + this.loanTerm = parseInt(storedValues.loanTerm) || this.loanTerm; + this.intRate = parseFloat(storedValues.customRateValue) || this.intRate; + this.downPayment = parseInt(storedValues.downPayment) || this.downPayment; + this.tradeValue = parseInt(storedValues.tradeValue) || this.tradeValue; + this.paymentFrequency = + parseInt(storedValues.paymentFrequency) || this.paymentFrequency; + } + + // Calculate other values based on the provided vehicle and overridden inputs + let amount = parseFloat(this.vehicle.advertise_price) || 0; + let months = parseFloat(this.loanTerm) || 0; + let down = parseFloat(this.downPayment) || 0; + let trade = parseFloat(this.tradeValue) || 0; + let totalDown = down + trade; + let annInterest = parseFloat(this.intRate) || 0; + let monInt = annInterest / 1200; + let financeTotal = amount - totalDown; + let numberOfPayments = months / (12 / this.paymentFrequency); + + // Fix calculation for total cost of credit + let interest = financeTotal * monInt * numberOfPayments; + this.totalCostOfCredit = interest.toFixed(2); + + this.totalObligation = ( + financeTotal + parseFloat(this.totalCostOfCredit) + ).toFixed(2); + + this.payment = + ( + (monInt + monInt / (Math.pow(1 + monInt, months) - 1)) * + (amount - (totalDown || 0)) + ).toFixed(2) / + (this.paymentFrequency / 12); + + // Notify parent callback with the updated values + this.notifyParentCallback(this); + + // Initialize the form + this.initForm(); + this.initializeFormInputs(); + } + + generateLoanTermOptions(vehicleAge) { + const defaultOptions = [ + { year: 2, terms: [12, 24, 36, 48, 60, 72, 84, 96] }, + { year: 5, terms: [12, 24, 36, 48, 60, 72, 84] }, + { year: 7, terms: [12, 24, 36, 48, 60, 72] }, + { year: 8, terms: [12, 24, 36, 48, 60] }, + { year: 10, terms: [12, 24, 36, 48] } + ]; + + const selectedOptions = defaultOptions.find(option => vehicleAge <= option.year); + + if (selectedOptions) { + const optionsHTML = selectedOptions.terms.map(term => ``).join('\n'); + return optionsHTML; + } else { + return ''; + } +} + + generateAdvertisePriceInput(){ + return (this.vehicle.advertise_price == 0) ? `
+ +
+ + + + +
+
` : ''; + } + + initForm() { + // console.log('initForm') + this.modalDiv = document.createElement('div'); + const currentYear = new Date().getFullYear(); + const vehicleYear = this.vehicle.year || 2024; + const vehicleAge = currentYear - vehicleYear; + const loanTermOptions = this.generateLoanTermOptions(vehicleAge); + const advertise_price = this.generateAdvertisePriceInput() + + // const modalDiv = document.createElement('div'); + this.modalDiv.innerHTML = ` +
+
+ + + + +
+ +
+ + +
+

Let’s Structure a Deal That Works For You

+

+ We understand that purchasing a vehicle is a big decision, so we want you to be paying a price that you’re comfortable with. + Let’s structure a deal that works for you below: +

+ + +
Finance Option
+

+ ${this.payment} / ${this.frequencyMap[this.paymentFrequency]} +

+

${this.intRate}% APR for ${this.loanTerm} Months

+
+ + +
+
-
+
- + -
-
- -
- -
- - - - -
-
-
- - -
-
- - -
-
- - -
-
- 7.99% -
- -
- -
- - -
-
-
-
-

Vehicle Price

-
    -
  • - Vehicle Price - - ${this.vehicle.advertise_price.toLocaleString('en-CA', { style: 'currency', currency: 'CAD', minimumFractionDigits: 0, maximumFractionDigits: 0 })} - -
  • -
-
-
- -
-
    -
  • - Finance Total - - ${this.vehicle.advertise_price.toLocaleString('en-CA', { style: 'currency', currency: 'CAD', minimumFractionDigits: 0, maximumFractionDigits: 0 })} - -
  • -
-
-
-

Finance Payment

-
    -
  • - Loan Term - - ${this.loanTerm} Months - -
  • -
  • - Program Rate - - 7.99% - -
  • -
  • - Frequency - - ${this.frequencyMap[this.paymentFrequency]} - -
  • - -
-
-
-

Total

-
    -
  • - Total Cost of Credit - - ${this.totalCostOfCredit.toLocaleString('en-CA', { style: 'currency', currency: 'CAD', minimumFractionDigits: 0, maximumFractionDigits: 0 })} - -
  • -
  • - Total Obligation - - ${this.totalObligation.toLocaleString('en-CA', { style: 'currency', currency: 'CAD', minimumFractionDigits: 0, maximumFractionDigits: 0 })} - -
  • -
-
- -
-
-
-

- ${(Number(this.payment) || 0).toLocaleString('en-CA', { style: 'currency', currency: 'CAD' })} - / - ${this.frequencyMap[this.paymentFrequency]} - -

-
- -
-
-
-
- `; - - const formContainer = this.modalDiv.querySelector( - '#appointmentFormContainer' - ); - - formContainer.appendChild(this.appointmentForm.initForm()); - - this.initializeTabNavigation(this.modalDiv); - this.initializeFormEventListeners(this.modalDiv); - return this.modalDiv; - } - - // initializeFormInputs() { - // const storedValues = JSON.parse(localStorage.getItem(`autocart_${this.name}`)) || {}; - // // const mergedValues = { ...this.defaultValues, ...storedValues }; - // console.log(storedValues); - // for (const key in storedValues) { - // console.log(key); - - // const inputElement = document.getElementById(key); - // if (inputElement) { - // inputElement.value = storedValues[key]; - // } - // } - // this.updateView() - // } - - initializeFormInputs() { - const storedValues = JSON.parse(localStorage.getItem(`autocart_${this.name}`)) || {}; - const selectElements = document.querySelectorAll('select'); - - for (const key in storedValues) { - const inputElement = document.getElementById(key); - if (inputElement) { - inputElement.value = storedValues[key]; - if (inputElement.tagName.toLowerCase() === 'select') { - const optionValues = Array.from(inputElement.options).map(option => option.value); - const selectedValue = storedValues[key]; +
+
+ + ${advertise_price} + +
+ +
+ + + + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ 7.99% +
+ +
+ +
+ + +
+
+
+
+

Vehicle Price

+
    +
  • + Vehicle Price + + ${this.vehicle.advertise_price.toLocaleString('en-CA', { style: 'currency', currency: 'CAD', minimumFractionDigits: 0, maximumFractionDigits: 0 })} + +
  • +
+
+
+ +
+
    +
  • + Finance Total + + ${this.vehicle.advertise_price.toLocaleString('en-CA', { style: 'currency', currency: 'CAD', minimumFractionDigits: 0, maximumFractionDigits: 0 })} + +
  • +
+
+
+

Finance Payment

+
    +
  • + Loan Term + + ${this.loanTerm} Months + +
  • +
  • + Program Rate + + 7.99% + +
  • +
  • + Frequency + + ${this.frequencyMap[this.paymentFrequency]} + +
  • + +
+
+
+

Total

+
    +
  • + Total Cost of Credit + + ${this.totalCostOfCredit.toLocaleString('en-CA', { style: 'currency', currency: 'CAD', minimumFractionDigits: 0, maximumFractionDigits: 0 })} + +
  • +
  • + Total Obligation + + ${this.totalObligation.toLocaleString('en-CA', { style: 'currency', currency: 'CAD', minimumFractionDigits: 0, maximumFractionDigits: 0 })} + +
  • +
+
+ +
+
+
+

+ ${(Number(this.payment) || 0).toLocaleString('en-CA', { style: 'currency', currency: 'CAD' })} + / + ${this.frequencyMap[this.paymentFrequency]} + +

+
+ +
+
+ + + `; + + const formContainer = this.modalDiv.querySelector( + '#appointmentFormContainer' + ); + + formContainer.appendChild(this.appointmentForm.initForm()); - const formValues = {}; - - this.inputs.forEach((input) => { - const inputElement = document.getElementById(input); - if (inputElement) { - formValues[input] = inputElement.value; - } - }); - - if (formValues['rate'] == 'default-rate') { - formValues['customRateValue'] = 7.99; + this.initializeTabNavigation(this.modalDiv); + this.initializeFormEventListeners(this.modalDiv); + return this.modalDiv; } - - localStorage.setItem(`autocart_${this.name}`, JSON.stringify(formValues)); + + // initializeFormInputs() { + // const storedValues = JSON.parse(localStorage.getItem(`autocart_${this.name}`)) || {}; + // // const mergedValues = { ...this.defaultValues, ...storedValues }; + // console.log(storedValues); + // for (const key in storedValues) { + // console.log(key); + + // const inputElement = document.getElementById(key); + // if (inputElement) { + // inputElement.value = storedValues[key]; + // } + // } + // this.updateView() + // } + + initializeFormInputs() { + const storedValues = JSON.parse(localStorage.getItem(`autocart_${this.name}`)) || {}; + const selectElements = document.querySelectorAll('select'); + + for (const key in storedValues) { + const inputElement = document.getElementById(key); + if (inputElement) { + inputElement.value = storedValues[key]; + if (inputElement.tagName.toLowerCase() === 'select') { + const optionValues = Array.from(inputElement.options).map(option => option.value); + const selectedValue = storedValues[key]; + + if (!optionValues.includes(selectedValue)) { + const closestValue = optionValues.reduce((a, b) => Math.abs(b - selectedValue) < Math.abs(a - selectedValue) ? b : a); + inputElement.value = closestValue; + } + } + inputElement.dispatchEvent(new Event('input')); + } + } + this.updateView(); +} + + calculatePayments() { + + var vehiclePrice = this.vehicle.advertise_price; + if(this.inputs.includes('advertise_price')){ + vehiclePrice = document.getElementById('advertise_price').value; + } + this.loanTerm = document.getElementById('loanTerm').value; + this.paymentFrequency = document.getElementById('paymentFrequency').value; + this.intRate = document.getElementById('rate').value == 'default-rate' + ? 7.99 + : document.getElementById('customRateValue').value; + this.downPayment = document.getElementById('downPayment').value; + this.tradeValue = document.getElementById('tradeValue').value; + var amount = parseFloat(vehiclePrice) || 0, + months = parseFloat(this.loanTerm) || 0, + down = parseFloat(this.downPayment) || 0, + trade = parseFloat(this.tradeValue) || 0, + totalDown = down + trade, + annInterest = parseFloat(this.intRate) || 0, + monInt = annInterest / 1200; + var financeTotal = amount - totalDown; + var numberOfPayments = months / (12 / this.paymentFrequency); + + var monthlyPayment = + ( + (monInt + monInt / (Math.pow(1 + monInt, months) - 1)) * + (amount - (totalDown || 0)) + ).toFixed(2) / + (this.paymentFrequency / 12); + this.totalCostOfCredit = ( + monthlyPayment * numberOfPayments - + financeTotal + ).toFixed(2); + this.totalObligation = ( + parseFloat(this.totalCostOfCredit) + parseFloat(financeTotal) + ).toFixed(2); + this.payment = + ( + (monInt + monInt / (Math.pow(1 + monInt, months) - 1)) * + (amount - (totalDown || 0)) + ).toFixed(2) / + (this.paymentFrequency / 12); + + this.updateView(); + } + + updateView() { + ['default-rate', 'custom-rate'].forEach((el) => { + document.getElementById(el)?.classList?.add('hidden'); + }); + if(document.getElementById('rate')){ + document.getElementById(document.getElementById('rate').value) + .classList.remove('hidden'); + } + + + if (document.querySelectorAll('.loanTermSpan').length) { + document.querySelectorAll('.loanTermSpan').forEach((el) => { + el.innerHTML = `${this.loanTerm}`; + }); + } + + if (document.querySelectorAll('.rateSpan').length) { + document.querySelectorAll('.rateSpan').forEach((el) => { + el.innerHTML = `${this.intRate}`; + }); + } + + if (document.querySelectorAll('.paymentSpan').length) { + document.querySelectorAll('.paymentSpan').forEach((el) => { + el.innerHTML = (Number(this.payment) || 0).toLocaleString('en-CA', { + style: 'currency', + currency: 'CAD', + }); + }); + } + + if (document.querySelectorAll('.paymentFrequencySpan').length) { + document.querySelectorAll('.paymentFrequencySpan').forEach((el) => { + el.innerHTML = this.frequencyMap[this.paymentFrequency]; + }); + } + + if (document.querySelectorAll('.totalCostOfCreditSpan').length) { + document.querySelectorAll('.totalCostOfCreditSpan').forEach((el) => { + el.innerHTML = (Number(this.totalCostOfCredit) || 0).toLocaleString( + 'en-CA', + { style: 'currency', currency: 'CAD' } + ); + }); + } + + if (document.querySelectorAll('.advertisePriceSpan').length) { + document.querySelectorAll('.advertisePriceSpan').forEach((el) => { + el.innerHTML = (Number(document.getElementById('advertise_price').value) || 0).toLocaleString( + 'en-CA', + { style: 'currency', currency: 'CAD' } + ); + }); + } + + + + if (document.querySelectorAll('.totalObligationSpan').length) { + document.querySelectorAll('.totalObligationSpan').forEach((el) => { + el.innerHTML = (Number(this.totalObligation) || 0).toLocaleString( + 'en-CA', + { style: 'currency', currency: 'CAD' } + ); + }); } } - \ No newline at end of file + + goToNextTab() { + let tab1 = document.querySelector('[data-tab="tab1"]'); + let tab2 = document.querySelector('[data-tab="tab2"]'); + let backButton = document.getElementById('next-step'); + + if (tab1 && tab2 && backButton) { + if (tab1.classList.contains('active')) { + // Switch to tab2 and update button text to "Back" + tab2.click(); + backButton.innerText = 'Back'; + } else if (tab2.classList.contains('active')) { + // Switch to tab1 and update button text to "Next step" + tab1.click(); + backButton.innerText = 'Next step'; + } + } + } + + initializeTabNavigation(modalDiv) { + const tabLinks = modalDiv.querySelectorAll('.tab-link'); + const tabContents = modalDiv.querySelectorAll('.tab-content'); + let nextStepButton = modalDiv.querySelector('#next-step'); + if (nextStepButton) { + nextStepButton.addEventListener('click', this.goToNextTab.bind(this)); + } + tabLinks.forEach(function (tabLink) { + tabLink.addEventListener('click', function (event) { + event.preventDefault(); + + tabLinks.forEach(function (link) { + link.classList.remove('active', 'bg-gray-600', 'text-white'); + }); + tabContents.forEach(function (content) { + content.classList.add('hidden'); + }); + + const targetTab = this.getAttribute('data-tab'); + this.classList.add('active', 'bg-gray-600', 'text-white'); + + let backButtonTexts = { tab1: 'Next Step', tab2: 'Back To Options' }; + nextStepButton.innerText = backButtonTexts[targetTab]; + modalDiv + .querySelector(`.tab-content[data-content="${targetTab}"]`) + .classList.remove('hidden'); + }); + }); + } + + initializeFormEventListeners(modalDiv) { + + + this.inputs.forEach((id) => { + const inputElement = modalDiv.querySelector(`#${id}`); + if (inputElement) { + inputElement.addEventListener('input', () => { + this.calculatePayments(); + this.saveFormValues(); // Save form values whenever an input changes + }); + } + }); + } + + saveFormValues() { + + const formValues = {}; + + this.inputs.forEach((input) => { + const inputElement = document.getElementById(input); + if (inputElement) { + formValues[input] = inputElement.value; + } + }); + + if (formValues['rate'] == 'default-rate') { + formValues['customRateValue'] = 7.99; + } + + localStorage.setItem(`autocart_${this.name}`, JSON.stringify(formValues)); + } +} diff --git a/autocart_assets/js/index.js b/autocart_assets/js/index.js index 95e147c..b707a9e 100644 --- a/autocart_assets/js/index.js +++ b/autocart_assets/js/index.js @@ -10,329 +10,296 @@ let shouldUpdateFilters = true; let modelFilter = []; let makeFilters; function sendReq() { - var formData = { - action: 'handle_autocart_form', - minPrice: price.getValueStart(), - maxPrice: price.getValue(), - minKilometres: kilometres.getValueStart(), - maxKilometres: kilometres.getValue(), - minYear: year.getValueStart(), - maxYear: year.getValue(), - autocart_nonce: jQuery('#autocart_nonce').val(), - }; - const vehiclesContainer = document.querySelector('.vehicles-container'); - // vehiclesContainer.textContent = 'Loading...'; - // Add skeleton cards to the vehicles container - for (let i = 0; i < 6; i++) { - const skeletonCard = createSkeletonCard(); - vehiclesContainer.appendChild(skeletonCard); - } + var formData = { + 'action': 'handle_autocart_form', + 'minPrice': price.getValueStart(), + 'maxPrice': price.getValue(), + 'minKilometres': kilometres.getValueStart(), + 'maxKilometres': kilometres.getValue(), + 'minYear': year.getValueStart(), + 'maxYear': year.getValue(), + 'autocart_nonce': jQuery('#autocart_nonce').val(), + }; + const vehiclesContainer = document.querySelector('.vehicles-container'); + // vehiclesContainer.textContent = 'Loading...'; + // Add skeleton cards to the vehicles container + for (let i = 0; i < 6; i++) { + const skeletonCard = createSkeletonCard(); + vehiclesContainer.appendChild(skeletonCard); + } - const filtersContainer = document.querySelector('.make-container'); - for (let i = 0; i < 2; i++) { - const skeletonListItem = createSkeletonListItem(); - filtersContainer.appendChild(skeletonListItem); - } - // Add skeleton list item to the filters container - // const skeletonListItem = createSkeletonListItem(); - // filtersContainer.appendChild(skeletonListItem); + const filtersContainer = document.querySelector('.make-container'); + for (let i = 0; i < 2; i++) { + const skeletonListItem = createSkeletonListItem(); + filtersContainer.appendChild(skeletonListItem); + } + // Add skeleton list item to the filters container + // const skeletonListItem = createSkeletonListItem(); + // filtersContainer.appendChild(skeletonListItem); - jQuery.ajax({ - type: 'POST', - url: ajax_object.ajax_url, - data: formData, - success: function (response) { - const vehicles = response.data.vehicles; - if (dataStore) { - dataStore.unsubscribeAll(); - } + jQuery.ajax({ + type: 'POST', + url: ajax_object.ajax_url, + data: formData, + success: function (response) { + const vehicles = response.data.vehicles; + if (dataStore) { + dataStore.unsubscribeAll(); + } - // Initialize new data store - dataStore.vehicles = vehicles; - filterManager = new FilterManager(dataStore); - appliedFilters = new AppliedFilters(dataStore, filterManager); + + // Initialize new data store + dataStore.vehicles = vehicles; + filterManager = new FilterManager(dataStore); + appliedFilters = new AppliedFilters(dataStore, filterManager); - // filterManager = new FilterManager(dataStore); - // appliedFilters = new AppliedFilters(dataStore, filterManager); + // filterManager = new FilterManager(dataStore); + // appliedFilters = new AppliedFilters(dataStore, filterManager); + + shouldUpdateFilters = true; + dataStore.subscribe(filteredVehicles => { + console.log('dataStore has been changed') + handleSuccess(filteredVehicles); + }); - shouldUpdateFilters = true; - dataStore.subscribe((filteredVehicles) => { - console.log('dataStore has been changed'); - handleSuccess(filteredVehicles); - }); - - dataStore.notifySubscribers(vehicles); - }, - error: function (xhr, status, error) { - console.log(xhr.responseText); - console.log('Status: ' + status); - console.log('Error: ' + error); - jQuery('#inventory-search__search-button').text('Error'); - }, - }); + dataStore.notifySubscribers(vehicles); + }, + error: function (xhr, status, error) { + console.log(xhr.responseText); + console.log('Status: ' + status); + console.log('Error: ' + error); + jQuery("#inventory-search__search-button").text("Error"); + } + }); } function handleSuccess(vehicles, updateFilters = shouldUpdateFilters) { - if (updateFilters) { - createMakeList(vehicles); - createBodyTypeList(vehicles); - createTransmissionList(vehicles); - createExteriorList(vehicles); - } - const vehiclesContainer = document.querySelector('.vehicles-container'); - vehiclesContainer.innerHTML = ''; + if(updateFilters){ + createMakeList(vehicles); + createBodyTypeList(vehicles); + createTransmissionList(vehicles); + createExteriorList(vehicles); + } + const vehiclesContainer = document.querySelector('.vehicles-container'); + vehiclesContainer.innerHTML = ''; + + vehicles.forEach(vehicleData => { + const vehicle = new VehicleThumbnail(vehicleData); + // vehiclesContainer.appendChild(vehicle.generateCardHTML()); + vehiclesContainer.appendChild(vehicle.generateCardElement()); - vehicles.forEach((vehicleData) => { - const vehicle = new VehicleThumbnail(vehicleData); - // vehiclesContainer.appendChild(vehicle.generateCardHTML()); - vehiclesContainer.appendChild(vehicle.generateCardElement()); - }); -} - -function createMakeList(vehicles) { - const makeContainer = document.querySelector('.make-container'); - makeContainer.innerHTML = ''; - - const makeCounts = vehicles.reduce((acc, vehicle) => { - const { make } = vehicle; - acc[make] = (acc[make] || 0) + 1; - return acc; - }, {}); - let makeValue = document.querySelector('#autocart-make-field').value; - // if(makeValue){ - // console.log('makeValue',makeValue); - // // dataStore.addFilter('make', makeValue); - // } - makeFilters = Object.entries(makeCounts).map(([make, count]) => { - return filterManager.createMakeFilter( - { - text: make, - checked: makeValue.toLowerCase() === make.toLowerCase(), - count, - models: fetchAvailableModels(vehicles, make), - }, - dataStore - ); - }); - makeFilters.sort((a, b) => a.value.localeCompare(b.value)); - makeFilters.forEach((make) => { - makeContainer.appendChild(make.generateCardHTML()); - make.subscribe((m) => initModelContainer(m)); - }); -} - -function createBodyTypeList(vehicles) { - const bodyTypeContainer = document.querySelector('.body-type-container'); - bodyTypeContainer.innerHTML = ''; - - const bodyType = vehicles.reduce((acc, vehicle) => { - const { body_type } = vehicle; - acc[body_type] = (acc[body_type] || 0) + 1; - return acc; - }, {}); - - filterManager.resetList('body_type'); - - bodyTypeFilters = Object.entries(bodyType).map(([body_type, count]) => - filterManager.createBodyTypeFilter({ text: body_type, count }, dataStore) - ); - bodyTypeFilters.sort((a, b) => a.value.localeCompare(b.value)); - bodyTypeFilters.forEach((body_type) => { - bodyTypeContainer.appendChild(body_type.initCheckbox()); - // body_type.subscribe(m=> iniBodyTypeContainer(m)) - }); -} - -function createTransmissionList(vehicles) { - const transmissionContainer = document.querySelector( - '.transmission-container' - ); - - transmissionContainer.innerHTML = ''; - - const transmission = vehicles.reduce((acc, vehicle) => { - const { transmission_type } = vehicle; - acc[transmission_type] = (acc[transmission_type] || 0) + 1; - return acc; - }, {}); - - filterManager.resetList('transmission_type'); - transmissionFilters = Object.entries(transmission).map( - ([transmission_type, count]) => - filterManager.createTransmissionFilter( - { text: transmission_type, count }, - dataStore - ) - ); - transmissionFilters.sort((a, b) => a.value.localeCompare(b.value)); - transmissionFilters.forEach((transmission) => { - transmissionContainer.appendChild(transmission.initCheckbox()); - }); -} - -function createExteriorList(vehicles) { - console.log(vehicles); - const exteriorContainer = document.querySelector('.exterior-color'); - exteriorContainer.innerHTML = ''; - const exterior = vehicles.reduce((acc, vehicle) => { - const { exterior_color } = vehicle; - acc[exterior_color] = (acc[exterior_color] || 0) + 1; - return acc; - }, {}); - filterManager.resetList('exterior_color'); - - exteriorFilters = Object.entries(exterior).map(([exterior_color, count]) => - filterManager.createExteriorFilter( - { text: exterior_color, count }, - dataStore - ) - ); - exteriorFilters.sort((a, b) => a.value.localeCompare(b.value)); - - exteriorFilters.forEach((exterior) => { - exteriorContainer.appendChild(exterior.initCheckbox()); - }); -} - -function initModelContainer(make) { - let list = [ - ...new Set( - filterManager.makeFilters - .filter((m) => m.checked == true) - .map((m) => m.models) - .flat() - ), - ]; - - const modelContainer = document.querySelector('.model-container'); - if (list.length === 0) { - modelContainer.innerHTML = '

Please Select a Make

'; - } else if (list && list.length > 0) { - modelContainer.innerHTML = ''; - list.sort((a, b) => a.value.localeCompare(b.value)); - list.forEach((model) => { - modelContainer.appendChild(model.initCheckbox()); }); - } else { - modelContainer.innerHTML = '

No models available

'; - } + + } -function initTrimContainer(model) { - let list = [ - ...new Set( - filterManager.modelFilters - .filter((m) => m.checked == true) - .map((m) => m.trims) - .flat() - ), - ]; +function createMakeList(vehicles){ - // const uniqueArray = [...new Set(array)]; - const trimContainer = document.querySelector('.trim-container'); + const makeContainer = document.querySelector('.make-container'); + makeContainer.innerHTML = ''; - if (list.length === 0) { - trimContainer.innerHTML = '

Please Select a Model

'; - } else if (list && list.length > 0) { - trimContainer.innerHTML = ''; - list.sort((a, b) => a.value.localeCompare(b.value)); - list.forEach((trim) => { - trimContainer.appendChild(trim.initCheckbox()); + const makeCounts = vehicles.reduce((acc, vehicle) => { + const { make } = vehicle; + acc[make] = (acc[make] || 0) + 1; + return acc; + }, {}); + let makeValue = document.querySelector('#autocart-make-field').value; + // if(makeValue){ + // console.log('makeValue',makeValue); + // // dataStore.addFilter('make', makeValue); + // } + makeFilters = Object.entries(makeCounts).map(([make, count]) => { + + return filterManager.createMakeFilter({ + text: make, + checked: makeValue.toLowerCase() === make.toLowerCase(), + count, + models: fetchAvailableModels(vehicles, make) + }, dataStore); }); - } else { - trimContainer.innerHTML = '

No trims available

'; - } + makeFilters.sort((a, b) => a.value.localeCompare(b.value)); + makeFilters.forEach(make => { + + makeContainer.appendChild(make.generateCardHTML()); + make.subscribe(m=> initModelContainer(m)) + }); +} + +function createBodyTypeList(vehicles){ + const bodyTypeContainer = document.querySelector('.body-type-container'); + bodyTypeContainer.innerHTML = ''; + + const bodyType = vehicles.reduce((acc, vehicle) => { + const { body_type } = vehicle; + acc[body_type] = (acc[body_type] || 0) + 1; + return acc; + }, {}); + + filterManager.resetList('body_type'); + + + bodyTypeFilters = Object.entries(bodyType).map(([body_type, count]) => filterManager.createBodyTypeFilter({ text: body_type, count}, dataStore)); + bodyTypeFilters.sort((a, b) => a.value.localeCompare(b.value)); + bodyTypeFilters.forEach(body_type => { + bodyTypeContainer.appendChild(body_type.initCheckbox()); + // body_type.subscribe(m=> iniBodyTypeContainer(m)) + }); +} + +function createTransmissionList(vehicles){ + const transmissionContainer = document.querySelector('.transmission-container'); + + transmissionContainer.innerHTML = ''; + + const transmission = vehicles.reduce((acc, vehicle) => { + const { transmission_type } = vehicle; + acc[transmission_type] = (acc[transmission_type] || 0) + 1; + return acc; + }, {}); + + filterManager.resetList('transmission_type'); + transmissionFilters = Object.entries(transmission).map(([transmission_type, count]) => filterManager.createTransmissionFilter({ text: transmission_type, count}, dataStore)); + transmissionFilters.sort((a, b) => a.value.localeCompare(b.value)); + transmissionFilters.forEach(transmission => { + transmissionContainer.appendChild(transmission.initCheckbox()); + }); +} + +function createExteriorList(vehicles){ + console.log(vehicles); + const exteriorContainer = document.querySelector('.exterior-color'); + exteriorContainer.innerHTML = ''; + const exterior = vehicles.reduce((acc, vehicle) => { + const { exterior_color } = vehicle; + acc[exterior_color] = (acc[exterior_color] || 0) + 1; + return acc; + }, {}); + filterManager.resetList('exterior_color'); + + exteriorFilters = Object.entries(exterior).map(([exterior_color, count]) => filterManager.createExteriorFilter({ text: exterior_color, count}, dataStore)); + exteriorFilters.sort((a, b) => a.value.localeCompare(b.value)); + + exteriorFilters.forEach(exterior => { + exteriorContainer.appendChild(exterior.initCheckbox()); + }); +} + + +function initModelContainer(make){ + let list = [...new Set(filterManager.makeFilters.filter(m=>m.checked == true).map(m=>m.models).flat())]; + + const modelContainer = document.querySelector('.model-container'); + if (list.length === 0) { + modelContainer.innerHTML = '

Please Select a Make

'; + } else if (list && list.length > 0) { + modelContainer.innerHTML = ''; + list.sort((a, b) => a.value.localeCompare(b.value)); + list.forEach(model => { + modelContainer.appendChild(model.initCheckbox()); + }); + } else { + modelContainer.innerHTML = '

No models available

'; + } +} + +function initTrimContainer(model){ + let list = [...new Set(filterManager.modelFilters.filter(m=>m.checked == true).map(m=>m.trims).flat())]; + + // const uniqueArray = [...new Set(array)]; + const trimContainer = document.querySelector('.trim-container'); + + if (list.length === 0) { + trimContainer.innerHTML = '

Please Select a Model

'; + } else if (list && list.length > 0) { + trimContainer.innerHTML = ''; + list.sort((a, b) => a.value.localeCompare(b.value)); + list.forEach(trim => { + trimContainer.appendChild(trim.initCheckbox()); + }); + } else { + trimContainer.innerHTML = '

No trims available

'; + } } function fetchAvailableModels(vehicles, make) { - const filteredModels = vehicles - .filter((vehicle) => vehicle.make === make) - .map((vehicle) => vehicle.model); - // Count occurrences of each model - const modelCounts = filteredModels.reduce((acc, model) => { - acc[model] = (acc[model] || 0) + 1; - return acc; - }, {}); + const filteredModels = vehicles + .filter(vehicle => vehicle.make === make) + .map(vehicle => vehicle.model); + // Count occurrences of each model + const modelCounts = filteredModels.reduce((acc, model) => { + acc[model] = (acc[model] || 0) + 1; + return acc; + }, {}); - // Convert to an array of objects - const modelsArray = Object.entries(modelCounts).map(([model, count]) => ({ - model, - count, - })); - modelsArray.map((m) => (m['trims'] = fetchAvailableTrim(vehicles, m.model))); - return modelsArray; + // Convert to an array of objects + const modelsArray = Object.entries(modelCounts).map(([model, count]) => ({ model, count })); + modelsArray.map(m=>m['trims'] = fetchAvailableTrim(vehicles, m.model)) + return modelsArray; } -function fetchAvailableTrim(vehicles, modelName) { - const filteredVehicles = vehicles.filter( - (vehicle) => vehicle.model === modelName - ); - const trimCount = filteredVehicles.reduce((result, vehicle) => { - vehicle.trim.forEach((trim) => { - const existingTrim = result.find((item) => item.text === trim); - if (existingTrim) { - existingTrim.count += 1; - } else { - result.push({ text: trim, count: 1 }); - } - }); - return result; - }, []); - return trimCount; +function fetchAvailableTrim(vehicles, modelName){ + const filteredVehicles = vehicles.filter(vehicle => vehicle.model === modelName); + const trimCount = filteredVehicles.reduce((result, vehicle) => { + vehicle.trim.forEach(trim => { + const existingTrim = result.find(item => item.text === trim); + if (existingTrim) { + existingTrim.count += 1; + } else { + result.push({ text: trim, count: 1 }); + } + }); + return result; + }, []); + return trimCount; } -function updateModel(models) { - console.log('updateModel', models); +function updateModel(models){ + console.log('updateModel', models) } + + function debounce(func, delay) { - let timeout; - return function () { - const context = this; - const args = arguments; - clearTimeout(timeout); - timeout = setTimeout(() => func.apply(context, args), delay); - }; + let timeout; + return function () { + const context = this; + const args = arguments; + clearTimeout(timeout); + timeout = setTimeout(() => func.apply(context, args), delay); + }; } function updatePrice() { - const min = price.getValueStart(); - const max = price.getValue(); - const formattedMin = '$' + min.toLocaleString(); - const formattedMax = '$' + max.toLocaleString(); - document.getElementById( - 'priceRange' - ).textContent = `${formattedMin} to ${formattedMax}`; - debouncedSendReq(); + const min = price.getValueStart(); + const max = price.getValue(); + const formattedMin = '$' + min.toLocaleString(); + const formattedMax = '$' + max.toLocaleString(); + document.getElementById('priceRange').textContent = `${formattedMin} to ${formattedMax}`; + debouncedSendReq(); } function updateYear() { - const min = year.getValueStart(); - const max = year.getValue(); - document.getElementById('yearRange').textContent = `${min} to ${max}`; - debouncedSendReq(); + const min = year.getValueStart(); + const max = year.getValue(); + document.getElementById('yearRange').textContent = `${min} to ${max}`; + debouncedSendReq(); } function updateMileage() { - const min = kilometres.getValueStart(); - const max = kilometres.getValue(); - document.getElementById('KilometresRange').textContent = `${min} to ${max}`; - debouncedSendReq(); + const min = kilometres.getValueStart(); + const max = kilometres.getValue(); + document.getElementById('KilometresRange').textContent = `${min} to ${max}`; + debouncedSendReq(); } // Create debounced versions of sendReq const debouncedSendReq = debounce(sendReq, 300); function createSkeletonCard() { - const skeletonCard = document.createElement('div'); - skeletonCard.classList.add( - 'bg-red-200', - 'rounded-lg', - 'shadow-md', - 'animate-pulse' - ); - - const innerHTML = ` + const skeletonCard = document.createElement('div'); + skeletonCard.classList.add('bg-red-200', 'rounded-lg', 'shadow-md', 'animate-pulse'); + + const innerHTML = `
@@ -342,23 +309,18 @@ function createSkeletonCard() {
`; + + skeletonCard.innerHTML = innerHTML; + + return skeletonCard; + } - skeletonCard.innerHTML = innerHTML; - - return skeletonCard; -} function createSkeletonListItem() { - const listItem = document.createElement('li'); - listItem.classList.add( - 'w-full', - 'bg-custom-red', - 'rounded-lg', - 'shadow-md', - 'animate-pulse' - ); + const listItem = document.createElement('li'); + listItem.classList.add('w-full', 'bg-custom-red', 'rounded-lg', 'shadow-md', 'animate-pulse'); - const innerHTML = ` + const innerHTML = `
@@ -366,7 +328,7 @@ function createSkeletonListItem() {
`; - listItem.innerHTML = innerHTML; + listItem.innerHTML = innerHTML; - return listItem; -} + return listItem; +} \ No newline at end of file diff --git a/autocart_assets/templates/autocart-results.php b/autocart_assets/templates/autocart-results.php index aabd59d..cba0a96 100644 --- a/autocart_assets/templates/autocart-results.php +++ b/autocart_assets/templates/autocart-results.php @@ -34,6 +34,8 @@ $response = get_transient("autocart_response");
+ +