From e9cc003f5cbfb82b137b48d31fd5264a580827c1 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 8 Mar 2023 13:22:04 -0500 Subject: [PATCH 01/42] Cherry-pick: Re-integrate Image-VIN POC. --- .../textbox-question/textbox-question.vue | 53 ++++++++++++++++++- src/constants/endpoints.js | 4 ++ src/constants/store-actions.js | 1 + src/global-methods.js | 20 +++++++ src/layouts/vin-lookup/vin-lookup.vue | 1 + src/store/index.js | 9 ++++ 6 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 957f59f36..5db64002e 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -6,7 +6,12 @@ class="form-label" :class="[questionAlignment === 'center' ? 'text-center w-100 mb-5' : '']" v-html="labelText"> -
+
{{ errorMessage }} @@ -70,6 +83,7 @@ export default { questionAlignment: String, // Left or center. Left is default. cornerStyle: String, // Rounded or square. Square is default. includeSearchIcon: Boolean, + includeCameraIcon: Boolean, }, setup(props) { const propsClone = Object.assign({}, props); @@ -106,6 +120,18 @@ export default { errors, }; }, + methods: { + async submitImage(e) { + await this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, e.target.files[0]) + .then((response) => { + document.getElementById(this.inputId).value = response.data; + }) + .catch((error) => { + console.log(error); + }); + e.target.value = null; + }, + }, computed: { questionText() { return this.getCmsContent(this.cmsWidgetName, "QuestionText"); @@ -183,6 +209,31 @@ export default { display: flex; } } + &.has-camera-icon { + label { + &.camera-icon-input { + position: absolute; + top: 50%; + transform: translateY(-50%); + right: 1rem; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 40 36' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.9774 16.5228C17.3559 16.5228 15.1864 18.6621 15.1864 21.3476C15.1864 24.0331 17.3107 26.1724 19.9774 26.1724C22.6441 26.1724 24.7684 24.0331 24.7684 21.3476C24.7684 18.6621 22.6441 16.5228 19.9774 16.5228Z' fill='%231574A1'/%3E%3Cpath d='M38.4181 7.23725H29.8701C29.1469 2.64 24.7684 0 19.9774 0C15.1864 0 10.8531 2.64 10.0847 7.23725H1.58192C0.723164 7.23725 0 7.96553 0 8.83035V33.7738C0 34.6387 0.723164 35.3669 1.58192 35.3669H38.4181C39.2768 35.3669 40 34.6387 40 33.7738V8.83035C40 7.96553 39.2768 7.23725 38.4181 7.23725ZM19.9774 29.7683C15.3672 29.7683 11.5706 25.9904 11.5706 21.3021C11.5706 16.6138 15.3672 12.8814 19.9774 12.8814C24.5876 12.8814 28.3842 16.6593 28.3842 21.3476C28.3842 26.0359 24.6328 29.7683 19.9774 29.7683ZM36.565 14.5655H33.0395V11.0152H36.565V14.5655Z' fill='%231574A1'/%3E%3C/svg%3E%0A"); + background-repeat: no-repeat; + background-position: center; + width: 2rem; + height: 100%; + display: flex; + border: none; + background-color: transparent; + &:hover { + cursor: pointer; + } + input[type="file"] { + position: absolute; + left: -9999px; + } + } + } + } } input { &.has-icon { diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 1fc6c2b8f..02334faed 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -54,6 +54,10 @@ const endpoints = { url: "/vehicle/api/v1/vehicle/lookup-vin-by-address", method: "POST", }, + LookupVinByImage: { + url: "https://slimagetovin.azurewebsites.net/home/FindVIN", + method: "POST", + }, IsVinByAddressPermissible: { url: "/vehicle/api/v1/vehicle/is-vin-by-address-permissible", method: "GET", diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index c11356d69..96fc64ac8 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -20,6 +20,7 @@ const storeActions = { LOOKUP_VEHICLE_BY_VIN: "lookupVehicleByVin", LOOKUP_VIN_BY_PLATE: "lookupVinByPlate", LOOKUP_VIN_BY_ADDRESS: "lookupVinByAddress", + LOOKUP_VIN_BY_IMAGE: "lookupVinByImage", GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions", GET_PARTS: "getParts", GET_WIPERS: "getWipers", diff --git a/src/global-methods.js b/src/global-methods.js index 14e5cca0e..8a669133e 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -53,6 +53,26 @@ export default { }); }, + // TODO: Remove after replacing test endpoint with real endpoint, then call through normal api call. + callExternalHttpClient({ method, endpoint, payload }) { + return new Promise((resolve, reject) => { + axios({ + method: method, + url: endpoint, + data: payload, + crossDomain: true, + headers: { "Access-Control-Allow-Origin": "*" }, + }).then( + (response) => { + return resolve(response); + }, + (error) => { + return reject(error.response); + } + ); + }); + }, + /* istanbul ignore next */ callMockHttpClient({ method, endpoint }) { // For Mock use only! diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index e42187b12..d9d2b113f 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -19,6 +19,7 @@ validationRules="vin-required|vin-format" :isDisabled="vinPopulatedOnPageLoad" maxLength="17" + includeCameraIcon :mask="vinMask" />
diff --git a/src/store/index.js b/src/store/index.js index f42a950ea..5b4390181 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -530,6 +530,15 @@ export const actions = { }, }); }, + lookupVinByImage(context, image) { + const data = new FormData(); + data.append("file", image); + return globalMethods.callExternalHttpClient({ + method: endpoints.LookupVinByImage.method, + endpoint: endpoints.LookupVinByImage.url, + payload: data, + }); + }, isVinByAddressPermissible(context, zip) { return globalMethods.callHttpClient({ method: endpoints.IsVinByAddressPermissible.method, From 808db6a9bf0d51972be972b66e2e216d722d97e1 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 8 Mar 2023 13:22:49 -0500 Subject: [PATCH 02/42] Cherry-pick: Updated to current endpoint --- src/constants/endpoints.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 02334faed..8c180ffb3 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -55,7 +55,7 @@ const endpoints = { method: "POST", }, LookupVinByImage: { - url: "https://slimagetovin.azurewebsites.net/home/FindVIN", + url: "https://api.dev.belronus.io/ocr/api/v1/VIN", method: "POST", }, IsVinByAddressPermissible: { From 8469d3811b384ab9543eddac085e80d9b1fb2359 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 8 Mar 2023 13:23:41 -0500 Subject: [PATCH 03/42] Cherry-pick: Add X-Mule header to api request --- src/global-methods.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/global-methods.js b/src/global-methods.js index 8a669133e..82e9cd995 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -61,7 +61,10 @@ export default { url: endpoint, data: payload, crossDomain: true, - headers: { "Access-Control-Allow-Origin": "*" }, + headers: { + "Access-Control-Allow-Origin": "*", + "X-Mule-Origin-Verify": "98SHAXE5DN8AWQJRYCT09KIO1RZ2PG", + }, }).then( (response) => { return resolve(response); From 2dc6ef33050d4b8f4253d1040830701e8681b853 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 8 Mar 2023 13:24:31 -0500 Subject: [PATCH 04/42] Cherry-pick: Renamed image file in html response --- src/store/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 5b4390181..529b24fc7 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -532,7 +532,7 @@ export const actions = { }, lookupVinByImage(context, image) { const data = new FormData(); - data.append("file", image); + data.append("vinFile", image); return globalMethods.callExternalHttpClient({ method: endpoints.LookupVinByImage.method, endpoint: endpoints.LookupVinByImage.url, From f7b9b79cfb4bff89c92b410205e833893e53691c Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 8 Mar 2023 13:25:13 -0500 Subject: [PATCH 05/42] Cherry-pick: Update to call local DigitalAPI endpoint --- src/constants/endpoints.js | 2 +- src/global-methods.js | 5 ----- src/store/index.js | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 8c180ffb3..f23552d4b 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -55,7 +55,7 @@ const endpoints = { method: "POST", }, LookupVinByImage: { - url: "https://api.dev.belronus.io/ocr/api/v1/VIN", + url: "https://localhost:44331/vehicle/api/v1/vehicle/vins-by-image", method: "POST", }, IsVinByAddressPermissible: { diff --git a/src/global-methods.js b/src/global-methods.js index 82e9cd995..80107b392 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -60,11 +60,6 @@ export default { method: method, url: endpoint, data: payload, - crossDomain: true, - headers: { - "Access-Control-Allow-Origin": "*", - "X-Mule-Origin-Verify": "98SHAXE5DN8AWQJRYCT09KIO1RZ2PG", - }, }).then( (response) => { return resolve(response); diff --git a/src/store/index.js b/src/store/index.js index 529b24fc7..69fc5b946 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -532,7 +532,7 @@ export const actions = { }, lookupVinByImage(context, image) { const data = new FormData(); - data.append("vinFile", image); + data.append("vinImage", image); return globalMethods.callExternalHttpClient({ method: endpoints.LookupVinByImage.method, endpoint: endpoints.LookupVinByImage.url, From f4eed79845b78d5930da9aa0668a189fb7c0a9d7 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 8 Mar 2023 13:25:50 -0500 Subject: [PATCH 06/42] Cherry-pick: Tie changes to validation flow --- .../textbox-question/textbox-question.vue | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 5db64002e..84c936e24 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -123,8 +123,15 @@ export default { methods: { async submitImage(e) { await this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, e.target.files[0]) - .then((response) => { - document.getElementById(this.inputId).value = response.data; + .then(async (response) => { + this.value = response.data.length > 0 ? response.data[0] : ""; + + // Wait for DOM to update before firing change event to handle validation. + await this.$nextTick(); + + document.getElementById(this.inputId).dispatchEvent( + new Event('change') + ); }) .catch((error) => { console.log(error); From b5fbdfec9382e96c5f53b9894a472f6744d0f4fe Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 8 Mar 2023 13:37:14 -0500 Subject: [PATCH 07/42] Formatting --- src/common-components/textbox-question/textbox-question.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 84c936e24..eddfd835e 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -129,9 +129,7 @@ export default { // Wait for DOM to update before firing change event to handle validation. await this.$nextTick(); - document.getElementById(this.inputId).dispatchEvent( - new Event('change') - ); + document.getElementById(this.inputId).dispatchEvent(new Event("change")); }) .catch((error) => { console.log(error); From 9b1612f84a249e755bb9c5bece7277baeda8f235 Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Wed, 8 Mar 2023 10:38:32 -0500 Subject: [PATCH 08/42] CSR-972 fix missing color option item. --- src/constants/tint-mapper.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/constants/tint-mapper.js b/src/constants/tint-mapper.js index fab6d508f..519de0855 100644 --- a/src/constants/tint-mapper.js +++ b/src/constants/tint-mapper.js @@ -32,6 +32,7 @@ const tintMap = { { name: "gray tint", src: "Glass-NoShade-GrayTint.svg" }, { name: "green tint", src: "Glass-NoShade-GreenTint.svg" }, { name: "gray tint privacy", src: "Glass-NoShade-GrayTint.svg" }, + { name: "blue tint", src: "Glass-NoShade-BlueTint.svg" }, // No shade or tint { name: "clear", src: "Glass-NoShade-NoTint.svg" }, From 0a317093b56e877c61e25b011a326fd038da5c12 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 8 Mar 2023 15:54:03 -0500 Subject: [PATCH 09/42] Display error when VIN scan fails. --- .../textbox-question/textbox-question.vue | 2 +- src/layouts/vin-lookup/vin-lookup.vue | 25 +++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index eddfd835e..a56a5a4bc 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -132,7 +132,7 @@ export default { document.getElementById(this.inputId).dispatchEvent(new Event("change")); }) .catch((error) => { - console.log(error); + this.$emit("imageLookupError"); }); e.target.value = null; }, diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index d9d2b113f..73a7e0e1c 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -8,7 +8,16 @@ :displayGenericVehicleImage="false" />
-
+
+
+ +
+
+
+ :mask="vinMask" + @image-lookup-error="displayVinScanAlert" />
@@ -188,6 +198,7 @@ export default { displayNonServiceableZipAlert: false, displayVinNotFoundAlert: false, displayMatchedDifferentVehicleAlert: false, + displayVinScanFailedAlert: false, }; }, methods: { @@ -381,11 +392,15 @@ export default { await this.navigateForwardWithSingleCarMatch(); } }, + displayVinScanAlert() { + this.displayVinScanFailedAlert = true; + }, resetAlerts() { this.displayMatchedDifferentVehicleAlert = false; this.displayNonServiceableZipAlert = false; this.displayInvalidZipAlert = false; this.displayVinNotFoundAlert = false; + this.displayVinScanFailedAlert = false; }, }, mounted() { @@ -432,6 +447,12 @@ export default { getIsWindshieldOnly() ); }, + AlertVinScanFailedHeader() { + return "VIN scan failed."; + }, + AlertVinScanFailedBody() { + return "Please try again or enter your VIN manually."; + }, isInsuranceVerified() { return ( store.getters.payment.insuranceCoverage.isVerified || From ca7c10a65a3806367178e589f41aad1f443d272a Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 9 Mar 2023 10:46:28 -0500 Subject: [PATCH 10/42] Initial spinner implementation. --- .../textbox-question/textbox-question.vue | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index a56a5a4bc..565655a11 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -36,7 +36,7 @@ :maxlength="maxLength ? maxLength : '999'" @focus="$emit('focus', $event.target.value)" />
{{ errorMessage }} @@ -54,6 +58,8 @@ @@ -238,6 +251,13 @@ export default { } } } + + .loading-icon { + position: absolute; + top: 50%; + transform: translateY(-50%); + right: 1.5rem; + } } } input { From 5ef2c75016cc063bb7bdcb3661b9de1c4a10172e Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 9 Mar 2023 10:53:22 -0500 Subject: [PATCH 11/42] Emit lookup error when no VINs are identified in image. --- .../textbox-question/textbox-question.vue | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 565655a11..9c25a8bc7 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -133,12 +133,16 @@ export default { this.isLoading = true; await this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, e.target.files[0]) .then(async (response) => { - this.value = response.data.length > 0 ? response.data[0] : ""; + if (response.data.length > 0) { + this.value = response.data[0]; - // Wait for DOM to update before firing change event to handle validation. - await this.$nextTick(); + // Wait for DOM to update before firing change event to handle validation. + await this.$nextTick(); - document.getElementById(this.inputId).dispatchEvent(new Event("change")); + document.getElementById(this.inputId).dispatchEvent(new Event("change")); + } else { + this.$emit("imageLookupError"); + } }) .catch((error) => { this.$emit("imageLookupError"); From 4553fa699db4b69d1bcae03d22044ba69cccfd10 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 14 Mar 2023 12:18:15 -0400 Subject: [PATCH 12/42] Update to use proper API call. --- src/constants/endpoints.js | 2 +- src/global-methods.js | 28 ++++++++-------------------- src/store/index.js | 3 ++- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index f23552d4b..a2f9b38be 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -55,7 +55,7 @@ const endpoints = { method: "POST", }, LookupVinByImage: { - url: "https://localhost:44331/vehicle/api/v1/vehicle/vins-by-image", + url: "/vehicle/api/v1/vehicle/vins-by-image", method: "POST", }, IsVinByAddressPermissible: { diff --git a/src/global-methods.js b/src/global-methods.js index 80107b392..2df5c29af 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -7,10 +7,16 @@ import { GaCategories, GaActions, GaLabels } from "@/constants/analytics"; import { headerKeys } from "@/constants/header-keys"; export default { - callHttpClient({ method, endpoint, payload, logApiCall = true }) { + callHttpClient({ method, endpoint, payload, logApiCall = true, isFormData = false }) { return new Promise((resolve, reject) => { const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; - const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" }); + let payloadAndAnalyticsData = {}; + if (isFormData) { + payloadAndAnalyticsData = payload; + payloadAndAnalyticsData.append("AppName", "FixMyGlass"); + } else { + Object.assign(payloadAndAnalyticsData, payload, { AppName: "FixMyGlass" }); + } const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), }; @@ -53,24 +59,6 @@ export default { }); }, - // TODO: Remove after replacing test endpoint with real endpoint, then call through normal api call. - callExternalHttpClient({ method, endpoint, payload }) { - return new Promise((resolve, reject) => { - axios({ - method: method, - url: endpoint, - data: payload, - }).then( - (response) => { - return resolve(response); - }, - (error) => { - return reject(error.response); - } - ); - }); - }, - /* istanbul ignore next */ callMockHttpClient({ method, endpoint }) { // For Mock use only! diff --git a/src/store/index.js b/src/store/index.js index 69fc5b946..751146430 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -533,10 +533,11 @@ export const actions = { lookupVinByImage(context, image) { const data = new FormData(); data.append("vinImage", image); - return globalMethods.callExternalHttpClient({ + return globalMethods.callHttpClient({ method: endpoints.LookupVinByImage.method, endpoint: endpoints.LookupVinByImage.url, payload: data, + isFormData: true, }); }, isVinByAddressPermissible(context, zip) { From b5749eb8aa4e8685e662a59b0ddb761a308684e9 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 14 Mar 2023 12:18:34 -0400 Subject: [PATCH 13/42] Update to use CMS for alert text. --- src/layouts/vin-lookup/vin-lookup.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index 73a7e0e1c..c001e832d 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -448,10 +448,10 @@ export default { ); }, AlertVinScanFailedHeader() { - return "VIN scan failed."; + return this.getCmsContent("AlertVinScanFailed", "HeadlineText"); }, AlertVinScanFailedBody() { - return "Please try again or enter your VIN manually."; + return this.getCmsContent("AlertVinScanFailed", "BodyText"); }, isInsuranceVerified() { return ( From 6b62095cf5508ddef553188360f420692e98f67b Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 14 Mar 2023 14:40:53 -0400 Subject: [PATCH 14/42] Add test for vin-lookup --- src/layouts/vin-lookup/vin-lookup.spec.js | 13 +++++++++++++ src/layouts/vin-lookup/vin-lookup.vue | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/layouts/vin-lookup/vin-lookup.spec.js b/src/layouts/vin-lookup/vin-lookup.spec.js index fc15d3667..936d6ca6a 100644 --- a/src/layouts/vin-lookup/vin-lookup.spec.js +++ b/src/layouts/vin-lookup/vin-lookup.spec.js @@ -242,6 +242,19 @@ describe("vin-lookup.vue", () => { // Assert expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(0); }); + + test.only("Error emitted by textbox-question element => VinScanFailed alert shown.", async () => { + // Arrange + const { wrapper } = setupMocks({}); + + // Act + const vinLookup = wrapper.findComponent('[data-test="vin-lookup-component"]'); + vinLookup.trigger('imageLookupError'); + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(1); + }); }); }); diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index c001e832d..4a9fd5dbd 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -30,7 +30,8 @@ maxLength="17" includeCameraIcon :mask="vinMask" - @image-lookup-error="displayVinScanAlert" /> + @image-lookup-error="displayVinScanAlert" + data-test="vin-lookup-field" />
From d111d0a7bc524799043c081563e830d316fe3072 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 14 Mar 2023 14:41:34 -0400 Subject: [PATCH 15/42] Remove .only from test --- src/layouts/vin-lookup/vin-lookup.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/vin-lookup/vin-lookup.spec.js b/src/layouts/vin-lookup/vin-lookup.spec.js index 936d6ca6a..206a3ffc0 100644 --- a/src/layouts/vin-lookup/vin-lookup.spec.js +++ b/src/layouts/vin-lookup/vin-lookup.spec.js @@ -243,7 +243,7 @@ describe("vin-lookup.vue", () => { expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(0); }); - test.only("Error emitted by textbox-question element => VinScanFailed alert shown.", async () => { + test("Error emitted by textbox-question element => VinScanFailed alert shown.", async () => { // Arrange const { wrapper } = setupMocks({}); From e06be65e341aceee5f9941ef012806ae6584edda Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 14 Mar 2023 18:30:45 -0400 Subject: [PATCH 16/42] Add tests for textbox-question --- .../textbox-question/textbox-question.spec.js | 139 ++++++++++++++++++ .../textbox-question/textbox-question.vue | 1 + 2 files changed, 140 insertions(+) diff --git a/src/common-components/textbox-question/textbox-question.spec.js b/src/common-components/textbox-question/textbox-question.spec.js index d5d1de4e6..e2a5ab820 100644 --- a/src/common-components/textbox-question/textbox-question.spec.js +++ b/src/common-components/textbox-question/textbox-question.spec.js @@ -197,4 +197,143 @@ describe("textboxQuestion.vue", () => { // Assert expect(wrapper.vm.handleChange).toHaveBeenCalled; }); + + it("Should call this.handleChange when image is submitted with valid value.", async () => { + // Arrange + const inputId = 'test'; + const responseValue = 'testResponse'; + + const storeMixin = { + methods: { + dispatchStoreAction: jest.fn().mockImplementation(() => { + return new Promise( + (resolve, reject) => resolve( + { + data: [ responseValue ] + } + ) + ); + }) + } + }; + + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + modelValue: "", + includeCameraIcon: true, + inputId: inputId, + }, + mixins: [mockMixin, storeMixin], + attachTo: document.body + }); + + wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); + + // Act + const imageUploadField = wrapper.find('[data-test="image-upload"]'); + + await imageUploadField.trigger('change'); + + await wrapper.vm.$nextTick(); + + // Assert + + expect(wrapper.vm.handleChange).toHaveBeenCalled(); + expect(wrapper.emitted()).toHaveProperty("update:modelValue"); + }); + + it("Should emit image-lookup-error when image is submitted with invalid value", async () => { + // Arrange + const inputId = 'test'; + + const storeMixin = { + methods: { + dispatchStoreAction: jest.fn().mockImplementation(() => { + return new Promise( + (resolve, reject) => resolve( + { + data: [] + } + ) + ); + }) + } + }; + + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + modelValue: "", + includeCameraIcon: true, + inputId: inputId, + }, + mixins: [mockMixin, storeMixin], + attachTo: document.body + }); + + wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); + + // Act + const imageUploadField = wrapper.find('[data-test="image-upload"]'); + + await imageUploadField.trigger('change'); + + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.handleChange).not.toHaveBeenCalled(); + expect(wrapper.emitted()).toHaveProperty("imageLookupError"); + }); + + it("Should emit image-lookup-error when image endpoint responds with an error", async () => { + // Arrange + const inputId = 'test'; + + const storeMixin = { + methods: { + dispatchStoreAction: jest.fn().mockImplementation(() => { + return new Promise( + (resolve, reject) => reject() + ); + }) + } + }; + + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + modelValue: "", + includeCameraIcon: true, + inputId: inputId, + }, + mixins: [mockMixin, storeMixin], + attachTo: document.body + }); + + wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); + + // Act + const imageUploadField = wrapper.find('[data-test="image-upload"]'); + + await imageUploadField.trigger('change'); + + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.handleChange).not.toHaveBeenCalled(); + expect(wrapper.emitted()).toHaveProperty("imageLookupError"); + }); }); diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 9c25a8bc7..27800a8e2 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -42,6 +42,7 @@ id="vin-input" accept="image/" aria-label="Camera icon/button" + data-test="image-upload" @change="submitImage" /> Date: Tue, 14 Mar 2023 18:49:01 -0400 Subject: [PATCH 17/42] Add tests for lookupVinByImage action. --- src/store/store.spec.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 06f0cb746..2a364243a 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -403,6 +403,37 @@ describe("Actions", () => { expect(response.data).toEqual({ carId: "C00000001" }); }); + it("lookupVinByImage action, should return list of vins", async () => { + // Arrange + const context = state; + const dummyImage = {}; + + globalMethods.callHttpClient.mockImplementation(() => { + return Promise.resolve({ data: [ "1C6JJTAG3NL134044" ] }); + }); + + // Act + const response = await actions.lookupVinByImage(context, dummyImage); + + // Assert + expect(response.data).toEqual([ "1C6JJTAG3NL134044" ]); + }); + + it("lookupVinByImage action, should reject if error in calling API", async () => { + // Arrange + const context = state; + const dummyImage = {}; + + globalMethods.callHttpClient.mockImplementation(() => { + return Promise.reject("An error occurred"); + }); + + // Act + + // Assert + await expect(actions.lookupVinByImage(context, dummyImage)).rejects.toEqual("An error occurred"); + }); + it("getVehicleMakes action, should return makes list", async () => { // Arrange const context = state; From 3543c1cb044b531812022a5f33cc478d62709d11 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 15 Mar 2023 09:36:00 -0400 Subject: [PATCH 18/42] Update position of vin-scan-alert as per mock. --- src/layouts/vin-lookup/vin-lookup.vue | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index 4a9fd5dbd..926bc785f 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -9,15 +9,6 @@
-
- -
-
-
+
+
+ +
+
From 78160d4cff101242a4f8af995b6605308b07407a Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 15 Mar 2023 09:38:58 -0400 Subject: [PATCH 19/42] Add remaining tests --- .../textbox-question/textbox-question.spec.js | 56 +++++++++---------- src/layouts/vin-lookup/vin-lookup.spec.js | 4 +- src/store/store.spec.js | 8 ++- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.spec.js b/src/common-components/textbox-question/textbox-question.spec.js index e2a5ab820..d8a29d9cd 100644 --- a/src/common-components/textbox-question/textbox-question.spec.js +++ b/src/common-components/textbox-question/textbox-question.spec.js @@ -200,21 +200,19 @@ describe("textboxQuestion.vue", () => { it("Should call this.handleChange when image is submitted with valid value.", async () => { // Arrange - const inputId = 'test'; - const responseValue = 'testResponse'; + const inputId = "test"; + const responseValue = "testResponse"; const storeMixin = { methods: { dispatchStoreAction: jest.fn().mockImplementation(() => { - return new Promise( - (resolve, reject) => resolve( - { - data: [ responseValue ] - } - ) + return new Promise((resolve, reject) => + resolve({ + data: [responseValue], + }) ); - }) - } + }), + }, }; const wrapper = shallowMount(textboxQuestion, { @@ -229,7 +227,7 @@ describe("textboxQuestion.vue", () => { inputId: inputId, }, mixins: [mockMixin, storeMixin], - attachTo: document.body + attachTo: document.body, }); wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); @@ -237,7 +235,7 @@ describe("textboxQuestion.vue", () => { // Act const imageUploadField = wrapper.find('[data-test="image-upload"]'); - await imageUploadField.trigger('change'); + await imageUploadField.trigger("change"); await wrapper.vm.$nextTick(); @@ -249,20 +247,18 @@ describe("textboxQuestion.vue", () => { it("Should emit image-lookup-error when image is submitted with invalid value", async () => { // Arrange - const inputId = 'test'; + const inputId = "test"; const storeMixin = { methods: { dispatchStoreAction: jest.fn().mockImplementation(() => { - return new Promise( - (resolve, reject) => resolve( - { - data: [] - } - ) + return new Promise((resolve, reject) => + resolve({ + data: [], + }) ); - }) - } + }), + }, }; const wrapper = shallowMount(textboxQuestion, { @@ -277,7 +273,7 @@ describe("textboxQuestion.vue", () => { inputId: inputId, }, mixins: [mockMixin, storeMixin], - attachTo: document.body + attachTo: document.body, }); wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); @@ -285,7 +281,7 @@ describe("textboxQuestion.vue", () => { // Act const imageUploadField = wrapper.find('[data-test="image-upload"]'); - await imageUploadField.trigger('change'); + await imageUploadField.trigger("change"); await wrapper.vm.$nextTick(); @@ -296,16 +292,14 @@ describe("textboxQuestion.vue", () => { it("Should emit image-lookup-error when image endpoint responds with an error", async () => { // Arrange - const inputId = 'test'; + const inputId = "test"; const storeMixin = { methods: { dispatchStoreAction: jest.fn().mockImplementation(() => { - return new Promise( - (resolve, reject) => reject() - ); - }) - } + return new Promise((resolve, reject) => reject()); + }), + }, }; const wrapper = shallowMount(textboxQuestion, { @@ -320,7 +314,7 @@ describe("textboxQuestion.vue", () => { inputId: inputId, }, mixins: [mockMixin, storeMixin], - attachTo: document.body + attachTo: document.body, }); wrapper.vm.handleChange = jest.fn().mockImplementation(() => {}); @@ -328,7 +322,7 @@ describe("textboxQuestion.vue", () => { // Act const imageUploadField = wrapper.find('[data-test="image-upload"]'); - await imageUploadField.trigger('change'); + await imageUploadField.trigger("change"); await wrapper.vm.$nextTick(); diff --git a/src/layouts/vin-lookup/vin-lookup.spec.js b/src/layouts/vin-lookup/vin-lookup.spec.js index 206a3ffc0..06174dafd 100644 --- a/src/layouts/vin-lookup/vin-lookup.spec.js +++ b/src/layouts/vin-lookup/vin-lookup.spec.js @@ -246,10 +246,10 @@ describe("vin-lookup.vue", () => { test("Error emitted by textbox-question element => VinScanFailed alert shown.", async () => { // Arrange const { wrapper } = setupMocks({}); - + // Act const vinLookup = wrapper.findComponent('[data-test="vin-lookup-component"]'); - vinLookup.trigger('imageLookupError'); + vinLookup.trigger("imageLookupError"); await wrapper.vm.$nextTick(); // Assert diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 2a364243a..9c2dbb0a7 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -409,14 +409,14 @@ describe("Actions", () => { const dummyImage = {}; globalMethods.callHttpClient.mockImplementation(() => { - return Promise.resolve({ data: [ "1C6JJTAG3NL134044" ] }); + return Promise.resolve({ data: ["1C6JJTAG3NL134044"] }); }); // Act const response = await actions.lookupVinByImage(context, dummyImage); // Assert - expect(response.data).toEqual([ "1C6JJTAG3NL134044" ]); + expect(response.data).toEqual(["1C6JJTAG3NL134044"]); }); it("lookupVinByImage action, should reject if error in calling API", async () => { @@ -431,7 +431,9 @@ describe("Actions", () => { // Act // Assert - await expect(actions.lookupVinByImage(context, dummyImage)).rejects.toEqual("An error occurred"); + await expect(actions.lookupVinByImage(context, dummyImage)).rejects.toEqual( + "An error occurred" + ); }); it("getVehicleMakes action, should return makes list", async () => { From 36004d9677261abc3ad680a6b3926553e5157b4e Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 15 Mar 2023 09:50:00 -0400 Subject: [PATCH 20/42] Limit accepted file types on input field. --- src/common-components/textbox-question/textbox-question.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 27800a8e2..48e46ffba 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -40,7 +40,7 @@ From a9ee53ce5ef90f0ba6c1df16c464b451979d1170 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 15 Mar 2023 09:53:25 -0400 Subject: [PATCH 21/42] Remove vin-scan error when new vin is entered. --- src/layouts/vin-lookup/vin-lookup.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index 926bc785f..92e265ccd 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -472,6 +472,7 @@ export default { watch: { vin() { this.displayVinNotFoundAlert = false; + this.displayVinScanFailedAlert = false; this.$refs.funnelFooter.updateButtonText( this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") ); From 64375f23971ea2319daf4e12de214c610c9d2322 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 15 Mar 2023 10:17:58 -0400 Subject: [PATCH 22/42] Properly resize camera icon --- src/common-components/textbox-question/textbox-question.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 48e46ffba..41fc3a5c2 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -242,7 +242,7 @@ export default { background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 40 36' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.9774 16.5228C17.3559 16.5228 15.1864 18.6621 15.1864 21.3476C15.1864 24.0331 17.3107 26.1724 19.9774 26.1724C22.6441 26.1724 24.7684 24.0331 24.7684 21.3476C24.7684 18.6621 22.6441 16.5228 19.9774 16.5228Z' fill='%231574A1'/%3E%3Cpath d='M38.4181 7.23725H29.8701C29.1469 2.64 24.7684 0 19.9774 0C15.1864 0 10.8531 2.64 10.0847 7.23725H1.58192C0.723164 7.23725 0 7.96553 0 8.83035V33.7738C0 34.6387 0.723164 35.3669 1.58192 35.3669H38.4181C39.2768 35.3669 40 34.6387 40 33.7738V8.83035C40 7.96553 39.2768 7.23725 38.4181 7.23725ZM19.9774 29.7683C15.3672 29.7683 11.5706 25.9904 11.5706 21.3021C11.5706 16.6138 15.3672 12.8814 19.9774 12.8814C24.5876 12.8814 28.3842 16.6593 28.3842 21.3476C28.3842 26.0359 24.6328 29.7683 19.9774 29.7683ZM36.565 14.5655H33.0395V11.0152H36.565V14.5655Z' fill='%231574A1'/%3E%3C/svg%3E%0A"); background-repeat: no-repeat; background-position: center; - width: 2rem; + width: 1rem; height: 100%; display: flex; border: none; @@ -261,7 +261,7 @@ export default { position: absolute; top: 50%; transform: translateY(-50%); - right: 1.5rem; + right: 1rem; } } } From 1e101eeaaffced8996d80994f8cf25678ff7b084 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 15 Mar 2023 11:49:06 -0400 Subject: [PATCH 23/42] Alert tweak to be less hacky --- src/layouts/vin-lookup/vin-lookup.vue | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index 92e265ccd..69dafd555 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -28,8 +28,7 @@
@@ -448,12 +447,6 @@ export default { getIsWindshieldOnly() ); }, - AlertVinScanFailedHeader() { - return this.getCmsContent("AlertVinScanFailed", "HeadlineText"); - }, - AlertVinScanFailedBody() { - return this.getCmsContent("AlertVinScanFailed", "BodyText"); - }, isInsuranceVerified() { return ( store.getters.payment.insuranceCoverage.isVerified || From 913b9098ebf7e35c98e1ccc1fd0ed02a3bc007de Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 16 Mar 2023 14:18:20 -0400 Subject: [PATCH 24/42] Disable image uploading when input is disabled. --- .../textbox-question/textbox-question.spec.js | 29 +++++++++++++++++++ .../textbox-question/textbox-question.vue | 28 +++++++++--------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.spec.js b/src/common-components/textbox-question/textbox-question.spec.js index d8a29d9cd..adffdbf1c 100644 --- a/src/common-components/textbox-question/textbox-question.spec.js +++ b/src/common-components/textbox-question/textbox-question.spec.js @@ -330,4 +330,33 @@ describe("textboxQuestion.vue", () => { expect(wrapper.vm.handleChange).not.toHaveBeenCalled(); expect(wrapper.emitted()).toHaveProperty("imageLookupError"); }); + + it("Should not display camera or spinner icon when disabled", () => { + // Arrange + const inputId = "test"; + + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + modelValue: "", + includeCameraIcon: true, + inputId: inputId, + isDisabled: true, + }, + mixins: [mockMixin], + attachTo: document.body, + }); + + // Act + const cameraIcon = wrapper.find('[data-test="image-upload"]'); + const loadingIcon = wrapper.findComponent('loader'); + + // Assert + expect(cameraIcon.exists()).toBe(false); + expect(loadingIcon.exists()).toBe(false); + }); }); diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 41fc3a5c2..c080e4f91 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -36,19 +36,21 @@ :maxlength="maxLength ? maxLength : '999'" @focus="$emit('focus', $event.target.value)" />
{{ errorMessage }} From 749db4c06c6bf0d03ba4dcbe601e4ec7781c38dc Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 16 Mar 2023 14:27:33 -0400 Subject: [PATCH 25/42] Formatting. --- .../textbox-question/textbox-question.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.spec.js b/src/common-components/textbox-question/textbox-question.spec.js index adffdbf1c..1f15246f7 100644 --- a/src/common-components/textbox-question/textbox-question.spec.js +++ b/src/common-components/textbox-question/textbox-question.spec.js @@ -334,7 +334,7 @@ describe("textboxQuestion.vue", () => { it("Should not display camera or spinner icon when disabled", () => { // Arrange const inputId = "test"; - + const wrapper = shallowMount(textboxQuestion, { global: { directives: { @@ -353,7 +353,7 @@ describe("textboxQuestion.vue", () => { // Act const cameraIcon = wrapper.find('[data-test="image-upload"]'); - const loadingIcon = wrapper.findComponent('loader'); + const loadingIcon = wrapper.findComponent("loader"); // Assert expect(cameraIcon.exists()).toBe(false); From 8085759892ec10686f4bec56e58b6e5c4de3d602 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 21 Mar 2023 17:06:26 -0400 Subject: [PATCH 26/42] Initial attempt to extract vin-capture business logic --- .../textbox-question/textbox-question.vue | 30 ++++--------------- src/layouts/vin-lookup/vin-lookup.vue | 28 +++++++++++++++-- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index c080e4f91..3a818e256 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -37,17 +37,17 @@ @focus="$emit('focus', $event.target.value)" />
@@ -199,6 +201,7 @@ export default { displayVinNotFoundAlert: false, displayMatchedDifferentVehicleAlert: false, displayVinScanFailedAlert: false, + isVinLoading: false, }; }, methods: { @@ -395,6 +398,27 @@ export default { displayVinScanAlert() { this.displayVinScanFailedAlert = true; }, + async submitImage(e) { + this.isVinLoading = true; + await this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, e) + .then(async (response) => { + if (response.data.length > 0) { + const result = response.data[0]; + + this.vin = result; + + this.$refs.vinLookupQuestion.handleChange(result); + + this.resetAlerts(); + } else { + this.displayVinScanAlert(); + } + }) + .catch((error) => { + this.displayVinScanAlert(); + }); + this.isVinLoading = false; + }, resetAlerts() { this.displayMatchedDifferentVehicleAlert = false; this.displayNonServiceableZipAlert = false; From ec37b93e31c6b895b58959734280f598d176f281 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 21 Mar 2023 17:42:54 -0400 Subject: [PATCH 27/42] Change to injected callback pattern, from event pattern. --- .../textbox-question/textbox-question.vue | 33 +++++++++++---- src/layouts/vin-lookup/vin-lookup.vue | 40 ++++++++----------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 3a818e256..76a9f3ec2 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -10,7 +10,7 @@ class="input-wrapper" :class="[ includeSearchIcon ? 'has-search-icon' : '', - includeCameraIcon ? 'has-camera-icon' : '', + includeImageQuestion ? 'has-camera-icon' : '', ]">
@@ -398,26 +398,20 @@ export default { displayVinScanAlert() { this.displayVinScanFailedAlert = true; }, - async submitImage(e) { - this.isVinLoading = true; - await this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, e) - .then(async (response) => { - if (response.data.length > 0) { - const result = response.data[0]; - - this.vin = result; - - this.$refs.vinLookupQuestion.handleChange(result); - - this.resetAlerts(); - } else { - this.displayVinScanAlert(); - } - }) - .catch((error) => { - this.displayVinScanAlert(); - }); - this.isVinLoading = false; + getVinFromImage(image) { + return new Promise((resolve, reject) => { + this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, image) + .then((response) => { + if (response.data.length > 0) { + resolve(response.data[0]); + } else { + reject(); + } + }) + .catch(() => { + reject(); + }); + }); }, resetAlerts() { this.displayMatchedDifferentVehicleAlert = false; From 3b41bb59e68e153c3480a443ed8b3fca83923701 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 21 Mar 2023 17:46:38 -0400 Subject: [PATCH 28/42] Semantic restructuring of v-ifs. --- .../textbox-question/textbox-question.vue | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/common-components/textbox-question/textbox-question.vue b/src/common-components/textbox-question/textbox-question.vue index 76a9f3ec2..3eeef5a05 100644 --- a/src/common-components/textbox-question/textbox-question.vue +++ b/src/common-components/textbox-question/textbox-question.vue @@ -36,22 +36,22 @@ :maxlength="maxLength ? maxLength : '999'" @focus="$emit('focus', $event.target.value)" />