From a97fe72e5e87bb23d16985e3876591ba010ef27d Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Tue, 27 Feb 2024 16:46:34 -0500 Subject: [PATCH 01/36] SSR-1081 handling payment return info from hop --- src/constants/query-strings.js | 17 +- src/constants/web-storage-constants.js | 5 + src/helpers/querystring-helper.js | 11 ++ src/layouts/payment-page/payment-page.vue | 8 +- src/layouts/payment-return/payment-return.vue | 145 ++++++++++++++++++ .../router-constants/navigation-scenarios.js | 3 + src/router/router-constants/routing-table.js | 17 ++ src/store/index.js | 79 ++++++++-- 8 files changed, 262 insertions(+), 23 deletions(-) create mode 100644 src/constants/web-storage-constants.js create mode 100644 src/helpers/querystring-helper.js create mode 100644 src/layouts/payment-return/payment-return.vue diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 9b486517..f217dea4 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -1,5 +1,20 @@ const queryStrings = Object.freeze({ - ISS_PAGE: 'issPage' + ISS_PAGE: 'issPage', + ERROR: 'error', + SUBSCRIPTIONID: 'subscriptionid', + REFERRAL_SEQ_NUM: 'referralseqnum', + CARD_EXPIRATION_MONTH: 'card_expirationmonth', + CARD_EXPIRATION_YEAR: 'card_expirationyear', + CARD_TYPE: 'sgcardtype', + BILL_TO_POSTAL_CODE: 'billto_postalcode', + BILL_TO_FIRST_NAME: 'billto_firstname', + BILL_TO_LAST_NAME: 'billto_lastname', + REFERENCE_NUMBER: 'req_reference_number', + AUTH_CODE: 'auth_code', + TRANSACTION_ID: 'transaction_id', + TRANS_REFERENCE_NUMBER: 'auth_trans_ref_no', + LAST_FOUR: 'last_four', + DISPLAY_PAY_IN_ADVANCE_ALERT: 'displayPayInAdvanceAlert' }); export default queryStrings; diff --git a/src/constants/web-storage-constants.js b/src/constants/web-storage-constants.js new file mode 100644 index 00000000..29c814cf --- /dev/null +++ b/src/constants/web-storage-constants.js @@ -0,0 +1,5 @@ +const webStorageConstants = Object.freeze({ + SUBMITTED_ORDER: 'submittedOrder' +}); + +export default webStorageConstants; diff --git a/src/helpers/querystring-helper.js b/src/helpers/querystring-helper.js new file mode 100644 index 00000000..32900e96 --- /dev/null +++ b/src/helpers/querystring-helper.js @@ -0,0 +1,11 @@ +export default function getQuerystringParameter(key) { + const queryString = window.location.search; + const urlParams = new URLSearchParams(queryString); + const lowerCaseParams = new URLSearchParams(); + + urlParams.forEach((value, name) => { + lowerCaseParams.append(name.toLowerCase(), value); + }); + + return lowerCaseParams.get(key.toLowerCase()); +} diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index 7612e842..1f77de74 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -460,15 +460,11 @@ export default { computed: { payInAdvanceResponseUrl() { const { protocol, host } = window.location; - return `${protocol}//${host}/?issPage=${ - issPageValues.PAYMENT_RETURN - }&src=iss-nextgen`; + return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN}&src=iss-nextgen`; }, payInAdvanceCancelUrl() { const { protocol, host } = window.location; - return `${protocol}//${host}/?issPage=${ - issPageValues.PAYMENT_METHOD - }&src=iss-nextgen`; + return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_METHOD}&src=iss-nextgen`; }, dynamicCSSUrl() { const { protocol, hostname, port } = window.location; diff --git a/src/layouts/payment-return/payment-return.vue b/src/layouts/payment-return/payment-return.vue new file mode 100644 index 00000000..1ef57a4b --- /dev/null +++ b/src/layouts/payment-return/payment-return.vue @@ -0,0 +1,145 @@ + + + diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 1406498e..f50af7d5 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -91,6 +91,9 @@ const navigationScenarios = Object.freeze({ // Payment CLICKED_PAY_NOW: 'CLICKED_PAY_NOW', + PAY_IN_ADVANCE_ERROR: 'PAY_IN_ADVANCE_ERROR', + PAY_IN_ADVANCE_CREDIT_CARD_ERROR: 'PAY_IN_ADVANCE_CREDIT_CARD_ERROR', + PAY_IN_ADVANCE_SUCCESS: 'PAY_IN_ADVANCE_SUCCESS', // Bailout CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index df960f77..badf8d68 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -629,6 +629,23 @@ const routingTable = () => [ } ] }, + { + issPageValue: issPageValues.PAYMENT_RETURN, + maps: [ + { + scenario: navigationScenarios.PAY_IN_ADVANCE_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_METHOD + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_CREDIT_CARD_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_PAGE + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, + destinationIssPageValue: issPageValues.CONFIRMATION + }, + ] + }, { issPageValue: issPageValues.TPA_CONFIRMATION, maps: [ diff --git a/src/store/index.js b/src/store/index.js index 9dd4e7ce..8be154de 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -14,6 +14,7 @@ import coverageStatuses from '@/constants/coverage-statuses'; import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants'; import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper'; import { paymentMethods } from '@/constants/payment-method-constants'; +import webStorageConstants from '@/constants/web-storage-constants'; const storeId = 'main'; @@ -150,7 +151,21 @@ const getDefaultState = () => ({ }, parentAccountNumber: 0, isPayInAdvance: null, - payInAdvanceType: null + payInAdvanceType: null, + ccToken: { + subscriptionId: null, + expMonth: null, + expYear: null, + cardType: null, + billToPostalCode: null, + billToFirstName: null, + billToLastName: null, + referenceNumber: null, + authCode: null, + transactionId: null, + transReferenceNumber: null, + lastFour: null + } }, contactInfo: { firstName: null, @@ -175,8 +190,7 @@ const getDefaultState = () => ({ eon: null, workOrderNumber: null, originalDeductible: null, - currentDeductible: null, - carrierPhoneNumber: null + currentDeductible: null }, applicationUser: { experiments: [], @@ -926,18 +940,6 @@ export const useMainStore = defineStore({ }); }, - getCarrierAccountInfo() { - return new Promise((resolve, reject) => { - globalMethods.callHttpClient({ - method: endpoints.GetAccountInfo.method, - endpoint: endpoints.GetAccountInfo.url + this.issConfig.parentAccountNumber - }).then((response) => { - this.order.carrierPhoneNumber = response.data.phoneNumber; - return resolve(response.data); - }).catch((error) => reject(error)); - }); - }, - async getSupportingItems() { const glassPartsArray = this.order.lineItems.glassParts ?? []; const { carId } = this.order.vehicle; @@ -1397,6 +1399,10 @@ export const useMainStore = defineStore({ this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter; }, + resetState() { + Object.assign(this, getDefaultState()); + }, + resetRegistrationState() { this.order.vehicle.registration.licensePlate = null; this.order.vehicle.registration.address = null; @@ -2166,7 +2172,48 @@ export const useMainStore = defineStore({ method: endpoints.GetPaymentSignature.method, endpoint: endpoints.GetPaymentSignature.url }); - } + }, + + updateCCToken(ccToken) { + this.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; + this.order.payment.ccToken.expMonth = ccToken.expMonth; + this.order.payment.ccToken.expYear = ccToken.expYear; + this.order.payment.ccToken.cardType = ccToken.cardType; + this.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; + this.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; + this.order.payment.ccToken.billToLastName = ccToken.billToLastName; + this.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; + this.order.payment.ccToken.authCode = ccToken.authCode; + this.order.payment.ccToken.transactionId = ccToken.transactionId; + this.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; + this.order.payment.ccToken.lastFour = ccToken.lastFour; + }, + + hasSubmittedOrder() { + return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; + }, + + createSubmittedOrder() { + if (this.hasSubmittedOrder()) { + return; + } + const submittedOrder = this.order; + const { experiments } = this.applicationUser; + + // set to local storage + window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); + + // clear vuex + this.resetState(); + + // restore user's experiments + this.applicationUser.experiments = experiments; + }, + + resetSubmittedOrder() { + // clear from local storage + window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); + }, }, persist: true From ec85a33693f822a19782f8c2884dfba2e28a5fd1 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 1 Mar 2024 17:57:59 -0500 Subject: [PATCH 02/36] Removing unnecessary --- src/layouts/coverage-statement/coverage-statement.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index f5ab548d..02848781 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -128,7 +128,6 @@ import baseFormMixin from '@/mixins/base-form-mixin.js'; import navigationScenarios from '@/router/router-constants/navigation-scenarios.js'; import routerParams from '@/router/router-constants/router-params'; import issPageValues from '@/router/router-constants/issPage-values'; -import bailoutCode from '@/constants/bailoutCode'; import bailoutMessage from '@/constants/bailoutMessage'; export default { @@ -405,7 +404,6 @@ export default { ); } }, - processIfStatements, getHeaderTextFromCms(cmsWidgetName) { const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); return this.processIfStatements(header, 'custom', this.getCustomValueFromString); From 5ac9970d655bc661c2858ac18538591c0b8f6ae4 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 1 Mar 2024 18:01:23 -0500 Subject: [PATCH 03/36] Getting rid of mainStore data property --- .../coverage-statement/coverage-statement.vue | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 02848781..51ad2a5d 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -177,7 +177,14 @@ export default { await useMainStore().getFinalDeductible(); pricingResults = await useMainStore().getPriceOrderItems(availableLineItems) .catch((err) => { - useMainStore().setBailout(to, bailoutMessage.pricingResponseError(availableLineItems.map((li) => li.partNumber), { code: err.code, message: err.message, data: err.data })); + useMainStore() + .setBailout( + to, + bailoutMessage.pricingResponseError( + availableLineItems.map((li) => li.partNumber), + { code: err.code, message: err.message, data: err.data } + ) + ); hasBailedOut = true; next(`/?issPage=${issPageValues.BAILOUT_PAGE}`); }); @@ -198,10 +205,6 @@ export default { }); } }, - setup() { - const mainStore = useMainStore(); - return { mainStore }; - }, data() { return { availableLineItems: [], @@ -368,7 +371,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { - this.mainStore.saveSupportingItems(this.supportingItems); + useMainStore().saveSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -378,7 +381,7 @@ export default { } else if (this.verifiedITAC || this.verifiedNoComp) { useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); if (this.selectedProvider === 'Safelite') { - this.mainStore.saveSupportingItems(this.supportingItems); + useMainStore().saveSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route, @@ -386,7 +389,7 @@ export default { { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else { - this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); + useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, this.$route, @@ -395,7 +398,7 @@ export default { ); } } else { - this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.coverageStatementInvalidState()); + useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.coverageStatementInvalidState()); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE, this.$route, @@ -406,23 +409,23 @@ export default { }, getHeaderTextFromCms(cmsWidgetName) { const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); - return this.processIfStatements(header, 'custom', this.getCustomValueFromString); + return processIfStatements(header, 'custom', this.getCustomValueFromString); }, getSubheaderTextFromCms(cmsWidgetName) { const subHeader = this.getCmsContent(cmsWidgetName, 'SubHeaderText'); - return this.processIfStatements(subHeader, 'custom', this.getCustomValueFromString); + return processIfStatements(subHeader, 'custom', this.getCustomValueFromString); }, getBodyTextFromCms(cmsWidgetName) { const bodyText = this.getCmsContent(cmsWidgetName, 'BodyText'); - return this.processIfStatements(bodyText, 'custom', this.getCustomValueFromString); + return processIfStatements(bodyText, 'custom', this.getCustomValueFromString); }, getSecondaryTextFromCms(cmsWidgetName) { const secondaryText = this.getCmsContent(cmsWidgetName, 'SecondaryText'); - return this.processIfStatements(secondaryText, 'custom', this.getCustomValueFromString); + return processIfStatements(secondaryText, 'custom', this.getCustomValueFromString); }, getExplantoryTextFromCms(cmsWidgetName) { const explanatoryText = this.getCmsContent(cmsWidgetName, 'BodyText'); - return this.processIfStatements(explanatoryText, 'custom', this.getCustomValueFromString); + return processIfStatements(explanatoryText, 'custom', this.getCustomValueFromString); }, getCustomValueFromString(str) { switch (str) { From 090188ed64ec6b66fa6cc53874b1e09f1ce6c70f Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 13:28:39 -0500 Subject: [PATCH 04/36] Partial --- .../coverage-statement/coverage-statement.vue | 191 +++++++++--------- src/store/index.js | 7 +- 2 files changed, 98 insertions(+), 100 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 51ad2a5d..80e1665f 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -38,7 +38,7 @@ {{ formattedDeductible }}
{{ formattedServicePrice }}
@@ -53,8 +53,8 @@ ref="verifiedITACAlert" class="mb-5" cmsWidgetName="VerifiedITACAlert" - :manualHeadline="verifiedITACAlertHeader" - :manualCopy="verifiedITACAlertBody" + :manualHeadline="verifiedItacAlertHeader" + :manualCopy="verifiedItacAlertBody" alertClass="alert-success" :isDismissible="false"> @@ -67,18 +67,18 @@ v-html="nextStepsBody"> @@ -88,7 +88,7 @@ cmsWidgetName="SiteFooterWidget" :isForwardActionDisabled="!meta.valid" @backClicked="navigateBackByVehicleQuestions" - @forwardClicked="forwardButtonAction" /> + @forwardClicked="navigateForward" /> @@ -129,6 +129,9 @@ import navigationScenarios from '@/router/router-constants/navigation-scenarios. import routerParams from '@/router/router-constants/router-params'; import issPageValues from '@/router/router-constants/issPage-values'; import bailoutMessage from '@/constants/bailoutMessage'; +import widgetFields from '@/constants/cms-widget-fields.js'; + +const SAFELITE_PROVIDER = 'Safelite'; export default { name: 'coverage-statement', @@ -163,8 +166,8 @@ export default { ]; const resultMap = await settleAllPromises(promiseResultMap); - const clonedGlassParts = useMainStore().order.lineItems.glassParts - ? JSON.parse(JSON.stringify(useMainStore().order.lineItems.glassParts)) + const clonedGlassParts = useMainStore().lineItems.glassParts + ? JSON.parse(JSON.stringify(useMainStore().lineItems.glassParts)) : []; const availableLineItems = [ ...(resultMap.supportingItems ?? []), @@ -173,7 +176,7 @@ export default { let hasBailedOut = false; let pricingResults = []; - if (useMainStore().order.policy.policyLookupSuccessful && useMainStore().order.vehicle.policyVehicleId >= 0) { + if (useMainStore().policy.policyLookupSuccessful && useMainStore().vehicle.policyVehicleId >= 0) { await useMainStore().getFinalDeductible(); pricingResults = await useMainStore().getPriceOrderItems(availableLineItems) .catch((err) => { @@ -196,9 +199,9 @@ export default { vm.setCmsContent(resultMap.cmsContent); vm.setSupportingItems(resultMap.supportingItems); // eslint-disable-next-line no-param-reassign - vm.availableLineItems = pricingResults; + vm.setAvailableLineItems(pricingResults); vm.$refs.loadingModal.showModal(); - vm.initializeComponent(availableLineItems); + vm.initializeComponent(); if (!vm.unverified) { useMainStore().disableKeyFields(); } @@ -206,7 +209,14 @@ export default { } }, data() { + const { isRepair } = useMainStore().damage; + const { policyLookupSuccessful, noCoverage } = useMainStore().policy; + const { currentDeductible } = useMainStore().order.currentDeductible; return { + isRepair, + policyLookupSuccessful, + deductibleValue: currentDeductible, + isNoComp: noCoverage ?? false, availableLineItems: [], selectedProvider: '', deductibleText: 'Your deductible is', @@ -219,83 +229,84 @@ export default { rules: { selectionRequired: globalRules.OPTION_REQUIRED }, - supportingItems: null + supportingItems: null, + widget: { + subheader: 'SiteSubHeaderWidget', + verifiedItacAlert: 'VerifiedITACAlert', + explanatoryText: 'ExplanatoryTextWidget', + nextStep: 'NextStepsWidget', + serviceProviderQuestion: 'ServiceProviderQuestion' + } }; }, computed: { - verifiedITACAlertHeader() { - return this.getCmsContent( - 'VerifiedITACAlert', - 'HeadlineText' + coverageStatementSubHeader() { + return this.getTextFromCmsWithCustomIfStatements( + this.widget.subheader, + widgetFields.SUB_HEADER_WIDGET.SUB_HEADER_TEXT ); }, - verifiedITACAlertBody() { + verifiedItacAlertHeader() { return this.getCmsContent( - 'VerifiedITACAlert', - 'BodyText' + this.widget.verifiedItacAlert, + widgetFields.ALERT_WIDGET.HEADLINE_TEXT + ); + }, + verifiedItacAlertBody() { + return this.getCmsContent( + this.widget.verifiedItacAlert, + widgetFields.ALERT_WIDGET.BODY_TEXT )?.replaceAll('{custom:costSavings}', this.costSavings); }, - coverageStatementSubHeader() { - return this.getSubheaderTextFromCms('SiteSubHeaderWidget'); - }, secondaryText() { - return this.getSecondaryTextFromCms('SiteSubHeaderWidget'); + return this.getTextFromCmsWithCustomIfStatements( + this.widget.subheader, + widgetFields.CONTENT_GROUP_WIDGET.SECONDARY_TEXT + ); }, explanatoryText() { - return this.getExplantoryTextFromCms('ExplanatoryTextWidget'); + return this.getTextFromCmsWithCustomIfStatements( + this.widget.explanatoryText, + widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT + ); }, nextStepsHeader() { - return this.getHeaderTextFromCms('NextStepsWidget'); + return this.getTextFromCmsWithCustomIfStatements( + this.widget.nextStep, + widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT + ); }, nextStepsBody() { - return this.getBodyTextFromCms('NextStepsWidget')?.replaceAll('{custom:damage}', this.damageText); - }, - continueWithSchedulingBodyText() { - return this.getCmsContent('continueWithSchedulingCopy', 'BodyText'); - }, - unverifiedADASNextStepsBodyText() { - return this.getCmsContent('UnverifiedADASNextStepsWidget', 'BodyText')?.replaceAll('{custom:damage}', this.damageText); - }, - unverifiedNonADASNextStepsBodyText() { - return this.getCmsContent('UnverifiedNonADASNextStepsWidget', 'BodyText')?.replaceAll('{custom:damage}', this.damageText); - }, - unverifiedNonADASRepairBodyText() { - return this.getCmsContent('UnverifiedNonADASRepairWidget', 'BodyText'); + return this.getTextFromCmsWithCustomIfStatements( + this.widget.nextStep, + widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT + )?.replaceAll('{custom:damage}', this.damageText); }, damageText() { const damageString = getDamageString(); return damageString === 'match' ? '' : damageString; }, - vehicleDeductible() { - const deductible = useMainStore().order.currentDeductible; - return deductible; - }, formattedDeductible() { - return this.getDeductibleString(this.vehicleDeductible); - }, - isDeductibleZero() { - return this.vehicleDeductible === 0; - }, - policyLookupSuccessful() { - return useMainStore().order.policy.policyLookupSuccessful; + return this.getDeductibleString(this.deductibleValue); }, registerClaimSuccessful() { return useMainStore().payment.insuranceCoverage.isVerified; }, verifiedNoComp() { - return this.policyLookupSuccessful ? useMainStore().order.policy.noCoverage : false; + return this.policyLookupSuccessful && this.isNoComp; }, verifiedITAC() { return this.policyLookupSuccessful - && !this.verifiedNoComp - && this.vehicleDeductible > this.totalServicePrice; + && !this.isNoComp + && this.deductibleValue > this.totalServicePrice; }, + // TODO maybe tweak coveredAndServicePriceAboveOrEqualDeductible() { - return !this.verifiedNoComp && this.totalServicePrice >= this.vehicleDeductible; + return !this.verifiedNoComp && this.totalServicePrice >= this.deductibleValue; }, verifiedDeductible() { return useMainStore().isClaimRegistrationRequired - ? this.registerClaimSuccessful && this.coveredAndServicePriceAboveOrEqualDeductible && this.vehicleDeductible !== null + ? this.registerClaimSuccessful && this.coveredAndServicePriceAboveOrEqualDeductible && this.deductibleValue !== null : this.policyLookupSuccessful && this.coveredAndServicePriceAboveOrEqualDeductible; }, unverified() { @@ -305,9 +316,7 @@ export default { const parts = useMainStore().order.lineItems.glassParts; return parts !== null && !!parts.find((part) => part.requiresRecalibration); }, - isRepair() { - return useMainStore().order.damage.isRepair; - }, + // TODO replace with better method totalServicePrice() { let total = 0; this.availableLineItems.forEach((lineItem) => { @@ -319,27 +328,30 @@ export default { return this.getServicePriceString(this.totalServicePrice); }, costSavings() { - const savings = this.getITACCostSavings(this.vehicleDeductible, this.totalServicePrice); + const savings = this.getITACCostSavings(this.deductibleValue, this.totalServicePrice); const formattedSavings = parseFloat(savings).toFixed(2); return `$${formattedSavings}`; }, - questionText() { - return this.getCmsContent('ServiceProviderQuestion', 'QuestionText'); + serviceProviderQuestionText() { + return this.getCmsContent( + this.widget.serviceProviderQuestion, + widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT + ); }, - answersFromCms() { - return this.getCmsContent('ServiceProviderQuestion', 'Answers'); + serviceProviderQuestionAnswers() { + return this.getCmsContent( + this.widget.serviceProviderQuestion, + widgetFields.INPUT_QUESTION_WIDGET.ANSWERS + ); }, - displayQuote() { + isQuoteDisplayed() { return this.verifiedITAC || this.verifiedNoComp; } }, watch: { selectedProvider() { - if (this.selectedProvider === 'Safelite') { - this.$refs.siteFooter.updateButtonText('Continue with Safelite'); - } else { - this.$refs.siteFooter.updateButtonText('Continue'); - } + const buttonText = this.selectedProvider === SAFELITE_PROVIDER ? 'Continue with Safelite' : 'Safelite'; + this.$refs.siteFooter.updateButtonText(buttonText); }, nextStepsBody(newValue, oldValue) { if (newValue !== oldValue) { @@ -366,9 +378,6 @@ export default { } this.$refs.loadingModal.hideModal(); }, - async forwardButtonAction() { - return this.navigateForward(); - }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { useMainStore().saveSupportingItems(this.supportingItems); @@ -379,8 +388,8 @@ export default { { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else if (this.verifiedITAC || this.verifiedNoComp) { - useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); - if (this.selectedProvider === 'Safelite') { + useMainStore().updateIsSafeliteProvider(this.selectedProvider === SAFELITE_PROVIDER); + if (this.selectedProvider === SAFELITE_PROVIDER) { useMainStore().saveSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, @@ -407,25 +416,9 @@ export default { ); } }, - getHeaderTextFromCms(cmsWidgetName) { - const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); - return processIfStatements(header, 'custom', this.getCustomValueFromString); - }, - getSubheaderTextFromCms(cmsWidgetName) { - const subHeader = this.getCmsContent(cmsWidgetName, 'SubHeaderText'); - return processIfStatements(subHeader, 'custom', this.getCustomValueFromString); - }, - getBodyTextFromCms(cmsWidgetName) { - const bodyText = this.getCmsContent(cmsWidgetName, 'BodyText'); - return processIfStatements(bodyText, 'custom', this.getCustomValueFromString); - }, - getSecondaryTextFromCms(cmsWidgetName) { - const secondaryText = this.getCmsContent(cmsWidgetName, 'SecondaryText'); - return processIfStatements(secondaryText, 'custom', this.getCustomValueFromString); - }, - getExplantoryTextFromCms(cmsWidgetName) { - const explanatoryText = this.getCmsContent(cmsWidgetName, 'BodyText'); - return processIfStatements(explanatoryText, 'custom', this.getCustomValueFromString); + getTextFromCmsWithCustomIfStatements(widgetName, widgetField) { + const rawText = this.getCmsContent(widgetName, widgetField); + return processIfStatements(rawText, 'custom', this.getCustomValueFromString); }, getCustomValueFromString(str) { switch (str) { @@ -444,20 +437,23 @@ export default { case 'nonADASRepair': return this.isRepair; case 'deductibleOverZero': - return this.verifiedDeductible && !this.isDeductibleZero; // TODO what if deductible is negative? + return this.verifiedDeductible && this.deductibleValue !== 0; // TODO what if deductible is negative? case 'isDeductibleZero': - return this.verifiedDeductible && this.isDeductibleZero; + return this.verifiedDeductible && this.deductibleValue === 0; default: return null; } }, + // TODO move to common location getTotalLineItemPrice(lineItem) { return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; }, + // TODO use price formatter getDeductibleString(deductible) { const formattedDeductibleFloat = parseFloat(deductible).toFixed(2); return `$${formattedDeductibleFloat}`; }, + // TODO use price formatter getServicePriceString(price) { const formattedPriceFloat = parseFloat(price).toFixed(2); return `$${formattedPriceFloat}`; @@ -467,6 +463,9 @@ export default { }, setSupportingItems(newSupportingItems) { this.supportingItems = newSupportingItems; + }, + setAvailableLineItems(newAvailableLineItems) { + this.availableLineItems = newAvailableLineItems; } } }; diff --git a/src/store/index.js b/src/store/index.js index 114b9989..c2517558 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -947,10 +947,9 @@ export const useMainStore = defineStore({ }, async getSupportingItems() { - const glassPartsArray = this.order.lineItems.glassParts ?? []; - const { carId } = this.order.vehicle; - const { isRepair } = this.order.damage; - const { numberOfChips } = this.order.damage; + const glassPartsArray = this.lineItems.glassParts ?? []; + const { carId } = this.vehicle; + const { isRepair, numberOfChips } = this.damage; return globalMethods .callHttpClient({ From 715490f12f4d0033e508e348a4197031fc8f8053 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 13:39:43 -0500 Subject: [PATCH 05/36] Modifying supporting items --- src/store/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index c2517558..3ae011f1 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -950,6 +950,7 @@ export const useMainStore = defineStore({ const glassPartsArray = this.lineItems.glassParts ?? []; const { carId } = this.vehicle; const { isRepair, numberOfChips } = this.damage; + const { parentAccountNumber } = this.issConfig; return globalMethods .callHttpClient({ @@ -958,7 +959,7 @@ export const useMainStore = defineStore({ payload: { carId, damageType: isRepair ? 'Repair' : 'Replace', - parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, + parentAccountNumber, parts: glassPartsArray, numberOfRepairChips: isRepair ? numberOfChips : 0 } From 7a8c685cecd9b15ac0e224734b68de6073b154ae Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 13:42:37 -0500 Subject: [PATCH 06/36] Adding comment --- src/store/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/store/index.js b/src/store/index.js index 114b9989..8c32d3e9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -144,6 +144,7 @@ const getDefaultState = () => ({ lineItems: { glassParts: null, otherParts: null, + // TODO figure out when this needs set and reset, then just reference supportingItems: null, vaps: null }, From 881a79c7eb9e3920400258038d88eda971beffce Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:08:51 -0500 Subject: [PATCH 07/36] Cleaning up supportingItems setting --- .../coverage-statement/coverage-statement.vue | 5 +- src/layouts/schedule-page/schedule-page.vue | 43 ++------------ .../service-packages/service-packages.vue | 24 ++++++-- src/layouts/vehicle-damage/vehicle-damage.vue | 3 +- src/store/index.js | 56 +++++++------------ 5 files changed, 49 insertions(+), 82 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index f5ab548d..b9877b44 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -369,7 +369,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { - this.mainStore.saveSupportingItems(this.supportingItems); + this.mainStore.updateSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -379,7 +379,8 @@ export default { } else if (this.verifiedITAC || this.verifiedNoComp) { useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); if (this.selectedProvider === 'Safelite') { - this.mainStore.saveSupportingItems(this.supportingItems); + // TODO maybe don't save supporting items on this page + this.mainStore.updateSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route, diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index 5a3fb0d4..13a8315e 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -268,7 +268,9 @@ export default { return { mainStore }; }, data() { + const { supportingItems } = useMainStore().lineItems; return { + supportingItems, selectedDate: this.getSelectedDate(), selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(), selectableDatesData: [], @@ -324,7 +326,7 @@ export default { && ((serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE || serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) || serviceLocation.provider.providerNumber); - const supportingItems = useMainStore().lineItems.supportingItems !== null; + const supportingItems = this.supportingItems !== null; const damageInfo = useMainStore().order.damage.isRepair || (useMainStore().order.lineItems?.glassParts != null @@ -360,9 +362,8 @@ export default { return this.mainStore.order.schedule.date; }, getSelectedTimeSlotInfo() { - const supportingItems = this.getSupportingItems(); const isPremiumAppointment = - !!supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) + !!this.supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) .length > 0; const selectedTimeSlotInfo = { @@ -372,9 +373,6 @@ export default { return selectedTimeSlotInfo; }, - getSupportingItems() { - return this.mainStore.lineItems.supportingItems; - }, timeSlotModalClosed() { // Clear the selectedDate if no timeSlot has been selected if (this.selectedTimeSlotInfo.timeSlot.routeCode == null) { @@ -424,40 +422,7 @@ export default { } return `${hours}:${minutes} ${meridianNotation}`; }, - updateSupportingItems() { - const supportingItems = this.getSupportingItems(); - - // if we have a premium fee(early bird), then save/update supporting items - if ( - this.appointmentType === AppointmentTypeStrings.MOBILE - && this.selectedTimeSlotInfo?.isPremiumAppointment - ) { - const premiumFeeIndex = supportingItems.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE); - - if (premiumFeeIndex >= 0) { - supportingItems[premiumFeeIndex].laborAmount = - this.mobilePremiumAppointmentFee.laborAmount; - supportingItems[premiumFeeIndex].sellingPrice = - this.mobilePremiumAppointmentFee.sellingPrice; - supportingItems[premiumFeeIndex].kitPrice = - this.mobilePremiumAppointmentFee.kitPrice; - } else { - supportingItems.push(this.mobilePremiumAppointmentFee); - } - - this.mainStore.saveSupportingItemsSuppressingStateResetting(supportingItems); - } else { - // if it's not a mobile and/or premium early bird, then make sure we remove any that may have been added - const removePremiumFeeIndex = supportingItems.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE); - - if (removePremiumFeeIndex >= 0) { - supportingItems.splice(removePremiumFeeIndex, 1); - this.mainStore.saveSupportingItemsSuppressingStateResetting(supportingItems); - } - } - }, forwardButtonAction() { - this.updateSupportingItems(); this.mainStore.saveSchedule(this.selectedTimeSlotInfo.timeSlot); this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route); diff --git a/src/layouts/service-packages/service-packages.vue b/src/layouts/service-packages/service-packages.vue index 8644ad85..8226c8a4 100644 --- a/src/layouts/service-packages/service-packages.vue +++ b/src/layouts/service-packages/service-packages.vue @@ -90,6 +90,7 @@ export default { const wipersPromise = await store.getWipers(); const rainDefensePromise = await store.getRainDefense(); + // TODO does this call need to happen here? const supportingItemsPromise = await store.getSupportingItems(); const promiseResultMap = [ { @@ -124,7 +125,13 @@ export default { let hasBailedOut = false; const pricingResults = await store.getPriceOrderItems(availableLineItems) .catch((err) => { - useMainStore().setBailout(to, bailoutMessage.pricingResponseError(availableLineItems.map((li) => li.partNumber), { code: err.code, message: err.message, data: err.data })); + useMainStore().setBailout( + to, + bailoutMessage.pricingResponseError( + availableLineItems.map((li) => li.partNumber), + { code: err.code, message: err.message, data: err.data } + ) + ); hasBailedOut = true; next(`/?issPage=${issPageValues.BAILOUT_PAGE}`); }); @@ -179,15 +186,22 @@ export default { this.selectedVaps = vapsItemsSelected; }, forwardButtonAction() { - const parts = { glassParts: this.pricedGlassParts, supportingItems: this.supportingItems, vaps: this.selectedVaps }; + const parts = { + glassParts: this.pricedGlassParts, + supportingItems: this.supportingItems, + vaps: this.selectedVaps + }; if (!allGlassPartsAndItemsHavePrices(parts)) { window.console.error('One or more items have no price assigned!'); } if (this.pricedGlassParts.length > 0) { - store.saveGlassParts(this.pricedGlassParts); + // TODO saving glass parts here + store.updateGlassParts(this.pricedGlassParts); } - store.saveSupportingItems(this.supportingItems); - store.saveVaps(this.selectedVaps); + // TODO saving supporting items on service packages page + // TODO does the glass parts array change? + store.updateSupportingItems(this.supportingItems); + store.updateVaps(this.selectedVaps); this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route); } diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index dd78afc0..892ec962 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -360,8 +360,9 @@ export default { ); if (this.isWindshieldRepair) { + // TODO only save supporting items on vehicle damage page if windshield repair const supportingItems = await useMainStore().getSupportingItems(); - this.mainStore.saveSupportingItems(supportingItems.data); + useMainStore().updateSupportingItems(supportingItems.data); } if (this.mainStore.damage.isRepair) { diff --git a/src/store/index.js b/src/store/index.js index 8c32d3e9..3954b24b 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -947,11 +947,12 @@ export const useMainStore = defineStore({ }); }, + // TODO this needs called when vehicle, damage, or glass parts changes async getSupportingItems() { - const glassPartsArray = this.order.lineItems.glassParts ?? []; - const { carId } = this.order.vehicle; - const { isRepair } = this.order.damage; - const { numberOfChips } = this.order.damage; + const { glassParts } = this.lineItems; + const { carId } = this.vehicle; + const { isRepair, numberOfChips } = this.damage; + const { parentAccountNumber } = this.issConfig; return globalMethods .callHttpClient({ @@ -960,8 +961,8 @@ export const useMainStore = defineStore({ payload: { carId, damageType: isRepair ? 'Repair' : 'Replace', - parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, - parts: glassPartsArray, + parentAccountNumber, + parts: glassParts ?? [], numberOfRepairChips: isRepair ? numberOfChips : 0 } }); @@ -1434,8 +1435,9 @@ export const useMainStore = defineStore({ this.order.payment.insuranceCoverage.isVerified = false; }, + // Note that this is only used in the store updateSupportingItems(partsData) { - this.order.lineItems.supportingItems = partsData; + this.lineItems.supportingItems = partsData; }, updateVaps(partsData) { @@ -1473,8 +1475,8 @@ export const useMainStore = defineStore({ this.order.originalDeductible = vehicle.deductible; this.order.currentDeductible = vehicle.deductible; - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateSupportingItems(null); + this.updateVaps(null); }, updateVehicleVin(vin) { @@ -1497,6 +1499,7 @@ export const useMainStore = defineStore({ resetGlassPartsState() { this.order.lineItems.glassParts = null; + this.order.lineItems.supportingItems = null; this.order.damage.partQuestionAnswers = null; this.order.damage.moldingQuestionAnswers = null; this.order.damage.capabilityQuestionAnswers = null; @@ -1505,6 +1508,7 @@ export const useMainStore = defineStore({ this.applicationUser.pageData[issPageValues.MOLDING_QUESTIONS] = null; this.applicationUser.pageData[issPageValues.CAPABILITY_QUESTIONS] = null; }, + // TODO when schedule reset, supporting items modified resetSchedule() { this.order.schedule.date = null; this.order.schedule.startTime = null; @@ -1522,12 +1526,6 @@ export const useMainStore = defineStore({ state.order.lineItems.supportingItems = supportingItems; } }, - resetSupportingItemsState() { - this.order.lineItems.supportingItems = null; - }, - resetVapsState() { - this.order.lineItems.vaps = null; - }, resetDamageState() { this.order.damage.isRepair = null; this.order.damage.numberOfChips = null; @@ -1686,8 +1684,8 @@ export const useMainStore = defineStore({ this.updateGlassParts(null); this.updateMoldingQuestionAnswers(null); this.updateCapabilityQuestionAnswers(null); - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateSupportingItems(null); + this.updateVaps(null); this.updatePageData({ page: issPageValues.VEHICLE_PARTS, data: null }); this.updatePageData({ page: issPageValues.MOLDING_QUESTIONS, data: null }); @@ -1731,18 +1729,6 @@ export const useMainStore = defineStore({ // Save new values this.updateCapabilityQuestionAnswers(capabilityQuestionAnswersArray); }, - saveGlassParts(glassParts) { - this.order.lineItems.glassParts = glassParts; - }, - saveSupportingItems(supportingItems) { - this.order.lineItems.supportingItems = supportingItems; - }, - saveSupportingItemsSuppressingStateResetting(supportingItems) { - this.order.lineItems.supportingItems = supportingItems; - }, - saveVaps(vaps) { - this.order.lineItems.vaps = vaps; - }, // Price order actions async priceOrderItemsAndSaveServerData(availableLineItems, serviceZipCode, serviceZipCodeCtu) { @@ -2044,6 +2030,7 @@ export const useMainStore = defineStore({ if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); + // TODO probably reset supporting items } // Save new values @@ -2062,6 +2049,7 @@ export const useMainStore = defineStore({ if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); + // TODO probably reset supporting items } // Save new values @@ -2078,6 +2066,7 @@ export const useMainStore = defineStore({ // Dependencies already cleared in above statement this.resetDamageState(); this.resetGlassPartsState(); + // TODO reset supporting items state } // Save new values @@ -2111,21 +2100,18 @@ export const useMainStore = defineStore({ resetRegistrationAndDependencies() { this.resetRegistrationState(); this.resetGlassPartsState(); - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateVaps(null); }, resetDamageAndDependencies() { this.resetDamageState(); this.resetGlassPartsState(); - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateVaps(null); }, resetPartsAndDependencies() { this.resetGlassPartsState(); - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateVaps(null); this.resetServiceLocationAndDependencies(); }, From c8b491cbbd3eb808e448aea9fa28dae4c9ae31f7 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:10:23 -0500 Subject: [PATCH 08/36] Removing comment --- src/layouts/coverage-statement/coverage-statement.vue | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index b9877b44..7338f1ad 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -369,7 +369,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { - this.mainStore.updateSupportingItems(this.supportingItems); + useMainStore().updateSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -379,8 +379,7 @@ export default { } else if (this.verifiedITAC || this.verifiedNoComp) { useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); if (this.selectedProvider === 'Safelite') { - // TODO maybe don't save supporting items on this page - this.mainStore.updateSupportingItems(this.supportingItems); + useMainStore().updateSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route, From de406b6fbbb688fc5a3ad4372199b6f15a5d702d Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:12:22 -0500 Subject: [PATCH 09/36] Removing comment --- src/layouts/service-packages/service-packages.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/service-packages/service-packages.vue b/src/layouts/service-packages/service-packages.vue index 8226c8a4..52fc9ba1 100644 --- a/src/layouts/service-packages/service-packages.vue +++ b/src/layouts/service-packages/service-packages.vue @@ -90,7 +90,6 @@ export default { const wipersPromise = await store.getWipers(); const rainDefensePromise = await store.getRainDefense(); - // TODO does this call need to happen here? const supportingItemsPromise = await store.getSupportingItems(); const promiseResultMap = [ { From e359126d3dd02f536eace2b355262300d48f6c74 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:14:17 -0500 Subject: [PATCH 10/36] Removing comment --- src/layouts/service-packages/service-packages.vue | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/layouts/service-packages/service-packages.vue b/src/layouts/service-packages/service-packages.vue index 52fc9ba1..ea1cb229 100644 --- a/src/layouts/service-packages/service-packages.vue +++ b/src/layouts/service-packages/service-packages.vue @@ -194,11 +194,8 @@ export default { window.console.error('One or more items have no price assigned!'); } if (this.pricedGlassParts.length > 0) { - // TODO saving glass parts here store.updateGlassParts(this.pricedGlassParts); } - // TODO saving supporting items on service packages page - // TODO does the glass parts array change? store.updateSupportingItems(this.supportingItems); store.updateVaps(this.selectedVaps); From 63872cd9000c187ef1b67c71ac081f293c2d88ec Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:15:15 -0500 Subject: [PATCH 11/36] Removing comment --- src/layouts/vehicle-damage/vehicle-damage.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index 892ec962..2771b30e 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -360,7 +360,6 @@ export default { ); if (this.isWindshieldRepair) { - // TODO only save supporting items on vehicle damage page if windshield repair const supportingItems = await useMainStore().getSupportingItems(); useMainStore().updateSupportingItems(supportingItems.data); } From 3a75fe9658a7537fd3b1c5dddd6f21a61e7cb74d Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:16:07 -0500 Subject: [PATCH 12/36] Removing comment --- src/store/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 3954b24b..be6c7343 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -144,7 +144,6 @@ const getDefaultState = () => ({ lineItems: { glassParts: null, otherParts: null, - // TODO figure out when this needs set and reset, then just reference supportingItems: null, vaps: null }, From 60012cb033681ab4f410115f19211af9eccb4392 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:16:45 -0500 Subject: [PATCH 13/36] Removing comment --- src/store/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index be6c7343..49027c3c 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -946,7 +946,6 @@ export const useMainStore = defineStore({ }); }, - // TODO this needs called when vehicle, damage, or glass parts changes async getSupportingItems() { const { glassParts } = this.lineItems; const { carId } = this.vehicle; From c7ffb35e4c672ea7bfac62ae6a07ab6b2f687164 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:17:24 -0500 Subject: [PATCH 14/36] Removing comment --- src/store/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 49027c3c..098b7f84 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1433,9 +1433,8 @@ export const useMainStore = defineStore({ this.order.payment.insuranceCoverage.isVerified = false; }, - // Note that this is only used in the store updateSupportingItems(partsData) { - this.lineItems.supportingItems = partsData; + this.order.lineItems.supportingItems = partsData; }, updateVaps(partsData) { From e5709444f9c5745b03334dac9c20371141b67fd9 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:19:36 -0500 Subject: [PATCH 15/36] Removing comment --- src/store/index.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 098b7f84..3aad08dc 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1505,7 +1505,6 @@ export const useMainStore = defineStore({ this.applicationUser.pageData[issPageValues.MOLDING_QUESTIONS] = null; this.applicationUser.pageData[issPageValues.CAPABILITY_QUESTIONS] = null; }, - // TODO when schedule reset, supporting items modified resetSchedule() { this.order.schedule.date = null; this.order.schedule.startTime = null; @@ -1513,15 +1512,6 @@ export const useMainStore = defineStore({ this.order.schedule.routeCode = null; this.order.schedule.jobMaxMinutes = null; this.order.schedule.jobMinMinutes = null; - - // premium appointment fee used on schedule page also needs reset when schedule is reset - const { supportingItems } = this.order.lineItems; - const premiumAppointmentFeeIndex = supportingItems?.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE); - - if (premiumAppointmentFeeIndex >= 0) { - supportingItems.splice(premiumAppointmentFeeIndex, 1); - state.order.lineItems.supportingItems = supportingItems; - } }, resetDamageState() { this.order.damage.isRepair = null; @@ -2027,7 +2017,6 @@ export const useMainStore = defineStore({ if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); - // TODO probably reset supporting items } // Save new values @@ -2046,7 +2035,6 @@ export const useMainStore = defineStore({ if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); - // TODO probably reset supporting items } // Save new values From 21d811c815343761f10cba1405ba59d32aa03c92 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:20:12 -0500 Subject: [PATCH 16/36] Removing comment --- src/store/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 3aad08dc..3ba028ec 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2051,7 +2051,6 @@ export const useMainStore = defineStore({ // Dependencies already cleared in above statement this.resetDamageState(); this.resetGlassPartsState(); - // TODO reset supporting items state } // Save new values From 9ddc157ed3616d69e273dc409dbb11805b87527a Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 4 Mar 2024 15:38:08 -0500 Subject: [PATCH 17/36] display service duration --- .../order-confirmation/order-confirmation.vue | 94 +++++++++++++++---- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 38f2dc9e..775630ef 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -29,6 +29,10 @@ class="appointment-text text-center text-color--black lh-base" v-html="appointmentWordingText"> +
+
${this.providerAddress},
${this.providerCity}, ${this.providerState} ${this.providerZipCode}
`; }, appointmentWordingText() { - return this.formatWordingText(this.appointmentType); + switch (this.appointmentType) { + case 'MOBILE': + return this.mobileWordingText?.replaceAll( + '{custom:address}', + this.serviceLocationFullAddress + ); + case 'DROP OFF': + return this.dropOffAndInShopWordingText?.replaceAll( + '{custom:address}', + this.providerFullAddress + ); + case 'INSHOP': + return this.dropOffAndInShopWordingText?.replaceAll( + '{custom:address}', + this.providerFullAddress + ); + default: + return null; + } + }, + appointmentWordingText2() { + switch (this.appointmentType) { + case 'MOBILE': + return this.mobileWordingText2; + case 'DROP OFF': + return this.dropOffAndInShopWordingText2; + case 'INSHOP': + return this.dropOffAndInShopWordingText2?.replaceAll( + '{custom:inShopDuration}', + this.inShopAppointmentDuration + ); + default: + return null; + } + }, + mobileAppointment() { + return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'MOBILE'; + }, + inShopAppointment() { + return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'INSHOP'; + }, + dropOffAppointment() { + return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'DROP OFF'; + }, + inShopAppointmentDuration() { + const inshopDurationTime = getDisplayTextForDurationLength( + this.mainStore.order.schedule.jobMinMinutes, + this.mainStore.order.schedule.jobMaxMinutes + ); + return inshopDurationTime; } }, mounted() { @@ -192,23 +252,17 @@ export default { return null; } }, - formatWordingText(appointmentType) { - switch (appointmentType) { - case 'MOBILE': - return this.mobileWordingText?.replaceAll( - '{custom:address}', - this.serviceLocationFullAddress - ); - case 'DROP OFF': - return this.dropOffAndInShopWordingText?.replaceAll( - '{custom:address}', - this.providerFullAddress - ); - case 'INSHOP': - return this.dropOffAndInShopWordingText?.replaceAll( - '{custom:address}', - this.providerFullAddress - ); + processIfStatements, + getBodyText2FromCms(cmsWidgetName) { + const body2Text = this.getCmsContent(cmsWidgetName, 'BodyText2'); + return this.processIfStatements(body2Text, 'custom', this.getCustomValueFromString); + }, + getCustomValueFromString(str) { + switch (str) { + case 'inShopAppointment': + return this.inShopAppointment; + case 'dropOffAppointment': + return this.dropOffAppointment; default: return null; } From 7651441115e2f08cd49e8eee4accb4dc7eb027af Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 4 Mar 2024 15:42:00 -0500 Subject: [PATCH 18/36] style fix --- src/layouts/order-confirmation/order-confirmation.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 775630ef..4b299b07 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -26,11 +26,11 @@

{{ appointmentTimeFormatted }}

@@ -308,6 +308,7 @@ $page-side-padding: 1.5rem; .appointment-text { :deep(strong) { font-weight: $font-weight-bold; + color: $black; } } From 24103335eec282fad8ded09087cf8502b0150ad6 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:46:31 -0500 Subject: [PATCH 19/36] Fixing tests --- .../schedule-page/schedule-page.spec.js | 79 ------------------- src/layouts/schedule-page/schedule-page.vue | 7 +- 2 files changed, 4 insertions(+), 82 deletions(-) diff --git a/src/layouts/schedule-page/schedule-page.spec.js b/src/layouts/schedule-page/schedule-page.spec.js index bc0d80df..c025ece6 100644 --- a/src/layouts/schedule-page/schedule-page.spec.js +++ b/src/layouts/schedule-page/schedule-page.spec.js @@ -75,8 +75,6 @@ function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { } }); - // mountOptions.global.mocks["$store"] = store; - mountOptions.global.stubs = { siteFooter: footerStub, loadingModal: loadingModalStub @@ -337,81 +335,4 @@ describe('schedule-page.vue', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); }); - test('for mobile appts, updateSupportingItems should call store action to save supporting items', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE; - wrapper.vm.mobilePremiumAppointmentFee = 14.99; - wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = true; - wrapper.vm.mainStore.lineItems.supportingItems = [ - { - partNumber: 'EARLY BIRD', - description: null, - partType: 'EARLY BIRD', - laborAmount: 0, - sellingPrice: 0, - kitPrice: 0 - } - ]; - const store = useMainStore(); - - // Act - await wrapper.vm.updateSupportingItems(); - - // Assert - expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(1); - expect(wrapper.vm.mainStore.lineItems.supportingItems) - .toEqual(expect.arrayContaining([ - expect.objectContaining({ - partType: 'EARLY BIRD' - }) - ])); - }); - test( - 'for Inshop appts, updateSupportingItems should call store action to save supporting items WITHOUT the EARLY BIRD supporting item', - async () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP; - wrapper.vm.mobilePremiumAppointmentFee = 14.99; - wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = true; - wrapper.vm.mainStore.lineItems.supportingItems = [ - { - partNumber: 'EARLY BIRD', - description: null, - partType: 'EARLY BIRD', - laborAmount: 0, - sellingPrice: 0, - kitPrice: 0 - } - ]; - const store = useMainStore(); - - // Act - await wrapper.vm.updateSupportingItems(); - - // Assert - expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(1); - expect(wrapper.vm.mainStore.lineItems.supportingItems) - .not.toEqual(expect.arrayContaining([ - expect.objectContaining({ - partType: 'EARLY BIRD' - }) - ])); - } - ); - test('if no EARLY BIRD supporting item, then updateSupportingItems should NOT call store action', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE; - wrapper.vm.mobilePremiumAppointmentFee = 14.99; - wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = false; - wrapper.vm.mainStore.lineItems.supportingItems = []; - const store = useMainStore(); - // Act - await wrapper.vm.updateSupportingItems(); - - // Assert - expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(0); - }); }); diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index 13a8315e..4636b834 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -268,9 +268,7 @@ export default { return { mainStore }; }, data() { - const { supportingItems } = useMainStore().lineItems; return { - supportingItems, selectedDate: this.getSelectedDate(), selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(), selectableDatesData: [], @@ -293,6 +291,9 @@ export default { } return this.selectableDatesData.days?.find((selectableDate) => selectableDate.date === this.selectedDate); + }, + supportingItems() { + return useMainStore().lineItems.supportingItems; } }, watch: { @@ -363,7 +364,7 @@ export default { }, getSelectedTimeSlotInfo() { const isPremiumAppointment = - !!this.supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) + !!(this.supportingItems?.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) ?? []) .length > 0; const selectedTimeSlotInfo = { From 4e4f99f7c90d4e583cd47fb107e44225ebbca8b5 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Tue, 5 Mar 2024 10:05:55 -0500 Subject: [PATCH 20/36] Moving line item pricing to price calculator --- src/helpers/price-calculator.js | 10 ++ src/helpers/price-calculator.spec.js | 56 +++++++++++ .../coverage-statement/coverage-statement.vue | 92 +++++++------------ 3 files changed, 99 insertions(+), 59 deletions(-) create mode 100644 src/helpers/price-calculator.js create mode 100644 src/helpers/price-calculator.spec.js diff --git a/src/helpers/price-calculator.js b/src/helpers/price-calculator.js new file mode 100644 index 00000000..9e69259b --- /dev/null +++ b/src/helpers/price-calculator.js @@ -0,0 +1,10 @@ +function getPriceOfLineItem(lineItem) { + return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; +} + +export default function getPriceOfLineItems(lineItems) { + return lineItems.reduce( + (accumulator, lineItem) => accumulator + getPriceOfLineItem(lineItem), + 0 + ); +} diff --git a/src/helpers/price-calculator.spec.js b/src/helpers/price-calculator.spec.js new file mode 100644 index 00000000..4d09128b --- /dev/null +++ b/src/helpers/price-calculator.spec.js @@ -0,0 +1,56 @@ +import getPriceOfLineItems from "@/helpers/price-calculator.js"; + +describe('getPriceOfLineItems', () => { + test('Returns zero when no line items', () => { + // Arrange + const lineItems = []; + + // Act + const result = getPriceOfLineItems(lineItems); + + // Assert + expect(result).toBe(0); + }); + test('Returns expected when one line item', () => { + // Arrange + const lineItems = [ + { + kitPrice: 1, + laborAmount: 2, + sellingPrice: 3 + } + ]; + const expected = 6; + + // Act + const result = getPriceOfLineItems(lineItems); + + // Assert + expect(result).toBe(expected); + }); + test('Returns expected when multiple line items', () => { + // Arrange + const lineItems = [ + { + kitPrice: 1, + laborAmount: 2, + sellingPrice: 3 + }, + { + kitPrice: 1 + }, + { + kitPrice: 10, + laborAmount: 100, + sellingPrice: 1000 + } + ]; + const expected = 1117; + + // Act + const result = getPriceOfLineItems(lineItems); + + // Assert + expect(result).toBe(expected); + }); +}); diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index b6ed7771..5ac78138 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -40,7 +40,7 @@
- {{ formattedServicePrice }} + {{ servicePriceForDisplay }}
this.totalServicePrice; }, - // TODO maybe tweak coveredAndServicePriceAboveOrEqualDeductible() { return !this.verifiedNoComp && this.totalServicePrice >= this.deductibleValue; }, @@ -316,21 +321,17 @@ export default { const parts = useMainStore().order.lineItems.glassParts; return parts !== null && !!parts.find((part) => part.requiresRecalibration); }, - // TODO replace with better method totalServicePrice() { - let total = 0; - this.availableLineItems.forEach((lineItem) => { - total += this.getTotalLineItemPrice(lineItem); - }); - return total; + return getPriceOfLineItems(this.baseServiceLineItems); }, - formattedServicePrice() { - return this.getServicePriceString(this.totalServicePrice); + servicePriceForDisplay() { + return this.getFormattedAmount(this.totalServicePrice); }, - costSavings() { - const savings = this.getITACCostSavings(this.deductibleValue, this.totalServicePrice); - const formattedSavings = parseFloat(savings).toFixed(2); - return `$${formattedSavings}`; + itacCostSavings() { + return this.deductibleValue - this.totalServicePrice; + }, + itacCostSavingsForDisplay() { + return this.getFormattedAmount(this.itacCostSavings); }, serviceProviderQuestionText() { return this.getCmsContent( @@ -367,10 +368,13 @@ export default { arePagePrerequisitesValid() { return !!useMainStore().vehicle.carId; }, + getFormattedAmount(amount) { + return this.currencyFormatter.format(amount); + }, async initializeComponent() { useMainStore().updatePolicyITACFlag(this.verifiedITAC); if (this.policyLookupSuccessful - && useMainStore().order.vehicle.policyVehicleId >= 0 + && useMainStore().vehicle.policyVehicleId >= 0 && useMainStore().isClaimRegistrationRequired && !useMainStore().isClaimAlreadyRegistered && (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC)) { @@ -380,11 +384,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { -<<<<<<< HEAD - useMainStore().saveSupportingItems(this.supportingItems); -======= useMainStore().updateSupportingItems(this.supportingItems); ->>>>>>> 24103335eec282fad8ded09087cf8502b0150ad6 this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -392,37 +392,28 @@ export default { { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else if (this.verifiedITAC || this.verifiedNoComp) { -<<<<<<< HEAD useMainStore().updateIsSafeliteProvider(this.selectedProvider === SAFELITE_PROVIDER); if (this.selectedProvider === SAFELITE_PROVIDER) { - useMainStore().saveSupportingItems(this.supportingItems); -======= - useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); - if (this.selectedProvider === 'Safelite') { useMainStore().updateSupportingItems(this.supportingItems); ->>>>>>> 24103335eec282fad8ded09087cf8502b0150ad6 this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, - this.$route, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + this.$route ); } else { useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, - this.$route, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + this.$route ); } } else { - useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.coverageStatementInvalidState()); + useMainStore().setBailout( + this.$router.currentRoute, + bailoutMessage.coverageStatementInvalidState() + ); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE, - this.$route, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + this.$route ); } }, @@ -454,28 +445,11 @@ export default { return null; } }, - // TODO move to common location - getTotalLineItemPrice(lineItem) { - return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; - }, - // TODO use price formatter - getDeductibleString(deductible) { - const formattedDeductibleFloat = parseFloat(deductible).toFixed(2); - return `$${formattedDeductibleFloat}`; - }, - // TODO use price formatter - getServicePriceString(price) { - const formattedPriceFloat = parseFloat(price).toFixed(2); - return `$${formattedPriceFloat}`; - }, - getITACCostSavings(vehicleDeductible, totalServicePrice) { - return vehicleDeductible - totalServicePrice; - }, setSupportingItems(newSupportingItems) { this.supportingItems = newSupportingItems; }, - setAvailableLineItems(newAvailableLineItems) { - this.availableLineItems = newAvailableLineItems; + setBaseServiceLineItems(lineItems) { + this.baseServiceLineItems = lineItems; } } }; @@ -485,7 +459,7 @@ export default { .cost { color: $green; font-size: 2rem; - font-weight: 300; + font-weight: $font-weight-light; line-height: 2.75rem; } From d5bf56418ac6a9fc8cc31d466c8ef03dff66d6e2 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Tue, 5 Mar 2024 10:40:12 -0500 Subject: [PATCH 21/36] Starting outline of tests --- src/helpers/price-calculator.js | 4 +- .../coverage-statement.spec.js | 54 +++++++++++++++++++ .../coverage-statement/coverage-statement.vue | 2 +- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/helpers/price-calculator.js b/src/helpers/price-calculator.js index 9e69259b..b44abc5a 100644 --- a/src/helpers/price-calculator.js +++ b/src/helpers/price-calculator.js @@ -1,5 +1,7 @@ function getPriceOfLineItem(lineItem) { - return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; + return (lineItem?.kitPrice ?? 0) + + (lineItem?.laborAmount ?? 0) + + (lineItem?.sellingPrice ?? 0); } export default function getPriceOfLineItems(lineItems) { diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index a597b7f9..79765a88 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -828,6 +828,60 @@ describe.skip('coverageStatement.vue', () => { }); describe('coverageStatement.vue-working', () => { + // test('initial data is as expected', () => {}); + describe('Rendering', () => { + test('Should render site header', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const siteHeader = wrapper.findComponent({ ref: 'siteHeader' }); + + // Assert + expect(siteHeader.exists()).toBe(true); + }); + test('Should render site subheader', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const subheader = wrapper.find({ ref: 'siteSubHeader' }); + + // Assert + expect(subheader.exists()).toBe(true); + }); + + test('Should render explanatory text', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const explanatoryText = wrapper.find({ ref: 'explanatoryText' }); + + // Assert + expect(explanatoryText.exists()).toBe(true); + }); + test('Should render secondary text', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const secondaryText = wrapper.find({ ref: 'secondaryText' }); + + // Assert + expect(secondaryText.exists()).toBe(true); + }); + test('Should render site footer', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const footer = wrapper.findComponent({ ref: 'siteFooter' }); + + // Assert + expect(footer.exists()).toBe(true); + }); + }); describe('ITAC flag', () => { test('ITAC flag updated once component is initialized', async () => { // Arrange diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 5ac78138..8776ebe1 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -200,7 +200,7 @@ export default { vm.setCmsContent(resultMap.cmsContent); vm.setSupportingItems(resultMap.supportingItems); // eslint-disable-next-line no-param-reassign - vm.setAvailableLineItems(pricingResults); + vm.setBaseServiceLineItems(pricingResults); vm.$refs.loadingModal.showModal(); vm.initializeComponent(); if (!vm.unverified) { From 8e9302df405fa18d31160ebdcc422d97722cf0d1 Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Tue, 27 Feb 2024 16:46:34 -0500 Subject: [PATCH 22/36] SSR-1081 handling payment return info from hop --- src/constants/query-strings.js | 17 +- src/constants/web-storage-constants.js | 5 + src/helpers/querystring-helper.js | 11 ++ src/layouts/payment-page/payment-page.vue | 8 +- src/layouts/payment-return/payment-return.vue | 145 ++++++++++++++++++ .../router-constants/navigation-scenarios.js | 3 + src/router/router-constants/routing-table.js | 17 ++ src/store/index.js | 76 +++++++-- 8 files changed, 261 insertions(+), 21 deletions(-) create mode 100644 src/constants/web-storage-constants.js create mode 100644 src/helpers/querystring-helper.js create mode 100644 src/layouts/payment-return/payment-return.vue diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 9b486517..f217dea4 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -1,5 +1,20 @@ const queryStrings = Object.freeze({ - ISS_PAGE: 'issPage' + ISS_PAGE: 'issPage', + ERROR: 'error', + SUBSCRIPTIONID: 'subscriptionid', + REFERRAL_SEQ_NUM: 'referralseqnum', + CARD_EXPIRATION_MONTH: 'card_expirationmonth', + CARD_EXPIRATION_YEAR: 'card_expirationyear', + CARD_TYPE: 'sgcardtype', + BILL_TO_POSTAL_CODE: 'billto_postalcode', + BILL_TO_FIRST_NAME: 'billto_firstname', + BILL_TO_LAST_NAME: 'billto_lastname', + REFERENCE_NUMBER: 'req_reference_number', + AUTH_CODE: 'auth_code', + TRANSACTION_ID: 'transaction_id', + TRANS_REFERENCE_NUMBER: 'auth_trans_ref_no', + LAST_FOUR: 'last_four', + DISPLAY_PAY_IN_ADVANCE_ALERT: 'displayPayInAdvanceAlert' }); export default queryStrings; diff --git a/src/constants/web-storage-constants.js b/src/constants/web-storage-constants.js new file mode 100644 index 00000000..29c814cf --- /dev/null +++ b/src/constants/web-storage-constants.js @@ -0,0 +1,5 @@ +const webStorageConstants = Object.freeze({ + SUBMITTED_ORDER: 'submittedOrder' +}); + +export default webStorageConstants; diff --git a/src/helpers/querystring-helper.js b/src/helpers/querystring-helper.js new file mode 100644 index 00000000..32900e96 --- /dev/null +++ b/src/helpers/querystring-helper.js @@ -0,0 +1,11 @@ +export default function getQuerystringParameter(key) { + const queryString = window.location.search; + const urlParams = new URLSearchParams(queryString); + const lowerCaseParams = new URLSearchParams(); + + urlParams.forEach((value, name) => { + lowerCaseParams.append(name.toLowerCase(), value); + }); + + return lowerCaseParams.get(key.toLowerCase()); +} diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index 7612e842..1f77de74 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -460,15 +460,11 @@ export default { computed: { payInAdvanceResponseUrl() { const { protocol, host } = window.location; - return `${protocol}//${host}/?issPage=${ - issPageValues.PAYMENT_RETURN - }&src=iss-nextgen`; + return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN}&src=iss-nextgen`; }, payInAdvanceCancelUrl() { const { protocol, host } = window.location; - return `${protocol}//${host}/?issPage=${ - issPageValues.PAYMENT_METHOD - }&src=iss-nextgen`; + return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_METHOD}&src=iss-nextgen`; }, dynamicCSSUrl() { const { protocol, hostname, port } = window.location; diff --git a/src/layouts/payment-return/payment-return.vue b/src/layouts/payment-return/payment-return.vue new file mode 100644 index 00000000..1ef57a4b --- /dev/null +++ b/src/layouts/payment-return/payment-return.vue @@ -0,0 +1,145 @@ + + + diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 967b99d4..bd079640 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -96,6 +96,9 @@ const navigationScenarios = Object.freeze({ // Payment CLICKED_PAY_NOW: 'CLICKED_PAY_NOW', + PAY_IN_ADVANCE_ERROR: 'PAY_IN_ADVANCE_ERROR', + PAY_IN_ADVANCE_CREDIT_CARD_ERROR: 'PAY_IN_ADVANCE_CREDIT_CARD_ERROR', + PAY_IN_ADVANCE_SUCCESS: 'PAY_IN_ADVANCE_SUCCESS', // Bailout CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index d20f59cd..60d76dcd 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -641,6 +641,23 @@ const routingTable = () => [ } ] }, + { + issPageValue: issPageValues.PAYMENT_RETURN, + maps: [ + { + scenario: navigationScenarios.PAY_IN_ADVANCE_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_METHOD + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_CREDIT_CARD_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_PAGE + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, + destinationIssPageValue: issPageValues.CONFIRMATION + }, + ] + }, { issPageValue: issPageValues.TPA_CONFIRMATION, maps: [ diff --git a/src/store/index.js b/src/store/index.js index 3ba028ec..cc1b2986 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -19,6 +19,7 @@ import { noCoverageForSelectedVehicle, repairWaivedForSelectedVehicle } from '@/helpers/policy-vehicle-helper'; +import webStorageConstants from '@/constants/web-storage-constants'; const storeId = 'main'; @@ -155,7 +156,21 @@ const getDefaultState = () => ({ }, parentAccountNumber: 0, isPayInAdvance: null, - payInAdvanceType: null + payInAdvanceType: null, + ccToken: { + subscriptionId: null, + expMonth: null, + expYear: null, + cardType: null, + billToPostalCode: null, + billToFirstName: null, + billToLastName: null, + referenceNumber: null, + authCode: null, + transactionId: null, + transReferenceNumber: null, + lastFour: null + } }, contactInfo: { firstName: null, @@ -934,18 +949,6 @@ export const useMainStore = defineStore({ }); }, - getCarrierAccountInfo() { - return new Promise((resolve, reject) => { - globalMethods.callHttpClient({ - method: endpoints.GetAccountInfo.method, - endpoint: endpoints.GetAccountInfo.url + this.issConfig.parentAccountNumber - }).then((response) => { - this.order.carrierPhoneNumber = response.data.phoneNumber; - return resolve(response.data); - }).catch((error) => reject(error)); - }); - }, - async getSupportingItems() { const { glassParts } = this.lineItems; const { carId } = this.vehicle; @@ -1383,6 +1386,10 @@ export const useMainStore = defineStore({ this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter; }, + resetState() { + Object.assign(this, getDefaultState()); + }, + resetRegistrationState() { this.order.vehicle.registration.licensePlate = null; this.order.vehicle.registration.address = null; @@ -2135,7 +2142,48 @@ export const useMainStore = defineStore({ method: endpoints.GetPaymentSignature.method, endpoint: endpoints.GetPaymentSignature.url }); - } + }, + + updateCCToken(ccToken) { + this.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; + this.order.payment.ccToken.expMonth = ccToken.expMonth; + this.order.payment.ccToken.expYear = ccToken.expYear; + this.order.payment.ccToken.cardType = ccToken.cardType; + this.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; + this.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; + this.order.payment.ccToken.billToLastName = ccToken.billToLastName; + this.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; + this.order.payment.ccToken.authCode = ccToken.authCode; + this.order.payment.ccToken.transactionId = ccToken.transactionId; + this.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; + this.order.payment.ccToken.lastFour = ccToken.lastFour; + }, + + hasSubmittedOrder() { + return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; + }, + + createSubmittedOrder() { + if (this.hasSubmittedOrder()) { + return; + } + const submittedOrder = this.order; + const { experiments } = this.applicationUser; + + // set to local storage + window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); + + // clear vuex + this.resetState(); + + // restore user's experiments + this.applicationUser.experiments = experiments; + }, + + resetSubmittedOrder() { + // clear from local storage + window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); + }, }, persist: true From 1a5b958b8c53309805079b319477024f53199303 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 4 Mar 2024 14:39:41 -0500 Subject: [PATCH 23/36] reorder alphabetically sans isspage --- src/constants/query-strings.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index f217dea4..576d1e5b 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -1,20 +1,21 @@ const queryStrings = Object.freeze({ ISS_PAGE: 'issPage', - ERROR: 'error', - SUBSCRIPTIONID: 'subscriptionid', - REFERRAL_SEQ_NUM: 'referralseqnum', + AUTH_CODE: 'auth_code', + BILL_TO_FIRST_NAME: 'billto_firstname', + BILL_TO_LAST_NAME: 'billto_lastname', + BILL_TO_POSTAL_CODE: 'billto_postalcode', CARD_EXPIRATION_MONTH: 'card_expirationmonth', CARD_EXPIRATION_YEAR: 'card_expirationyear', CARD_TYPE: 'sgcardtype', - BILL_TO_POSTAL_CODE: 'billto_postalcode', - BILL_TO_FIRST_NAME: 'billto_firstname', - BILL_TO_LAST_NAME: 'billto_lastname', - REFERENCE_NUMBER: 'req_reference_number', - AUTH_CODE: 'auth_code', - TRANSACTION_ID: 'transaction_id', - TRANS_REFERENCE_NUMBER: 'auth_trans_ref_no', + DISPLAY_PAY_IN_ADVANCE_ALERT: 'displayPayInAdvanceAlert', + ERROR: 'error', LAST_FOUR: 'last_four', - DISPLAY_PAY_IN_ADVANCE_ALERT: 'displayPayInAdvanceAlert' + REFERENCE_NUMBER: 'req_reference_number', + REFERRAL_SEQ_NUM: 'referralseqnum', + SUBSCRIPTIONID: 'subscriptionid', + TRANS_REFERENCE_NUMBER: 'auth_trans_ref_no', + TRANSACTION_ID: 'transaction_id' + }); export default queryStrings; From ff5f8c5b29dcf2d3b84a38743bc199c70357ee6a Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 4 Mar 2024 16:06:54 -0500 Subject: [PATCH 24/36] Small tweaks --- src/helpers/order-helper.js | 37 ++++++++---- src/helpers/querystring-helper.js | 2 +- src/layouts/payment-return/payment-return.vue | 57 +++++++++++-------- src/router/index.js | 12 ++-- src/router/router-constants/routing-table.js | 4 +- src/store/index.js | 43 +++++++------- 6 files changed, 91 insertions(+), 64 deletions(-) diff --git a/src/helpers/order-helper.js b/src/helpers/order-helper.js index 85d0bec2..33e7d3c4 100644 --- a/src/helpers/order-helper.js +++ b/src/helpers/order-helper.js @@ -1,6 +1,17 @@ import { useMainStore } from '@/store'; import { updateOrCreateISSCookie } from '@/helpers/cookie-helper'; +/* + Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing +*/ +async function saveSessionHelper(store) { + const savedSessionInfo = await store.saveSession(); + if (savedSessionInfo) { + store.setSaveSessionInfo(savedSessionInfo.data); + } + updateOrCreateISSCookie(); +} + /* Will call API to save existing order, or create new one depending where it's called from. This will also set Referral information in the store after saving, and then @@ -8,8 +19,8 @@ import { updateOrCreateISSCookie } from '@/helpers/cookie-helper'; */ export async function saveSession({ shouldAwaitSaveSessionQueue = false }) { const store = useMainStore(); - var saveSessionPromise = store.applicationUser.saveSessionPromise - ? store.applicationUser.saveSessionPromise.then(() => { return saveSessionHelper(store); }) + const saveSessionPromise = store.applicationUser.saveSessionPromise + ? store.applicationUser.saveSessionPromise.then(() => saveSessionHelper(store)) : saveSessionHelper(store); store.setSaveSessionPromise(saveSessionPromise); @@ -20,12 +31,18 @@ export async function saveSession({ shouldAwaitSaveSessionQueue = false }) { } /* - Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing + Will determine if to submitWorkOrder. + TODO: Add more description to this */ -async function saveSessionHelper(store) { - const savedSessionInfo = await store.saveSession(); - if (savedSessionInfo) { - store.setSaveSessionInfo(savedSessionInfo.data); - } - updateOrCreateISSCookie(); -} \ No newline at end of file +export async function submitWorkOrder({ + pageNameToLog, + submitAfterSave = false, + createDeleteStatusWorkOrderForPia = false +}) { + await saveSession({ + pageNameToLog, + shouldAwaitSaveSessionQueue: true, + submitAfterSave, + createDeleteStatusWorkOrderForPia + }); +} diff --git a/src/helpers/querystring-helper.js b/src/helpers/querystring-helper.js index 32900e96..f4df1ed7 100644 --- a/src/helpers/querystring-helper.js +++ b/src/helpers/querystring-helper.js @@ -1,4 +1,4 @@ -export default function getQuerystringParameter(key) { +export default function getQueryStringParameter(key) { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const lowerCaseParams = new URLSearchParams(); diff --git a/src/layouts/payment-return/payment-return.vue b/src/layouts/payment-return/payment-return.vue index 1ef57a4b..329badf9 100644 --- a/src/layouts/payment-return/payment-return.vue +++ b/src/layouts/payment-return/payment-return.vue @@ -11,8 +11,10 @@ import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store/index.js'; import queryStrings from '@/constants/query-strings'; -import getQuerystringParameter from '@/helpers/querystring-helper.js'; +import getQueryStringParameter from '@/helpers/querystring-helper.js'; import { paymentMethods } from '@/constants/payment-method-constants.js'; +import { submitWorkOrder } from '@/helpers/order-helper.js'; +import showIssLoadingModal from '@/helpers/loading-modal-helper'; export default { name: 'payment-return', @@ -22,14 +24,14 @@ export default { }, mixins: [BaseFormMixin], async mounted() { - const payInAdvanceError = getQuerystringParameter(queryStrings.ERROR); + showIssLoadingModal(true); + const payInAdvanceError = getQueryStringParameter(queryStrings.ERROR); const { payInAdvanceType } = useMainStore().order.payment; if (payInAdvanceError) { console.error(`Error during payment: ${payInAdvanceError}`); const paymentPageNavScenario = - payInAdvanceType === paymentMethods.CREDIT_CARD - || payInAdvanceType === paymentMethods.AFTERPAY; + payInAdvanceType === paymentMethods.CREDIT_CARD || payInAdvanceType === paymentMethods.AFTERPAY; if (paymentPageNavScenario) { this.$router.navigate( this.navigationScenarios.PAY_IN_ADVANCE_CREDIT_CARD_ERROR, @@ -71,10 +73,16 @@ export default { arePagePrerequisitesValid() { return true; }, - async processCreditCardResponse() { - const subscriptionId = getQuerystringParameter(queryStrings.SUBSCRIPTIONID); + async processPaypalResponse() { + const token = getQueryStringParameter(queryStrings.TOKEN); + this.mainStore.updatePaypalToken(token); - const referralSeqNum = getQuerystringParameter(queryStrings.REFERRAL_SEQ_NUM); + await this.saveAndSubmitWorkOrder(); + }, + async processCreditCardResponse() { + const subscriptionId = getQueryStringParameter(queryStrings.SUBSCRIPTIONID); + + const referralSeqNum = getQueryStringParameter(queryStrings.REFERRAL_SEQ_NUM); if (referralSeqNum !== useMainStore().order.referralSequenceNumber) { console.error(`error: unknown ref:${referralSeqNum} ${useMainStore().order.referralSequenceNumber}`); this.$router.navigate( @@ -85,19 +93,19 @@ export default { } ); } else { - const expMonth = getQuerystringParameter(queryStrings.CARD_EXPIRATION_MONTH); - const expYear = getQuerystringParameter(queryStrings.CARD_EXPIRATION_YEAR); - const cardType = getQuerystringParameter(queryStrings.CARD_TYPE); - const billToPostalCode = getQuerystringParameter(queryStrings.BILL_TO_POSTAL_CODE); - const billToFirstName = getQuerystringParameter(queryStrings.BILL_TO_FIRST_NAME); - const billToLastName = getQuerystringParameter(queryStrings.BILL_TO_LAST_NAME); - const referenceNumber = getQuerystringParameter(queryStrings.REFERENCE_NUMBER); - const authCode = getQuerystringParameter(queryStrings.AUTH_CODE); - const transactionId = getQuerystringParameter(queryStrings.TRANSACTION_ID); - const transReferenceNumber = getQuerystringParameter(queryStrings.TRANS_REFERENCE_NUMBER); - const lastFour = getQuerystringParameter(queryStrings.LAST_FOUR); + const expMonth = getQueryStringParameter(queryStrings.CARD_EXPIRATION_MONTH); + const expYear = getQueryStringParameter(queryStrings.CARD_EXPIRATION_YEAR); + const cardType = getQueryStringParameter(queryStrings.CARD_TYPE); + const billToPostalCode = getQueryStringParameter(queryStrings.BILL_TO_POSTAL_CODE); + const billToFirstName = getQueryStringParameter(queryStrings.BILL_TO_FIRST_NAME); + const billToLastName = getQueryStringParameter(queryStrings.BILL_TO_LAST_NAME); + const referenceNumber = getQueryStringParameter(queryStrings.REFERENCE_NUMBER); + const authCode = getQueryStringParameter(queryStrings.AUTH_CODE); + const transactionId = getQueryStringParameter(queryStrings.TRANSACTION_ID); + const transReferenceNumber = getQueryStringParameter(queryStrings.TRANS_REFERENCE_NUMBER); + const lastFour = getQueryStringParameter(queryStrings.LAST_FOUR); - const ccToken = { + const creditCardToken = { subscriptionId, expMonth, expYear, @@ -111,7 +119,7 @@ export default { transReferenceNumber, lastFour }; - useMainStore().updateCCToken(ccToken); + useMainStore().updateCreditCardToken(creditCardToken); await this.saveAndSubmitWorkOrder(); } }, @@ -119,9 +127,10 @@ export default { // Final work order submit after returning from pay in advance. useMainStore().resetSubmittedOrder(); try { - // do we have a function to submit a work order, - // perhaps built into saveSession? - // we need to submit the work order here + await submitWorkOrder({ + pageNameToLog: 'payment-return', + submitAfterSave: true + }); } catch (error) { console.error(`error: response from submit work order:${error.message}`); this.$router.navigate( @@ -131,9 +140,11 @@ export default { [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true } ); + showIssLoadingModal(false); return; } + showIssLoadingModal(false); useMainStore().createSubmittedOrder(); this.$router.navigate( this.navigationScenarios.PAY_IN_ADVANCE_SUCCESS, diff --git a/src/router/index.js b/src/router/index.js index 4cd2dc45..fda08794 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -2,7 +2,7 @@ import { createWebHistory, createRouter } from 'vue-router'; import lazyLoadComponent from '@/router/dynamic-routing/component-loader'; import issPageValues from '@/router/router-constants/issPage-values'; -import { routingTable } from '@/router/router-constants/routing-table'; +import routingTable from '@/router/router-constants/routing-table'; import { useMainStore } from '@/store'; import eventBus from '@/helpers/event-bus/event-bus'; import { globalEvents, globalEventTypes } from '@/constants/events'; @@ -16,11 +16,9 @@ import showIssLoadingModal from '@/helpers/loading-modal-helper'; import analyticsMixin from '@/mixins/analytics-mixin'; import { saveSession } from '@/helpers/order-helper.js'; import routerParams from '@/router/router-constants/router-params'; -import bailoutCode from '@/constants/bailoutCode'; -import IssPageValues from '@/router/router-constants/issPage-values'; +import canBailoutNavigateBack from '@/helpers/bailout-helper'; +import bailoutMessage from '@/constants/bailoutMessage'; import navigationScenarios from './router-constants/navigation-scenarios'; -import canBailoutNavigateBack from "@/helpers/bailout-helper"; -import bailoutMessage from "@/constants/bailoutMessage"; const routes = [ { @@ -129,7 +127,7 @@ router.beforeEach(async (to, from) => { showIssLoadingModal(true); } - const isInIframe = fromQueryPage === IssPageValues.PAYMENT_PAGE; + const isInIframe = fromQueryPage === issPageValues.PAYMENT_PAGE; if (isInIframe) { // need to set window.top.location.href directly when navigating out of an iframe // especially when navigating with browser buttons @@ -139,7 +137,7 @@ router.beforeEach(async (to, from) => { const store = useMainStore(); // Prevent navigating backwards if we enter a bailout that we are not allowed to go back on - if (store.isBailout && from.name === IssPageValues.BAILOUT_PAGE && to.name !== 'root' && to.name !== IssPageValues.CONTACT_CONFIRMATION + if (store.isBailout && from.name === issPageValues.BAILOUT_PAGE && to.name !== 'root' && to.name !== issPageValues.CONTACT_CONFIRMATION && !canBailoutNavigateBack()) { return false; } diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 60d76dcd..99582af8 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -655,7 +655,7 @@ const routingTable = () => [ { scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, destinationIssPageValue: issPageValues.CONFIRMATION - }, + } ] }, { @@ -763,4 +763,4 @@ const routingTable = () => [ ]; -export { routingTable }; +export default routingTable; diff --git a/src/store/index.js b/src/store/index.js index cc1b2986..6d8f8084 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -157,7 +157,8 @@ const getDefaultState = () => ({ parentAccountNumber: 0, isPayInAdvance: null, payInAdvanceType: null, - ccToken: { + paypalToken: null, + creditCardToken: { subscriptionId: null, expMonth: null, expYear: null, @@ -1202,7 +1203,7 @@ export const useMainStore = defineStore({ submitToMainframe: !!this.order.referralNumber, loadedFromDupeCheck }, - additionalSuccessEventDataHandler: (response) => + additionalSuccessEventDataHandler: () => `Email provided: ${customer.emailAddress ? 'true' : 'false'}` }).then((response) => { if (loadedFromDupeCheck) { @@ -1304,7 +1305,23 @@ export const useMainStore = defineStore({ throw ex; } }, - + updateCreditCardToken(token) { + this.order.payment.creditCardToken.subscriptionId = token.subscriptionId; + this.order.payment.creditCardToken.expMonth = token.expMonth; + this.order.payment.creditCardToken.expYear = token.expYear; + this.order.payment.creditCardToken.cardType = token.cardType; + this.order.payment.creditCardToken.billToPostalCode = token.billToPostalCode; + this.order.payment.creditCardToken.billToFirstName = token.billToFirstName; + this.order.payment.creditCardToken.billToLastName = token.billToLastName; + this.order.payment.creditCardToken.referenceNumber = token.referenceNumber; + this.order.payment.creditCardToken.authCode = token.authCode; + this.order.payment.creditCardToken.transactionId = token.transactionId; + this.order.payment.creditCardToken.transReferenceNumber = token.transReferenceNumber; + this.order.payment.creditCardToken.lastFour = token.lastFour; + }, + updatePaypalToken(token) { + this.order.payment.paypalToken = token; + }, setSaveSessionPromise(promise) { this.applicationUser.saveSessionPromise = promise; }, @@ -1399,7 +1416,7 @@ export const useMainStore = defineStore({ this.order.vehicle.registration.firstName = null; this.order.vehicle.registration.lastName = null; }, - resetServiceLocationAndDependencies(context) { + resetServiceLocationAndDependencies() { this.resetServiceLocationAppointmentType(); this.resetServiceLocationProvider(); this.resetSchedule(); @@ -2130,7 +2147,6 @@ export const useMainStore = defineStore({ this.resetInsurance(); this.resetBailout(); }, - savePaymentMethodChoice(paymentMethod) { const isPayInAdvance = paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE; this.order.payment.isPayInAdvance = isPayInAdvance; @@ -2144,21 +2160,6 @@ export const useMainStore = defineStore({ }); }, - updateCCToken(ccToken) { - this.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; - this.order.payment.ccToken.expMonth = ccToken.expMonth; - this.order.payment.ccToken.expYear = ccToken.expYear; - this.order.payment.ccToken.cardType = ccToken.cardType; - this.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; - this.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; - this.order.payment.ccToken.billToLastName = ccToken.billToLastName; - this.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; - this.order.payment.ccToken.authCode = ccToken.authCode; - this.order.payment.ccToken.transactionId = ccToken.transactionId; - this.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; - this.order.payment.ccToken.lastFour = ccToken.lastFour; - }, - hasSubmittedOrder() { return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; }, @@ -2183,7 +2184,7 @@ export const useMainStore = defineStore({ resetSubmittedOrder() { // clear from local storage window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); - }, + } }, persist: true From 76c35865e4fcf4141b78f6a050e1910983b44714 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Tue, 5 Mar 2024 10:41:47 -0500 Subject: [PATCH 25/36] Starting outline of tests --- .../coverage-statement.spec.js | 68 ++++--------------- 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index 79765a88..12f0b49a 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -118,59 +118,6 @@ describe.skip('coverageStatement.vue', () => { expect(arePagePrerequisitesValid).not.toBeTruthy(); }); }); - describe('Rendering', () => { - test('Should render site header', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const siteHeader = wrapper.findComponent({ ref: 'siteHeader' }); - - // Assert - expect(siteHeader.exists()).toBe(true); - }); - test('Should render site subheader', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const subheader = wrapper.find({ ref: 'siteSubHeader' }); - - // Assert - expect(subheader.exists()).toBe(true); - }); - - test('Should render explanatory text', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const explanatoryText = wrapper.find({ ref: 'explanatoryText' }); - - // Assert - expect(explanatoryText.exists()).toBe(true); - }); - test('Should render secondary text', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const secondaryText = wrapper.find({ ref: 'secondaryText' }); - - // Assert - expect(secondaryText.exists()).toBe(true); - }); - test('Should render site footer', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const footer = wrapper.findComponent({ ref: 'siteFooter' }); - - // Assert - expect(footer.exists()).toBe(true); - }); - }); describe('Verified ITAC scenario', () => { test('If policy lookup successful, not No Comp, and deductible > service price, verifiedITAC returns true', () => { // Arrange @@ -881,6 +828,21 @@ describe('coverageStatement.vue-working', () => { // Assert expect(footer.exists()).toBe(true); }); + }); + describe('Computed', () => { + describe('formattedDeductible', () => {}); + describe('verifiedNoComp', () => {}); + describe('verifiedITAC', () => {}); + describe('verifiedDeductible', () => {}); + describe('unverified', () => {}); + describe('isADAS', () => {}); + describe('servicePriceForDisplay', () => {}); + describe('itacCostSavings', () => {}); + describe('itacCostSavingsForDisplay', () => {}); + describe('isQuoteDisplayed', () => {}); + }); + describe('watchers', () => { + }); describe('ITAC flag', () => { test('ITAC flag updated once component is initialized', async () => { From 9fd65de29ef1c5f3d421becc8d784127b91798fd Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 5 Mar 2024 10:43:50 -0500 Subject: [PATCH 26/36] but missing function back --- src/store/index.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 6d8f8084..2efd6470 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -949,7 +949,17 @@ export const useMainStore = defineStore({ }).then((response) => resolve(response), (error) => reject(error)); }); }, - + getCarrierAccountInfo() { + return new Promise((resolve, reject) => { + globalMethods.callHttpClient({ + method: endpoints.GetAccountInfo.method, + endpoint: endpoints.GetAccountInfo.url + this.issConfig.parentAccountNumber + }).then((response) => { + this.order.carrierPhoneNumber = response.data.phoneNumber; + return resolve(response.data); + }).catch((error) => reject(error)); + }); + }, async getSupportingItems() { const { glassParts } = this.lineItems; const { carId } = this.vehicle; From cf850358ae8b2591a37f5d4bb6bd053094482ff2 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Tue, 5 Mar 2024 10:44:35 -0500 Subject: [PATCH 27/36] Reverting problematic change --- src/store/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 3ba028ec..5017c884 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -950,7 +950,6 @@ export const useMainStore = defineStore({ const { glassParts } = this.lineItems; const { carId } = this.vehicle; const { isRepair, numberOfChips } = this.damage; - const { parentAccountNumber } = this.issConfig; return globalMethods .callHttpClient({ @@ -959,7 +958,7 @@ export const useMainStore = defineStore({ payload: { carId, damageType: isRepair ? 'Repair' : 'Replace', - parentAccountNumber, + parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, parts: glassParts ?? [], numberOfRepairChips: isRepair ? numberOfChips : 0 } From 844d1b0215ab3cc5a7f13f2e8cddde0f32d095e3 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 5 Mar 2024 11:22:00 -0500 Subject: [PATCH 28/36] unit tests --- .../order-confirmation.spec.js | 110 +++++++++++++++++- .../order-confirmation/order-confirmation.vue | 2 +- 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index 590b5c1b..1984ef04 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -12,10 +12,18 @@ import { createTestingPinia } from '@pinia/testing'; jest.mock('@/helpers/layout-helper.js', () => jest.fn()); jest.mock('@/helpers/cms-content-helper', () => ({ - fetchCmsContentForPage: jest.fn() + fetchCmsContentForPage: jest.fn(), + processIfStatements: jest.fn() })); const wordingText = 'wording Text {custom:address}'; +const inShopDuration = '60-90 minutes'; +jest.mock('@/helpers/date-helper', () => ({ + getDisplayTextForDurationLength: jest.fn().mockImplementation(() => inShopDuration), + convertDateStringToDate: jest.fn(), + get12HourTimeFormat: jest.fn() +})); + const mockMixin = { methods: { getCmsContent: jest.fn().mockImplementation(() => wordingText), @@ -34,12 +42,18 @@ const headerStub = { render: () => {} }; +const vehicleBannerStub = { + render: () => {} +}; + const initialStore = { order: { schedule: { date: '2024-03-01', startTime: '09:00', - endTime: '10:00' + endTime: '10:00', + jobMinMinutes: 60, + jobMaxMinutes: 90 }, serviceLocation: { address: '123 Test Way', @@ -70,7 +84,8 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu mountOptions.global.stubs = { siteFooter: footerStub, - siteHeader: headerStub + siteHeader: headerStub, + vehicleBanner: vehicleBannerStub }; const testingPinia = createTestingPinia({ @@ -110,6 +125,16 @@ describe('OrderConfirmation.vue', () => { // Assert expect(siteHeader.exists()).toBe(true); }); + test('Should render Vehicle Banner', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const vehicleBanner = wrapper.findComponent(vehicleBannerStub); + + // Assert + expect(vehicleBanner.exists()).toBe(true); + }); test('If Advanced flow, should display Site Footer', () => { // Arrange const testStore = { @@ -324,5 +349,84 @@ describe('OrderConfirmation.vue', () => { // Assert expect(testValue).toEqual('
123 Safelite Street,
Mesa, AZ 12345
'); }); + test('appointmentWordingText2 should return Mobile text in expected format', () => { + // Arrange + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + address: '123 Test Way', + address2: '#1', + city: 'Mesa', + state: 'AZ', + zipCode: '12345', + appointmentType: 'Mobile' + } + } + }; + const { wrapper } = getMountedComponent(testStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText2; + + // Assert + expect(testValue).toEqual(wordingText); + }); + test('appointmentWordingText2 should return Drop Off and text in expected format', () => { + // Arrange + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + provider: { + address: { + streetAddress: '123 Safelite Street', + city: 'Mesa', + state: 'AZ', + zipCode: '12345' + } + }, + appointmentType: 'Drop Off' + } + } + }; + const { wrapper } = getMountedComponent(testStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText2; + const expected = wrapper.vm.getBodyText2FromCms('Test Widget'); + + // Assert + expect(testValue).toEqual(expected); + }); + test('appointmentWordingText2 should return In Shop text in expected format', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText2; + const expected = wrapper.vm.getBodyText2FromCms('Test Widget'); + + // Assert + expect(testValue).toEqual(expected); + }); + test('inShopAppointmentDuration should return appointment length', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.inShopAppointmentDuration; + + // Assert + expect(testValue).toEqual(inShopDuration); + }); }); }); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 4b299b07..25911e24 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -120,7 +120,7 @@ export default { // This conversion ensures we don't get get GMT induced date changes const dateObject = convertDateStringToDate(this.appointmentDate); // Ex: Tuesday, April 22 - return dateObject.toLocaleDateString('en-us', { + return dateObject?.toLocaleDateString('en-us', { weekday: 'long', month: 'long', day: 'numeric' From b8712cbf5ef15051c9ffbf48baefef5b996a87ca Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Tue, 5 Mar 2024 11:24:47 -0500 Subject: [PATCH 29/36] SSR-1081 break up processCreditCardResponse --- src/layouts/payment-return/payment-return.vue | 73 ++++++++----------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/src/layouts/payment-return/payment-return.vue b/src/layouts/payment-return/payment-return.vue index 329badf9..8e5d3de6 100644 --- a/src/layouts/payment-return/payment-return.vue +++ b/src/layouts/payment-return/payment-return.vue @@ -23,6 +23,24 @@ export default { Form }, mixins: [BaseFormMixin], + computed: { + creditCardToken() { + return { + subscriptionId: getQueryStringParameter(queryStrings.SUBSCRIPTIONID), + expMonth: getQueryStringParameter(queryStrings.CARD_EXPIRATION_MONTH), + expYear: getQueryStringParameter(queryStrings.CARD_EXPIRATION_YEAR), + cardType: getQueryStringParameter(queryStrings.CARD_TYPE), + billToPostalCode: getQueryStringParameter(queryStrings.BILL_TO_POSTAL_CODE), + billToFirstName: getQueryStringParameter(queryStrings.BILL_TO_FIRST_NAME), + billToLastName: getQueryStringParameter(queryStrings.BILL_TO_LAST_NAME), + referenceNumber: getQueryStringParameter(queryStrings.REFERENCE_NUMBER), + authCode: getQueryStringParameter(queryStrings.AUTH_CODE), + transactionId: getQueryStringParameter(queryStrings.TRANSACTION_ID), + transReferenceNumber: getQueryStringParameter(queryStrings.TRANS_REFERENCE_NUMBER), + lastFour: getQueryStringParameter(queryStrings.LAST_FOUR) + }; + } + }, async mounted() { showIssLoadingModal(true); const payInAdvanceError = getQueryStringParameter(queryStrings.ERROR); @@ -73,6 +91,15 @@ export default { arePagePrerequisitesValid() { return true; }, + navigateOnPayInAdvanceError() { + this.$router.navigate( + this.navigationScenarios.PAY_IN_ADVANCE_ERROR, + this.$route, + { + [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true + } + ); + }, async processPaypalResponse() { const token = getQueryStringParameter(queryStrings.TOKEN); this.mainStore.updatePaypalToken(token); @@ -80,46 +107,12 @@ export default { await this.saveAndSubmitWorkOrder(); }, async processCreditCardResponse() { - const subscriptionId = getQueryStringParameter(queryStrings.SUBSCRIPTIONID); - const referralSeqNum = getQueryStringParameter(queryStrings.REFERRAL_SEQ_NUM); if (referralSeqNum !== useMainStore().order.referralSequenceNumber) { console.error(`error: unknown ref:${referralSeqNum} ${useMainStore().order.referralSequenceNumber}`); - this.$router.navigate( - this.navigationScenarios.PAY_IN_ADVANCE_ERROR, - this.$route, - { - [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true - } - ); + this.navigateOnPayInAdvanceError(); } else { - const expMonth = getQueryStringParameter(queryStrings.CARD_EXPIRATION_MONTH); - const expYear = getQueryStringParameter(queryStrings.CARD_EXPIRATION_YEAR); - const cardType = getQueryStringParameter(queryStrings.CARD_TYPE); - const billToPostalCode = getQueryStringParameter(queryStrings.BILL_TO_POSTAL_CODE); - const billToFirstName = getQueryStringParameter(queryStrings.BILL_TO_FIRST_NAME); - const billToLastName = getQueryStringParameter(queryStrings.BILL_TO_LAST_NAME); - const referenceNumber = getQueryStringParameter(queryStrings.REFERENCE_NUMBER); - const authCode = getQueryStringParameter(queryStrings.AUTH_CODE); - const transactionId = getQueryStringParameter(queryStrings.TRANSACTION_ID); - const transReferenceNumber = getQueryStringParameter(queryStrings.TRANS_REFERENCE_NUMBER); - const lastFour = getQueryStringParameter(queryStrings.LAST_FOUR); - - const creditCardToken = { - subscriptionId, - expMonth, - expYear, - cardType, - billToPostalCode, - billToFirstName, - billToLastName, - referenceNumber, - authCode, - transactionId, - transReferenceNumber, - lastFour - }; - useMainStore().updateCreditCardToken(creditCardToken); + useMainStore().updateCreditCardToken(this.creditCardToken); await this.saveAndSubmitWorkOrder(); } }, @@ -133,13 +126,7 @@ export default { }); } catch (error) { console.error(`error: response from submit work order:${error.message}`); - this.$router.navigate( - this.navigationScenarios.PAY_IN_ADVANCE_ERROR, - this.$route, - { - [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true - } - ); + this.navigateOnPayInAdvanceError(); showIssLoadingModal(false); return; } From 2f5883be5a5f6c291834f8ac99b3049025a7b8b7 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 5 Mar 2024 11:34:08 -0500 Subject: [PATCH 30/36] fix a merge issue --- src/store/index.js | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 0bbf894c..b0d7fb10 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -20,7 +20,6 @@ import { noCoverageForSelectedVehicle, repairWaivedForSelectedVehicle } from '@/helpers/policy-vehicle-helper'; -import webStorageConstants from '@/constants/web-storage-constants'; const storeId = 'main'; @@ -2196,48 +2195,6 @@ export const useMainStore = defineStore({ // clear from local storage window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); } - - updateCCToken(ccToken) { - this.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; - this.order.payment.ccToken.expMonth = ccToken.expMonth; - this.order.payment.ccToken.expYear = ccToken.expYear; - this.order.payment.ccToken.cardType = ccToken.cardType; - this.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; - this.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; - this.order.payment.ccToken.billToLastName = ccToken.billToLastName; - this.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; - this.order.payment.ccToken.authCode = ccToken.authCode; - this.order.payment.ccToken.transactionId = ccToken.transactionId; - this.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; - this.order.payment.ccToken.lastFour = ccToken.lastFour; - }, - - hasSubmittedOrder() { - return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; - }, - - createSubmittedOrder() { - if (this.hasSubmittedOrder()) { - return; - } - const submittedOrder = this.order; - const { experiments } = this.applicationUser; - - // set to local storage - window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); - - // clear vuex - this.resetState(); - - // restore user's experiments - this.applicationUser.experiments = experiments; - }, - - resetSubmittedOrder() { - // clear from local storage - window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); - }, - }, persist: true }); From ddb49a8e7ce2fb85d06ed74dd7669b9119d68b91 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 5 Mar 2024 13:26:12 -0500 Subject: [PATCH 31/36] final fixes --- .../order-confirmation.spec.js | 17 ----------------- .../order-confirmation/order-confirmation.vue | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index 1984ef04..d53eacbd 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -17,13 +17,6 @@ jest.mock('@/helpers/cms-content-helper', () => ({ })); const wordingText = 'wording Text {custom:address}'; -const inShopDuration = '60-90 minutes'; -jest.mock('@/helpers/date-helper', () => ({ - getDisplayTextForDurationLength: jest.fn().mockImplementation(() => inShopDuration), - convertDateStringToDate: jest.fn(), - get12HourTimeFormat: jest.fn() -})); - const mockMixin = { methods: { getCmsContent: jest.fn().mockImplementation(() => wordingText), @@ -418,15 +411,5 @@ describe('OrderConfirmation.vue', () => { // Assert expect(testValue).toEqual(expected); }); - test('inShopAppointmentDuration should return appointment length', () => { - // Arrange - const { wrapper } = getMountedComponent(initialStore); - - // Act - const testValue = wrapper.vm.inShopAppointmentDuration; - - // Assert - expect(testValue).toEqual(inShopDuration); - }); }); }); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 25911e24..4b299b07 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -120,7 +120,7 @@ export default { // This conversion ensures we don't get get GMT induced date changes const dateObject = convertDateStringToDate(this.appointmentDate); // Ex: Tuesday, April 22 - return dateObject?.toLocaleDateString('en-us', { + return dateObject.toLocaleDateString('en-us', { weekday: 'long', month: 'long', day: 'numeric' From a1b66955220c44c7bc272d858cc644d8db4ab272 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 5 Mar 2024 14:05:00 -0500 Subject: [PATCH 32/36] PR feedback refactoring, unit test fixes --- .../order-confirmation.spec.js | 6 ++--- .../order-confirmation/order-confirmation.vue | 27 ++++++++++--------- src/store/index.js | 1 + 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index d53eacbd..5883b9d1 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -233,7 +233,7 @@ describe('OrderConfirmation.vue', () => { endTime: '10:00' }, serviceLocation: { - appointmentType: 'Drop Off' + appointmentType: 'Dropoff' } } }; @@ -300,7 +300,7 @@ describe('OrderConfirmation.vue', () => { zipCode: '12345' } }, - appointmentType: 'Drop Off' + appointmentType: 'Dropoff' } } }; @@ -387,7 +387,7 @@ describe('OrderConfirmation.vue', () => { zipCode: '12345' } }, - appointmentType: 'Drop Off' + appointmentType: 'Dropoff' } } }; diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 4b299b07..d6c7b2d2 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -61,6 +61,7 @@ import { useMainStore } from '@/store'; import { get12HourTimeFormat, get12HourTimeMobileFormat, convertDateStringToDate, getDisplayTextForDurationLength } from '@/helpers/date-helper.js'; import { toTitleCase } from '@/helpers/text-helper.js'; +import { AppointmentTypeStrings } from '@/constants/schedule-constants'; export default { name: 'order-confirmation', @@ -105,7 +106,7 @@ export default { return this.getCmsContent('OrderConfirmationContent', 'Image'); }, appointmentType() { - return this.mainStore.order.serviceLocation.appointmentType.toUpperCase(); + return this.mainStore.order.serviceLocation.appointmentType; }, appointmentDate() { return this.mainStore.order.schedule.date; @@ -179,17 +180,17 @@ export default { }, appointmentWordingText() { switch (this.appointmentType) { - case 'MOBILE': + case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: return this.mobileWordingText?.replaceAll( '{custom:address}', this.serviceLocationFullAddress ); - case 'DROP OFF': + case AppointmentTypeStrings.DROP_OFF: return this.dropOffAndInShopWordingText?.replaceAll( '{custom:address}', this.providerFullAddress ); - case 'INSHOP': + case AppointmentTypeStrings.IN_SHOP: return this.dropOffAndInShopWordingText?.replaceAll( '{custom:address}', this.providerFullAddress @@ -200,11 +201,11 @@ export default { }, appointmentWordingText2() { switch (this.appointmentType) { - case 'MOBILE': + case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: return this.mobileWordingText2; - case 'DROP OFF': + case AppointmentTypeStrings.DROP_OFF: return this.dropOffAndInShopWordingText2; - case 'INSHOP': + case AppointmentTypeStrings.IN_SHOP: return this.dropOffAndInShopWordingText2?.replaceAll( '{custom:inShopDuration}', this.inShopAppointmentDuration @@ -214,13 +215,13 @@ export default { } }, mobileAppointment() { - return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'MOBILE'; + return useMainStore().getters.isMobileAppointment; }, inShopAppointment() { - return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'INSHOP'; + return useMainStore().getters.isInShopAppointment; }, dropOffAppointment() { - return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'DROP OFF'; + return useMainStore().getters.isDropOffAppointment; }, inShopAppointmentDuration() { const inshopDurationTime = getDisplayTextForDurationLength( @@ -241,12 +242,12 @@ export default { }, formatAppointmentTime(appointmentType) { switch (appointmentType) { - case 'MOBILE': + case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: // eslint-disable-next-line max-len return `Between ${get12HourTimeMobileFormat(this.appointmentStartTime)} - ${get12HourTimeMobileFormat(this.appointmentEndTime)}`; - case 'DROP OFF': + case AppointmentTypeStrings.DROP_OFF: return 'Drop off before 9:30 AM'; - case 'INSHOP': + case AppointmentTypeStrings.IN_SHOP: return `at ${get12HourTimeFormat(this.appointmentStartTime)}`; default: return null; diff --git a/src/store/index.js b/src/store/index.js index 5017c884..e34a7fcd 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -237,6 +237,7 @@ export const useMainStore = defineStore({ isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE || state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP, isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF, + isInShopAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.IN_SHOP, isClaimRegistrationRequired: (state) => state.issConfig.isClaimRegistrationRequired, isClaimAlreadyRegistered: (state) => state.order.payment.insuranceCoverage.claimNumber !== null, isBailout: (state) => state.applicationUser.pageData[issPageValues.BAILOUT_PAGE] != null, From 018e27679afb67706f3cf004621667b526b1a1a6 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 5 Mar 2024 14:22:12 -0500 Subject: [PATCH 33/36] logic/prereq updates --- .../order-confirmation/order-confirmation.vue | 15 +++++++++------ src/layouts/payment-method/payment-method.vue | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index d6c7b2d2..f1bddf9e 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -180,7 +180,8 @@ export default { }, appointmentWordingText() { switch (this.appointmentType) { - case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: + case AppointmentTypeStrings.MOBILE: + case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: return this.mobileWordingText?.replaceAll( '{custom:address}', this.serviceLocationFullAddress @@ -201,7 +202,8 @@ export default { }, appointmentWordingText2() { switch (this.appointmentType) { - case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: + case AppointmentTypeStrings.MOBILE: + case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: return this.mobileWordingText2; case AppointmentTypeStrings.DROP_OFF: return this.dropOffAndInShopWordingText2; @@ -215,13 +217,13 @@ export default { } }, mobileAppointment() { - return useMainStore().getters.isMobileAppointment; + return this.mainStore.isMobileAppointment; }, inShopAppointment() { - return useMainStore().getters.isInShopAppointment; + return this.mainStore.isInShopAppointment; }, dropOffAppointment() { - return useMainStore().getters.isDropOffAppointment; + return this.mainStore.isDropOffAppointment; }, inShopAppointmentDuration() { const inshopDurationTime = getDisplayTextForDurationLength( @@ -242,7 +244,8 @@ export default { }, formatAppointmentTime(appointmentType) { switch (appointmentType) { - case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: + case AppointmentTypeStrings.MOBILE: + case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: // eslint-disable-next-line max-len return `Between ${get12HourTimeMobileFormat(this.appointmentStartTime)} - ${get12HourTimeMobileFormat(this.appointmentEndTime)}`; case AppointmentTypeStrings.DROP_OFF: diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 8b03a875..ab362f4c 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -178,7 +178,8 @@ export default { && providerLocation.zipCode ); - const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE; + const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE + || serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; const serviceLocationReqs = (isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs); From 7757bc6cfd78f02a0aee58623c4726de50f72f17 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Wed, 6 Mar 2024 10:15:08 -0500 Subject: [PATCH 34/36] Adding test cases --- .../coverage-statement.spec.js | 57 +++++++++++++-- .../coverage-statement/coverage-statement.vue | 70 ++++++++----------- 2 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index 12f0b49a..186c1799 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -830,19 +830,62 @@ describe('coverageStatement.vue-working', () => { }); }); describe('Computed', () => { - describe('formattedDeductible', () => {}); - describe('verifiedNoComp', () => {}); - describe('verifiedITAC', () => {}); - describe('verifiedDeductible', () => {}); + describe.only('verifiedNoComp', () => { + test.each([true, false])('returns false when policyLookupSuccessful false', (isNoComp) => { + + }); + test.each([true, false])('returns false when isNoComp false', (policyLookupSuccessful) => {}); + test('returns true when policyLookupSuccessful true and policyLookupSuccessful true', () => { + + }); + }); + describe('verifiedITAC', () => { + test('returns false when policyLookupSuccessful false', () => {}); + test('returns false when isNoComp true', () => {}); + test('returns false when deductibleValue equals totalServicePrice', () => {}); + test('returns false when deductibleValue less than totalServicePrice', () => {}); + }); + describe('verifiedDeductible', () => { + test('', () => { }); + test('', () => { }); + test('', () => { }); + test('', () => { }); + test('', () => { }); + test('', () => { }); + test('', () => { }); + }); describe('unverified', () => {}); describe('isADAS', () => {}); - describe('servicePriceForDisplay', () => {}); describe('itacCostSavings', () => {}); - describe('itacCostSavingsForDisplay', () => {}); describe('isQuoteDisplayed', () => {}); + describe('shouldRegisterClaim', () => {}); }); - describe('watchers', () => { + describe('methods', () => { + describe('arePagePrerequisitesValid', () => { + }); + test.each([ + [0, '$0.00'], + [1, '$1.00'], + [12, '$12.00'], + [1.2, '$1.20'], + [1.25, '$1.25'], + [1.254, '$1.25'], + [1.255, '$1.26'], + [-1, '-$1.00'] + ])('getFormattedAmount', (value, expected) => { + // Arrange + const { wrapper } = getMountedComponent(); + + // Act + const result = wrapper.vm.getFormattedAmount(value); + + // Assert + expect(result).toBe(expected); + }); + describe('navigateForward', () => { + + }); }); describe('ITAC flag', () => { test('ITAC flag updated once component is initialized', async () => { diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 8776ebe1..ad578df1 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -35,7 +35,7 @@
- {{ formattedDeductible }} + {{ deductibleForDisplay }}
{{ deductibleText }}  - {{ formattedDeductible }} + {{ deductibleForDisplay }}
{ - useMainStore() - .setBailout( - to, - bailoutMessage.pricingResponseError( - availableLineItems.map((li) => li.partNumber), - { code: err.code, message: err.message, data: err.data } - ) - ); + setBailout(to, bailoutMessage.pricingResponseError( + availableLineItems.map((li) => li.partNumber), + { code: err.code, message: err.message, data: err.data } + )); hasBailedOut = true; next(`/?issPage=${issPageValues.BAILOUT_PAGE}`); }); @@ -292,7 +292,7 @@ export default { deductibleValue() { return useMainStore().order.currentDeductible; }, - formattedDeductible() { + deductibleForDisplay() { return this.getFormattedAmount(this.deductibleValue); }, registerClaimSuccessful() { @@ -347,6 +347,13 @@ export default { }, isQuoteDisplayed() { return this.verifiedITAC || this.verifiedNoComp; + }, + shouldRegisterClaim() { + return this.policyLookupSuccessful + && useMainStore().vehicle.policyVehicleId >= 0 + && useMainStore().isClaimRegistrationRequired + && !useMainStore().isClaimAlreadyRegistered + && (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC); } }, watch: { @@ -373,11 +380,7 @@ export default { }, async initializeComponent() { useMainStore().updatePolicyITACFlag(this.verifiedITAC); - if (this.policyLookupSuccessful - && useMainStore().vehicle.policyVehicleId >= 0 - && useMainStore().isClaimRegistrationRequired - && !useMainStore().isClaimAlreadyRegistered - && (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC)) { + if (this.shouldRegisterClaim) { await useMainStore().registerClaim()?.catch(() => {}); } this.$refs.loadingModal.hideModal(); @@ -385,38 +388,27 @@ export default { async navigateForward() { if (this.unverified || this.verifiedDeductible) { useMainStore().updateSupportingItems(this.supportingItems); - this.$router.navigate( - navigationScenarios.CLICKED_FORWARD, - this.$route, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); + this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD); } else if (this.verifiedITAC || this.verifiedNoComp) { useMainStore().updateIsSafeliteProvider(this.selectedProvider === SAFELITE_PROVIDER); if (this.selectedProvider === SAFELITE_PROVIDER) { useMainStore().updateSupportingItems(this.supportingItems); - this.$router.navigate( - navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, - this.$route - ); + this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE); } else { - useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); - this.$router.navigate( - navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, - this.$route - ); + this.setBailoutWithMessage(bailoutMessage.RequestCallback()); + this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP); } } else { - useMainStore().setBailout( - this.$router.currentRoute, - bailoutMessage.coverageStatementInvalidState() - ); - this.$router.navigate( - navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE, - this.$route - ); + this.setBailoutWithMessage(bailoutMessage.coverageStatementInvalidState()); + this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE); } }, + setBailoutWithMessage(message) { + setBailout(this.$router.currentRoute, message); + }, + navigateWithScenario(scenario) { + this.$router.navigate(scenario, this.$route); + }, getTextFromCmsWithCustomIfStatements(widgetName, widgetField) { const rawText = this.getCmsContent(widgetName, widgetField); return processIfStatements(rawText, 'custom', this.getCustomValueFromString); From 320093cf2df3620b7a0f6dc4845a385878eacc2b Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 7 Mar 2024 14:13:13 -0500 Subject: [PATCH 35/36] Finishing coverage statement tests --- .../coverage-statement.spec.js.snap | 29 + .../coverage-statement.spec.js | 759 +++++++++++++++++- .../coverage-statement/coverage-statement.vue | 9 +- 3 files changed, 767 insertions(+), 30 deletions(-) create mode 100644 src/layouts/coverage-statement/__snapshots__/coverage-statement.spec.js.snap diff --git a/src/layouts/coverage-statement/__snapshots__/coverage-statement.spec.js.snap b/src/layouts/coverage-statement/__snapshots__/coverage-statement.spec.js.snap new file mode 100644 index 00000000..aca040ba --- /dev/null +++ b/src/layouts/coverage-statement/__snapshots__/coverage-statement.spec.js.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`coverageStatement.vue-working returns the initial data 1`] = ` +Object { + "baseServiceLineItems": Array [], + "currencyFormatter": NumberFormat {}, + "deductibleText": "Your deductible is", + "isNoComp": false, + "isRepair": true, + "loadingText": Array [ + "Connecting to your insurance company", + "Nearly there", + "Finishing up", + ], + "policyLookupSuccessful": true, + "rules": Object { + "selectionRequired": "option-required", + }, + "selectedProvider": "", + "supportingItems": null, + "widget": Object { + "explanatoryText": "ExplanatoryTextWidget", + "nextStep": "NextStepsWidget", + "serviceProviderQuestion": "ServiceProviderQuestion", + "subheader": "SiteSubHeaderWidget", + "verifiedItacAlert": "VerifiedITACAlert", + }, +} +`; diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index 186c1799..8fa66c0c 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -3,7 +3,7 @@ import coverageStatement from '@/layouts/coverage-statement/coverage-statement.v // Supporting Files import { nextTick } from 'vue'; -import { mount } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { createTestingPinia } from '@pinia/testing'; import navigationScenarios from '@/router/router-constants/navigation-scenarios.js'; @@ -12,8 +12,10 @@ import settleAllPromises from '@/helpers/layout-helper.js'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import routerParams from '@/router/router-constants/router-params'; import { useMainStore } from '@/store/index.js'; +import getPriceOfLineItems from '@/helpers/price-calculator.js'; jest.mock('@/helpers/layout-helper.js', () => jest.fn()); +jest.mock('@/helpers/price-calculator.js', () => jest.fn()); jest.mock('@/helpers/cms-content-helper', () => ({ fetchCmsContentForPage: jest.fn(), @@ -24,7 +26,10 @@ jest.mock('@/helpers/cms-content-helper', () => ({ const mockMixin = { methods: { getCmsContent: jest.fn().mockImplementation(() => ''), - setCmsContent: jest.fn() + setCmsContent: jest.fn(), + onSubmit: jest.fn(), + onInvalidSubmit: jest.fn(), + navigateBackByVehicleQuestions: jest.fn() } }; @@ -51,6 +56,7 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu }); mountOptions.global.stubs = { + ...mountOptions.global.stubs, siteFooter: footerStub, siteHeader: true, recalModal: true, @@ -79,7 +85,7 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const wrapper = mount(coverageStatement, mountOptions); + const wrapper = shallowMount(coverageStatement, mountOptions); return { wrapper }; } @@ -775,7 +781,24 @@ describe.skip('coverageStatement.vue', () => { }); describe('coverageStatement.vue-working', () => { - // test('initial data is as expected', () => {}); + test('returns the initial data', () => { + // Arrange + const mainInitialState = { + order: { + damage: { + isRepair: true + }, + policy: { + policyLookupSuccessful: true, + noCoverage: false + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Assert + expect(wrapper.vm.$data).toMatchSnapshot(); + }); describe('Rendering', () => { test('Should render site header', () => { // Arrange @@ -830,39 +853,724 @@ describe('coverageStatement.vue-working', () => { }); }); describe('Computed', () => { - describe.only('verifiedNoComp', () => { + describe('verifiedNoComp', () => { test.each([true, false])('returns false when policyLookupSuccessful false', (isNoComp) => { + // Arrange + const mainInitialState = { + order: { + policy: { + noCoverage: isNoComp, + policyLookupSuccessful: false + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + // Act + const result = wrapper.vm.verifiedNoComp; + + // Assert + expect(result).toBeFalsy(); }); - test.each([true, false])('returns false when isNoComp false', (policyLookupSuccessful) => {}); - test('returns true when policyLookupSuccessful true and policyLookupSuccessful true', () => { + test.each([true, false])('returns false when isNoComp false', (policyLookupSuccessful) => { + // Arrange + const mainInitialState = { + order: { + policy: { + noCoverage: false, + policyLookupSuccessful + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + // Act + const result = wrapper.vm.verifiedNoComp; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns true when policyLookupSuccessful true and policyLookupSuccessful true', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + noCoverage: true, + policyLookupSuccessful: true + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedNoComp; + + // Assert + expect(result).toBeTruthy(); }); }); describe('verifiedITAC', () => { - test('returns false when policyLookupSuccessful false', () => {}); - test('returns false when isNoComp true', () => {}); - test('returns false when deductibleValue equals totalServicePrice', () => {}); - test('returns false when deductibleValue less than totalServicePrice', () => {}); + const priceOfLineItems = 213; + test.each([true, false])('returns false when policyLookupSuccessful false', (isNoComp) => { + // Arrange + const mainInitialState = { + order: { + policy: { + noCoverage: isNoComp, + policyLookupSuccessful: false + }, + currentDeductible: priceOfLineItems + 1 + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedITAC; + + // Assert + expect(result).toBeFalsy(); + }); + test.each([true, false])('returns false when isNoComp true', (policyLookupSuccessful) => { + // Arrange + const mainInitialState = { + order: { + policy: { + noCoverage: true, + policyLookupSuccessful + }, + currentDeductible: priceOfLineItems + 1 + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedITAC; + + // Assert + expect(result).toBeFalsy(); + }); + test.each([ + [true, false], + [true, true], + [false, false], + [false, true] + ])('returns false when deductibleValue equals totalServicePrice', (noCoverage, policyLookupSuccessful) => { + // Arrange + const mainInitialState = { + order: { + policy: { + noCoverage, + policyLookupSuccessful + }, + currentDeductible: priceOfLineItems + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedITAC; + + // Assert + expect(result).toBeFalsy(); + }); + test.each([ + [true, false], + [true, true], + [false, false], + [false, true] + ])( + 'returns false when deductibleValue less than totalServicePrice when noCoverage is %p and policyLookupSuccessful is %p', + (noCoverage, policyLookupSuccessful) => { + // Arrange + const mainInitialState = { + order: { + policy: { + noCoverage, + policyLookupSuccessful + }, + currentDeductible: priceOfLineItems - 1 + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedITAC; + + // Assert + expect(result).toBeFalsy(); + } + ); + test('returns true when deductibleValue more than totalServicePrice, noComp is false, and policyLookupSuccessful true', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + noCoverage: false, + policyLookupSuccessful: true + }, + currentDeductible: priceOfLineItems + 1 + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedITAC; + + // Assert + expect(result).toBeTruthy(); + }); }); describe('verifiedDeductible', () => { - test('', () => { }); - test('', () => { }); - test('', () => { }); - test('', () => { }); - test('', () => { }); - test('', () => { }); - test('', () => { }); + const servicePrice = 123; + describe('claim registration required', () => { + const issConfig = { isClaimRegistrationRequired: true }; + let verifiedDeductibleStoreState; + beforeEach(() => { + verifiedDeductibleStoreState = { + issConfig, + order: { + payment: { + insuranceCoverage: { + isVerified: true + } + }, + policy: { + noCoverage: false, + policyLookupSuccessful: false + }, + currentDeductible: servicePrice - 1 + } + }; + getPriceOfLineItems.mockImplementation(() => servicePrice); + }); + test('returns false when deductible is null', () => { + // Arrange + const mainInitialState = verifiedDeductibleStoreState; + mainInitialState.order.currentDeductible = null; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedDeductible; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when register claim not successful', () => { + // Arrange + const mainInitialState = verifiedDeductibleStoreState; + mainInitialState.order.payment.insuranceCoverage.isVerified = false; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedDeductible; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns true when register claim successful, isNoComp false, and service price over deductible', () => { + // Arrange + const { wrapper } = getMountedComponent(verifiedDeductibleStoreState); + + // Act + const result = wrapper.vm.verifiedDeductible; + + // Assert + expect(result).toBeTruthy(); + }); + }); + describe('claim registration not required', () => { + const issConfig = { isClaimRegistrationRequired: false }; + let verifiedDeductibleStoreState; + beforeEach(() => { + verifiedDeductibleStoreState = { + issConfig, + order: { + payment: { + insuranceCoverage: { + isVerified: false + } + }, + policy: { + noCoverage: false, + policyLookupSuccessful: true + }, + currentDeductible: servicePrice - 1 + } + }; + }); + test('returns false when policy lookup not successful', () => { + // Arrange + const mainInitialState = verifiedDeductibleStoreState; + mainInitialState.order.policy.policyLookupSuccessful = false; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.verifiedDeductible; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns true when policyLookupSuccessful, isNoComp false, and deductible over service price', () => { + // Arrange + const { wrapper } = getMountedComponent(verifiedDeductibleStoreState); + + // Act + const result = wrapper.vm.verifiedDeductible; + + // Assert + expect(result).toBeTruthy(); + }); + }); + test('returns false when isNoComp true', () => { + // Arrange + const isNoComp = true; + const storeState = { + issConfig: { + isClaimRegistrationRequired: false + }, + order: { + payment: { + insuranceCoverage: { + isVerified: true + } + }, + policy: { + noCoverage: isNoComp, + policyLookupSuccessful: true + }, + currentDeductible: servicePrice - 1 + } + }; + const { wrapper } = getMountedComponent(storeState); + + // Act + const result = wrapper.vm.verifiedDeductible; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when service price below deductible', () => { + // Arrange + const storeState = { + issConfig: { + isClaimRegistrationRequired: false + }, + order: { + payment: { + insuranceCoverage: { + isVerified: true + } + }, + policy: { + noCoverage: false, + policyLookupSuccessful: true + }, + currentDeductible: servicePrice + 1 + } + }; + const { wrapper } = getMountedComponent(storeState); + + // Act + const result = wrapper.vm.verifiedDeductible; + + // Assert + expect(result).toBeFalsy(); + }); + }); + describe('isADAS', () => { + test('returns false when glassParts null', () => { + // Arrange + const mainInitialState = { + order: { + lineItems: { + glassParts: null + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isADAS; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when glassParts empty', () => { + // Arrange + const mainInitialState = { + order: { + lineItems: { + glassParts: [] + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isADAS; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when no parts in glassParts require recalibration', () => { + // Arrange + const mainInitialState = { + order: { + lineItems: { + glassParts: [ + { + partNumber: 123, + requiresRecalibration: false + }, + { + partNumber: 111, + requiresRecalibration: false + } + ] + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isADAS; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns true when a part in glassParts require recalibration', () => { + // Arrange + const mainInitialState = { + order: { + lineItems: { + glassParts: [ + { + partNumber: 123, + requiresRecalibration: true + }, + { + partNumber: 111, + requiresRecalibration: false + } + ] + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isADAS; + + // Assert + expect(result).toBeTruthy(); + }); + }); + describe('isQuoteDisplayed', () => { + test('returns false when policy lookup not successful', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + policyLookupSuccessful: false + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isQuoteDisplayed; + + // Assert + expect(result).toBeFalsy(); + }); + describe('not no comp', () => { + const priceOfLineItems = 341; + test('returns false when deductible equal to service price', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + policyLookupSuccessful: true, + noCoverage: false + }, + currentDeductible: priceOfLineItems + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isQuoteDisplayed; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when deductible less than service price', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + policyLookupSuccessful: true, + noCoverage: false + }, + currentDeductible: priceOfLineItems - 1 + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isQuoteDisplayed; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns true when policy lookup successful and deductible over service price', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + policyLookupSuccessful: true, + noCoverage: false + }, + currentDeductible: priceOfLineItems + 1 + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isQuoteDisplayed; + + // Assert + expect(result).toBeTruthy(); + }); + }); + describe('not itac', () => { + const priceOfLineItems = 23; + test('returns false when isNoComp false', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + policyLookupSuccessful: true, + noCoverage: false + }, + currentDeductible: priceOfLineItems + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isQuoteDisplayed; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns true when isNoComp true', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + policyLookupSuccessful: true, + noCoverage: true + }, + currentDeductible: priceOfLineItems + } + }; + getPriceOfLineItems.mockImplementationOnce(() => priceOfLineItems); + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.isQuoteDisplayed; + + // Assert + expect(result).toBeTruthy(); + }); + }); + }); + describe.each([[0], [12]])('shouldRegisterClaim', (policyVehicleId) => { + const servicePrice = 90; + let shouldRegisterClaimStoreStateItac; + beforeEach(() => { + shouldRegisterClaimStoreStateItac = { + order: { + payment: { + insuranceCoverage: { claimNumber: null } + }, + policy: { + policyLookupSuccessful: true, + noCoverage: false + }, + vehicle: { + policyVehicleId + }, + currentDeductible: servicePrice - 1 + }, + issConfig: { + isClaimRegistrationRequired: true + } + }; + getPriceOfLineItems.mockImplementation(() => servicePrice); + }); + test('returns false when policy lookup not successful', () => { + // Arrange + const mainInitialState = shouldRegisterClaimStoreStateItac; + mainInitialState.order.policy.policyLookupSuccessful = false; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.shouldRegisterClaim; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when policy vehicle id is less than 0', () => { + // Arrange + const mainInitialState = shouldRegisterClaimStoreStateItac; + mainInitialState.order.vehicle.policyVehicleId = -3; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.shouldRegisterClaim; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when policy vehicle id is null', () => { + // Arrange + const mainInitialState = shouldRegisterClaimStoreStateItac; + mainInitialState.order.vehicle.policyVehicleId = null; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.shouldRegisterClaim; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when claim registration is not required', () => { + // Arrange + const mainInitialState = shouldRegisterClaimStoreStateItac; + mainInitialState.issConfig.isClaimRegistrationRequired = false; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.shouldRegisterClaim; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when claim already registered', () => { + // Arrange + const mainInitialState = shouldRegisterClaimStoreStateItac; + mainInitialState.order.payment.insuranceCoverage.claimNumber = 13; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.shouldRegisterClaim; + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false when no comp', () => { + // Arrange + const mainInitialState = shouldRegisterClaimStoreStateItac; + mainInitialState.order.policy.noCoverage = true; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.shouldRegisterClaim; + + // Assert + expect(result).toBeFalsy(); + }); + describe('returns true when policy lookup success, vehicleId set to %p, claim reg req, claim not yet reg', () => { + test('and itac', () => { + // Arrange + const { wrapper } = getMountedComponent(shouldRegisterClaimStoreStateItac); + + // Act + const result = wrapper.vm.shouldRegisterClaim; + + // Assert + expect(result).toBeTruthy(); + }); + test.each([ + [servicePrice], + [servicePrice + 1] + ])('and deductible case', (deductibleValue) => { + // Arrange + const mainInitialState = shouldRegisterClaimStoreStateItac; + mainInitialState.currentDeductible = deductibleValue; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.shouldRegisterClaim; + + // Assert + expect(result).toBeTruthy(); + }); + }); }); - describe('unverified', () => {}); - describe('isADAS', () => {}); - describe('itacCostSavings', () => {}); - describe('isQuoteDisplayed', () => {}); - describe('shouldRegisterClaim', () => {}); }); describe('methods', () => { describe('arePagePrerequisitesValid', () => { + test('returns false if car id not set', () => { + // Arrange + const mainInitialState = { + order: { + vehicle: { + carId: null + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(result).toBeFalsy(); + }); + test('returns false if car id set to 0', () => { + // Arrange + const mainInitialState = { + order: { + vehicle: { + carId: 0 + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(result).toBeFalsy(); + }); + test.each([[-1], [1], [123]])('returns true if car id set to %p', (carId) => { + // Arrange + const mainInitialState = { + order: { + vehicle: { carId } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + const result = wrapper.vm.arePagePrerequisitesValid(); + + // Assert + expect(result).toBeTruthy(); + }); }); test.each([ [0, '$0.00'], @@ -873,7 +1581,7 @@ describe('coverageStatement.vue-working', () => { [1.254, '$1.25'], [1.255, '$1.26'], [-1, '-$1.00'] - ])('getFormattedAmount', (value, expected) => { + ])('getFormattedAmount given %p returns "%p"', (value, expected) => { // Arrange const { wrapper } = getMountedComponent(); @@ -883,9 +1591,6 @@ describe('coverageStatement.vue-working', () => { // Assert expect(result).toBe(expected); }); - describe('navigateForward', () => { - - }); }); describe('ITAC flag', () => { test('ITAC flag updated once component is initialized', async () => { diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index ad578df1..a2471fb3 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -126,7 +126,6 @@ import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin.js'; import globalRules from '@/constants/global-rules.js'; import baseFormMixin from '@/mixins/base-form-mixin.js'; import navigationScenarios from '@/router/router-constants/navigation-scenarios.js'; -import routerParams from '@/router/router-constants/router-params'; import issPageValues from '@/router/router-constants/issPage-values'; import bailoutMessage from '@/constants/bailoutMessage'; import widgetFields from '@/constants/cms-widget-fields.js'; @@ -311,8 +310,11 @@ export default { }, verifiedDeductible() { return useMainStore().isClaimRegistrationRequired - ? this.registerClaimSuccessful && this.coveredAndServicePriceAboveOrEqualDeductible && this.deductibleValue !== null - : this.policyLookupSuccessful && this.coveredAndServicePriceAboveOrEqualDeductible; + ? this.registerClaimSuccessful + && this.coveredAndServicePriceAboveOrEqualDeductible + && this.deductibleValue !== null + : this.policyLookupSuccessful + && this.coveredAndServicePriceAboveOrEqualDeductible; }, unverified() { return !this.verifiedDeductible && !this.verifiedITAC && !this.verifiedNoComp; @@ -350,6 +352,7 @@ export default { }, shouldRegisterClaim() { return this.policyLookupSuccessful + && useMainStore().vehicle.policyVehicleId != null && useMainStore().vehicle.policyVehicleId >= 0 && useMainStore().isClaimRegistrationRequired && !useMainStore().isClaimAlreadyRegistered From cba17fb6769d98cb4d5abdca30b593b1532e2657 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 7 Mar 2024 14:43:46 -0500 Subject: [PATCH 36/36] Repurposing old tests --- .../coverage-statement.spec.js | 938 +++++------------- 1 file changed, 246 insertions(+), 692 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index 8fa66c0c..65cfd347 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -10,7 +10,6 @@ import navigationScenarios from '@/router/router-constants/navigation-scenarios. import { getRandomString, getRandomInt } from '@/helpers/data-generation.js'; import settleAllPromises from '@/helpers/layout-helper.js'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; -import routerParams from '@/router/router-constants/router-params'; import { useMainStore } from '@/store/index.js'; import getPriceOfLineItems from '@/helpers/price-calculator.js'; @@ -23,6 +22,8 @@ jest.mock('@/helpers/cms-content-helper', () => ({ processIfStatements: jest.fn() })); +const SAFELITE_PROVIDER = 'Safelite'; + const mockMixin = { methods: { getCmsContent: jest.fn().mockImplementation(() => ''), @@ -89,697 +90,6 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu return { wrapper }; } -describe.skip('coverageStatement.vue', () => { - describe('method arePagePrerequisitesValid...', () => { - test('Should return true for valid page requisites if vin exists', () => { - // Arrange - const { wrapper } = getMountedComponent({ - order: { - vehicle: { - vin: getRandomString(5, 20) - } - } - }); - - // Act - const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(arePagePrerequisitesValid).toBeTruthy(); - }); - test('Should return false for valid page requisites if vin is missing', () => { - // Arrange - const { wrapper } = getMountedComponent({ - order: { - vehicle: { - vin: null - } - } - }); - - // Act - const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(arePagePrerequisitesValid).not.toBeTruthy(); - }); - }); - describe('Verified ITAC scenario', () => { - test('If policy lookup successful, not No Comp, and deductible > service price, verifiedITAC returns true', () => { - // Arrange - const sellingPrice = getRandomInt(100, 500); - const deductible = sellingPrice + 1; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - }, - policyLookupSuccessful: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ] - }); - - // Assert - expect(wrapper.vm.verifiedITAC).toBeTruthy(); - }); - test('If policy lookup unsuccessful, verifiedITAC returns false', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - policyLookupSuccessful: false - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.verifiedITAC).toBeFalsy(); - }); - test('If No Comp, verifiedITAC returns false', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.verifiedITAC).toBeFalsy(); - }); - test('If deductible < service price, verifiedITAC returns false', () => { - // Arrange - const sellingPrice = getRandomInt(100, 500); - const deductible = sellingPrice - 1; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - } - } - } - }; - - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ] - }); - - // Assert - expect(wrapper.vm.verifiedITAC).toBeFalsy(); - }); - }); - describe('Verified Deductible scenario', () => { - test('If policy lookup successful, not No Comp, and service price > deductible, verifiedITAC returns true', () => { - // Arrange - const sellingPrice = getRandomInt(100, 500); - const deductible = sellingPrice - 1; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - }, - policyLookupSuccessful: true - } - } - }; - - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ] - }); - - // Assert - expect(wrapper.vm.verifiedDeductible).toBeTruthy(); - }); - test('If policy lookup unsuccessful, verifiedDeductible returns false', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - policyLookupSuccessful: false - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.verifiedDeductible).toBeFalsy(); - }); - test('If No Comp, verifiedDeductible returns false', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.verifiedDeductible).toBeFalsy(); - }); - test('If service price < deductible, verifiedDeductible returns false', () => { - const sellingPrice = getRandomInt(100, 500); - const deductible = sellingPrice + 1; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - } - } - } - }; - - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ] - }); - - // Assert - expect(wrapper.vm.verifiedDeductible).toBeFalsy(); - }); - test('If deductible is null, verifiedDeductible returns false', () => { - const sellingPrice = getRandomInt(100, 500); - const deductible = null; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - } - } - } - }; - - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ] - }); - - // Assert - expect(wrapper.vm.verifiedDeductible).toBeFalsy(); - }); - }); - describe('No Comp scenario', () => { - test('If noCoverage = true, verifiedNoComp returns true', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: true, - policyLookupSuccessful: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.verifiedNoComp).toBeTruthy(); - }); - test('If noCoverage = false, verifiedNoComp returns false', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.verifiedNoComp).toBeFalsy(); - }); - }); - describe('Unverified scenario', () => { - test('If policyLookupSuccessful false, unverified returns true', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - policyLookupSuccessful: false - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.unverified).toBeTruthy(); - }); - test('If policyLookupSuccessful is true, unverified returns false', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - policyLookupSuccessful: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.unverified).toBeFalsy(); - }); - }); - describe('Navigation', () => { - test('If Unverified, navigate forward with CLICKED_FORWARD scenario', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - policyLookupSuccessful: false - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Act - wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('If Verified Deductible, navigate forward with CLICKED_FORWARD scenario', () => { - // Arrange - const sellingPrice = getRandomInt(100, 500); - const deductible = sellingPrice - 1; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - }, - policyLookupSuccessful: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ] - }); - - // Act - wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('If Verified ITAC and selected Safelite, navigate forward with CLICKED_FORWARD_WITH_SAFELITE scenario', () => { - // Arrange - const sellingPrice = getRandomInt(100, 500); - const deductible = sellingPrice + 1; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - }, - policyLookupSuccessful: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ], - selectedProvider: 'Safelite' - }); - - // Act - wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('If Verified ITAC, selected other shop, and TPA enabled, navigate forward w/ CLICKED_FORWARD_WITH_TPA_ENABLED', () => { - // Arrange - const sellingPrice = getRandomInt(100, 500); - const deductible = sellingPrice + 1; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - }, - policyLookupSuccessful: true - } - }, - issConfig: { - enableTPAFlow: true - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ], - selectedProvider: 'Other' - }); - - // Act - wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('If Verified ITAC, selected other shop, and TPA disabled, navigate forward w/ CLICKED_FORWARD_WITH_TPA_DISABLED', () => { - // Arrange - const sellingPrice = getRandomInt(100, 500); - const deductible = sellingPrice + 1; - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: false, - deductible: { - repair: deductible - }, - policyLookupSuccessful: true - } - }, - issConfig: { - enableTPAFlow: false - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - availableLineItems: [ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ], - selectedProvider: 'Other' - }); - - // Act - wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - test('If No Comp and selected Safelite, navigate forward with CLICKED_FORWARD scenario', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - }, - policy: { - noCoverage: true, - policyLookupSuccessful: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - wrapper.setData({ - isVerified: false, - selectedProvider: 'Safelite' - }); - - // Act - wrapper.vm.forwardButtonAction(); - - // Assert - expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, - undefined, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); - }); - }); - describe('ADAS', () => { - test('if Replace and parts require recalibration, isADAS should return true', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: false - }, - lineItems: { - glassParts: [ - { - requiresRecalibration: true - } - ] - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.isADAS).toBeTruthy(); - }); - test('if Replace and parts do not require recalibration, isADAS should return false', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: false - }, - lineItems: { - glassParts: [ - { - requiresRecalibration: false - } - ] - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.isADAS).toBeFalsy(); - }); - test('if Repair, isADAS should return true', () => { - // Arrange - const mainInitialState = { - order: { - damage: { - isRepair: true - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Assert - expect(wrapper.vm.isADAS).toBeFalsy(); - }); - }); - describe('claim registration api call', () => { - it('claim registration not required => method not called', async () => { - // Arrange - const { wrapper } = getMountedComponent({ - issConfig: { - isClaimRegistrationRequired: false - } - }); - - // Assert - expect(wrapper.vm.mainStore.registerClaim).not.toHaveBeenCalled(); - }); - - it('claim registration required => register claim method called', async () => { - // Arrange - const sellingPrice = getRandomInt(50, 100); - const deductible = sellingPrice - 1; - const initialStore = { - order: { - policy: { - policyLookupSuccessful: true, - noCoverage: false, - deductible: { - repair: deductible - } - }, - damage: { - isRepair: true - } - }, - issConfig: { - isClaimRegistrationRequired: true - } - }; - const mockStoreActions = () => { - useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve()); - useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve()); - useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve()); - useMainStore().getPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve([ - { - sellingPrice, - kitPrice: 0, - laborAmount: 0 - } - ])); - }; - const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions); - const next = (method) => { method(wrapper.vm); }; - - // Act - coverageStatement.beforeRouteEnter.call(wrapper.vm, undefined, undefined, next); - for (let i = 0; i < 7; i++) { - // eslint-disable-next-line no-await-in-loop - await nextTick(); - } - - // Assert - expect(wrapper.vm.mainStore.registerClaim).toHaveBeenCalled(); - }); - }); -}); - describe('coverageStatement.vue-working', () => { test('returns the initial data', () => { // Arrange @@ -1591,6 +901,180 @@ describe('coverageStatement.vue-working', () => { // Assert expect(result).toBe(expected); }); + describe('navigateForward', () => { + const servicePrice = 82; + beforeEach(() => { + getPriceOfLineItems.mockImplementation(() => servicePrice); + }); + test('If Unverified, navigate forward with CLICKED_FORWARD scenario', () => { + // Arrange + const mainInitialState = { + order: { + damage: { + isRepair: true + }, + policy: { + policyLookupSuccessful: false + }, + currentDeductible: null + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + wrapper.vm.navigateForward(); + + // Assert + expect(wrapper.vm.$router.navigate) + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD, + undefined + ); + }); + test('If Verified Deductible, navigate forward with CLICKED_FORWARD scenario', () => { + // Arrange + const deductible = servicePrice - 1; + const mainInitialState = { + order: { + damage: { + isRepair: true + }, + policy: { + noCoverage: false, + policyLookupSuccessful: true + }, + currentDeductible: deductible + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + wrapper.vm.navigateForward(); + + // Assert + expect(wrapper.vm.$router.navigate) + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD, + undefined + ); + }); + test('If Verified ITAC and selected Safelite, navigate forward with CLICKED_FORWARD_WITH_SAFELITE scenario', () => { + // Arrange + const deductible = servicePrice + 1; + const mainInitialState = { + order: { + damage: { + isRepair: true + }, + policy: { + noCoverage: false, + policyLookupSuccessful: true + }, + currentDeductible: deductible + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + wrapper.setData({ + selectedProvider: SAFELITE_PROVIDER + }); + + // Act + wrapper.vm.navigateForward(); + + // Assert + expect(wrapper.vm.$router.navigate) + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, + undefined + ); + }); + test('If Verified ITAC, selected other shop, navigate forward w/ CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP', () => { + // Arrange + const deductible = servicePrice + 1; + const mainInitialState = { + order: { + damage: { + isRepair: true + }, + policy: { + noCoverage: false, + policyLookupSuccessful: true + }, + currentDeductible: deductible + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + wrapper.setData({ + selectedProvider: 'Other' + }); + + // Act + wrapper.vm.navigateForward(); + + // Assert + expect(wrapper.vm.$router.navigate) + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, + undefined + ); + }); + test('If No Comp and selected Safelite, navigate forward with CLICKED_FORWARD_WITH_SAFELITE scenario', () => { + // Arrange + const mainInitialState = { + order: { + damage: { + isRepair: true + }, + policy: { + noCoverage: true, + policyLookupSuccessful: true + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + wrapper.setData({ + selectedProvider: SAFELITE_PROVIDER + }); + + // Act + wrapper.vm.navigateForward(); + + // Assert + expect(wrapper.vm.$router.navigate) + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, + undefined + ); + }); + test('If No comp and selected other shop, navigate forward with CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP ', () => { + // Arrange + const mainInitialState = { + order: { + damage: { + isRepair: true + }, + policy: { + noCoverage: true, + policyLookupSuccessful: true + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + wrapper.setData({ + selectedProvider: 'other' + }); + + // Act + wrapper.vm.navigateForward(); + + // Assert + expect(wrapper.vm.$router.navigate) + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, + undefined + ); + }); + }); }); describe('ITAC flag', () => { test('ITAC flag updated once component is initialized', async () => { @@ -1667,4 +1151,74 @@ describe('coverageStatement.vue-working', () => { expect(wrapper.vm.mainStore.registerClaim).toHaveBeenCalledTimes(0); }); }); + describe('claim registration api call', () => { + it('claim registration not required => method not called', async () => { + // Arrange + const mockStoreActions = () => { + useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve()); + useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve()); + useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve()); + useMainStore().getPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve()); + }; + const { wrapper } = getMountedComponent({ + issConfig: { + isClaimRegistrationRequired: false + } + }, {}, mockStoreActions); + const next = (method) => { method(wrapper.vm); }; + + // Act + coverageStatement.beforeRouteEnter.call(wrapper.vm, undefined, undefined, next); + for (let i = 0; i < 7; i++) { + // eslint-disable-next-line no-await-in-loop + await nextTick(); + } + + // Assert + expect(wrapper.vm.mainStore.registerClaim).not.toHaveBeenCalled(); + }); + + it('claim registration required => register claim method called', async () => { + // Arrange + const servicePrice = 7283; + const deductible = servicePrice - 1; + const initialStore = { + order: { + payment: { + insuranceCoverage: { claimNumber: null } + }, + policy: { + policyLookupSuccessful: true, + noCoverage: false + }, + vehicle: { + policyVehicleId: 1 + }, + currentDeductible: deductible + }, + issConfig: { + isClaimRegistrationRequired: true + } + }; + getPriceOfLineItems.mockImplementation(() => servicePrice); + const mockStoreActions = () => { + useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve()); + useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve()); + useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve()); + useMainStore().getPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve()); + }; + const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions); + const next = (method) => { method(wrapper.vm); }; + + // Act + coverageStatement.beforeRouteEnter.call(wrapper.vm, undefined, undefined, next); + for (let i = 0; i < 7; i++) { + // eslint-disable-next-line no-await-in-loop + await nextTick(); + } + + // Assert + expect(wrapper.vm.mainStore.registerClaim).toHaveBeenCalled(); + }); + }); });