Updating ways special strings are parsed
This commit is contained in:
parent
7150f5fd9b
commit
18710d1469
9 changed files with 75 additions and 124 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="textbox-question" :class="(errors.length > 0 || hasError) ? 'has-error' : ''">
|
<div class="textbox-question" :class="(hasError) ? 'has-error' : ''">
|
||||||
<label :for="inputId" :aria-label="questionText" class="form-label" v-html="labelText"></label>
|
<label :for="inputId" :aria-label="questionText" class="form-label" v-html="labelText"></label>
|
||||||
<input v-model="value"
|
<input v-model="value"
|
||||||
v-maska="mask"
|
v-maska="mask"
|
||||||
|
|
|
||||||
7
src/constants/magic-strings.js
Normal file
7
src/constants/magic-strings.js
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
const magicStrings = {
|
||||||
|
GLOBAL_STATE: "globalState",
|
||||||
|
CUSTOM: "custom",
|
||||||
|
ROUTER_LINK: "routerLink"
|
||||||
|
};
|
||||||
|
|
||||||
|
export { magicStrings };
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { storeActions } from "@/constants/store-actions.js";
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
import { magicStrings } from "../constants/magic-strings";
|
||||||
|
|
||||||
export function fetchCmsContentForPage(fmgPage) {
|
export function fetchCmsContentForPage(fmgPage) {
|
||||||
return store
|
return store
|
||||||
|
|
@ -42,7 +43,7 @@ function mapStringToState(str) {
|
||||||
const regexExp = new RegExp("{(.*?):(.*?)}", "g");
|
const regexExp = new RegExp("{(.*?):(.*?)}", "g");
|
||||||
const regexMatches = [...str.matchAll(regexExp)];
|
const regexMatches = [...str.matchAll(regexExp)];
|
||||||
const globalStateMatches = regexMatches.filter(match => {
|
const globalStateMatches = regexMatches.filter(match => {
|
||||||
return match[1] === "globalState";
|
return match[1] === magicStrings.GLOBAL_STATE;
|
||||||
})
|
})
|
||||||
|
|
||||||
// Our final string value that will be built from the matches.
|
// Our final string value that will be built from the matches.
|
||||||
|
|
@ -63,7 +64,7 @@ function mapStringToState(str) {
|
||||||
const stringWithReplacement = str.replace(match[0], storeState);
|
const stringWithReplacement = str.replace(match[0], storeState);
|
||||||
|
|
||||||
// If we still have values we need to substitute, call this function again.
|
// If we still have values we need to substitute, call this function again.
|
||||||
if (stringWithReplacement.includes("{globalState:")) {
|
if (stringWithReplacement.includes(magicStrings.GLOBAL_STATE)) {
|
||||||
return mapStringToState(stringWithReplacement);
|
return mapStringToState(stringWithReplacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,7 +100,7 @@ function findAndReplaceGlobalStateValues(widgetModel, widgetName) {
|
||||||
function processWidgetItemForReplacement(widgetModel, key) {
|
function processWidgetItemForReplacement(widgetModel, key) {
|
||||||
// If we have a string, and it needs to be replaced.
|
// If we have a string, and it needs to be replaced.
|
||||||
if (typeof widgetModel[key] === "string") {
|
if (typeof widgetModel[key] === "string") {
|
||||||
if (widgetModel[key].includes("{globalState:")) {
|
if (widgetModel[key].includes(magicStrings.GLOBAL_STATE)) {
|
||||||
widgetModel[key] = mapStringToState(widgetModel[key]);
|
widgetModel[key] = mapStringToState(widgetModel[key]);
|
||||||
}
|
}
|
||||||
return widgetModel[key];
|
return widgetModel[key];
|
||||||
|
|
|
||||||
5
src/helpers/damage-helper.js
Normal file
5
src/helpers/damage-helper.js
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
export function getDamageString() {
|
||||||
|
return store.getters.damage.glassToReplace.length > 1 ? "match" : store.getters.damage.glassToReplace[0].location;
|
||||||
|
}
|
||||||
|
|
@ -43,10 +43,10 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHerita
|
||||||
return 'vehicle-damage'
|
return 'vehicle-damage'
|
||||||
} else {
|
} else {
|
||||||
if (store.getters.vehicle.vin) {
|
if (store.getters.vehicle.vin) {
|
||||||
return 'vehicle-damage';
|
return 'license-plate-lookup';
|
||||||
//return "vin-lookup"; (uncomment)
|
//return "vin-lookup"; (uncomment)
|
||||||
} else {
|
} else {
|
||||||
return 'vehicle-damage';
|
return 'license-plate-lookup';
|
||||||
//return "estimate" (uncomment)
|
//return "estimate" (uncomment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -66,6 +66,9 @@ export async function navigateToHeritageFunnel() {
|
||||||
{
|
{
|
||||||
corid: store.getters.order.referralCorrelationId,
|
corid: store.getters.order.referralCorrelationId,
|
||||||
src: "concept-funnel",
|
src: "concept-funnel",
|
||||||
|
// TODO CSR-28, remove this
|
||||||
|
cns: "all",
|
||||||
|
experiments: "RemoveServiceAreaPage=ServAreaRemoval_V7=NoShowPackages_CONTROL=true,ConceptFunnel=ConceptFunnel_V1=ConceptFunnel_TEST=true"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -26,22 +26,21 @@
|
||||||
</div>
|
</div>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-3"
|
||||||
cmsWidgetName="NoServiceZipWidget"
|
:manualHeadline="NoServiceZipHeader"
|
||||||
v-model="customAlertData"
|
:manualCopy="NoServiceZipBody"
|
||||||
v-if="newServiceZipRequired"
|
v-if="newServiceZipRequired"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-3"
|
||||||
cmsWidgetName="NoMatchAlertWidget"
|
cmsWidgetName="NoMatchAlertWidget"
|
||||||
v-model="customAlertData"
|
|
||||||
v-if="vinNotValid"
|
v-if="vinNotValid"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-3"
|
||||||
cmsWidgetName="MatchedDifferentVehicleAlertWidget"
|
:manualHeadline="MatchedDifferentVehicleAlertHeader"
|
||||||
v-model="customAlertData"
|
:manualCopy="MatchedDifferentVehicleAlertBody"
|
||||||
v-if="vinDoesNotMatchCarId"
|
v-if="vinDoesNotMatchCarId"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
/>
|
/>
|
||||||
|
|
@ -78,6 +77,7 @@ import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
import { getDamageString } from "@/helpers/damage-helper";
|
||||||
import { required, regex } from "@/helpers/validation-rules";
|
import { required, regex } from "@/helpers/validation-rules";
|
||||||
import { Form, defineRule } from "vee-validate";
|
import { Form, defineRule } from "vee-validate";
|
||||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
@ -125,6 +125,35 @@ export default {
|
||||||
customAlertData: {}
|
customAlertData: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
MatchedDifferentVehicleAlertHeader(){
|
||||||
|
let text = this.getCmsContent("MatchedDifferentVehicleAlertWidget", "HeadlineText");
|
||||||
|
// Replace all instances where custom data is implemented
|
||||||
|
text = text.replaceAll("{custom:damage}", getDamageString());
|
||||||
|
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
MatchedDifferentVehicleAlertBody(){
|
||||||
|
let text = this.getCmsContent("MatchedDifferentVehicleAlertWidget", "BodyText");
|
||||||
|
// Replace all instances where custom data is implemented
|
||||||
|
text = text.replaceAll("{custom:damage}", getDamageString());
|
||||||
|
text = text.replaceAll("{custom:plateLookupYear}", this.customAlertData?.vehicleInfo?.year);
|
||||||
|
text = text.replaceAll("{custom:plateLookupMake}", this.customAlertData?.vehicleInfo?.make);
|
||||||
|
text = text.replaceAll("{custom:plateLookupModel}", this.customAlertData?.vehicleInfo?.model);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
NoServiceZipHeader(){
|
||||||
|
let text = this.getCmsContent("NoServiceZipWidget", "HeadlineText");
|
||||||
|
// Replace all instances where custom data is implemented
|
||||||
|
text = text.replaceAll("{custom:zip}", this.zip);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
NoServiceZipBody(){
|
||||||
|
return this.getCmsContent("NoServiceZipWidget", "BodyText");
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
return store.getters.vehicle.carId !== null;
|
return store.getters.vehicle.carId !== null;
|
||||||
|
|
@ -171,7 +200,7 @@ export default {
|
||||||
vehicleInfo = store.getters.vehicle;
|
vehicleInfo = store.getters.vehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateStore(vin, vehicleInfo, zipValidation.data.state);
|
this.updateCustomerInfo(vin, vehicleInfo, zipValidation.data.state);
|
||||||
|
|
||||||
const partsData = await baseMixin.methods.dispatchNonBlockingStoreAction(
|
const partsData = await baseMixin.methods.dispatchNonBlockingStoreAction(
|
||||||
this.storeActions.GET_PARTS_OR_QUESTIONS,
|
this.storeActions.GET_PARTS_OR_QUESTIONS,
|
||||||
|
|
@ -209,7 +238,7 @@ export default {
|
||||||
{ licensePlate: plate, licenseState: state }
|
{ licensePlate: plate, licenseState: state }
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
updateStore(vin, vehicleInfo, registrationState) {
|
updateCustomerInfo(vin, vehicleInfo, registrationState) {
|
||||||
// if(vehicleDamage){
|
// if(vehicleDamage){
|
||||||
// store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
// store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
// }
|
// }
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
<h1>Part Questions Page Placeholder</h1>
|
<h1>Part Questions Page Placeholder</h1>
|
||||||
<funnel-footer
|
<funnel-footer
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget" @back-clicked="backButtonAction"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import { createStore } from 'vuex'
|
|
||||||
import alert from "./alert";
|
import alert from "./alert";
|
||||||
|
|
||||||
describe("alert.vue", () => {
|
describe("alert.vue", () => {
|
||||||
|
|
@ -11,7 +10,7 @@ describe("alert.vue", () => {
|
||||||
isDismissible: true
|
isDismissible: true
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
alertCopy: {
|
splitAlertCopyForLink: {
|
||||||
get() {
|
get() {
|
||||||
return "TEST";
|
return "TEST";
|
||||||
},
|
},
|
||||||
|
|
@ -33,7 +32,7 @@ describe("alert.vue", () => {
|
||||||
alertClass: 'warning'
|
alertClass: 'warning'
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
alertCopy: {
|
splitAlertCopyForLink: {
|
||||||
get() {
|
get() {
|
||||||
return "TEST";
|
return "TEST";
|
||||||
},
|
},
|
||||||
|
|
@ -48,9 +47,10 @@ describe("alert.vue", () => {
|
||||||
expect(wrapperDiv.classes()).toContain('warning')
|
expect(wrapperDiv.classes()).toContain('warning')
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should return original string if no custom string notations added", async () => {
|
it("Should update headline when manual headline added", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const wrapper = shallowMount(alert, {
|
const wrapper = shallowMount(alert, {
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
alertCopy: {
|
alertCopy: {
|
||||||
get() {
|
get() {
|
||||||
|
|
@ -61,69 +61,11 @@ describe("alert.vue", () => {
|
||||||
mixins: [mockMixin]
|
mixins: [mockMixin]
|
||||||
});
|
});
|
||||||
|
|
||||||
const stringWithNoCustomAtrributes = wrapper.vm.checkForCustomStrings("Test string")
|
await wrapper.vm.$nextTick();
|
||||||
|
const wrapperDiv = wrapper.find('.text-body');
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(stringWithNoCustomAtrributes).toEqual("Test string")
|
expect(wrapperDiv.text()).toEqual('TEST')
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return link when custom string notation with 'routerLink' included", async () => {
|
|
||||||
// Arrange
|
|
||||||
const wrapper = shallowMount(alert, {
|
|
||||||
computed: {
|
|
||||||
alertCopy: {
|
|
||||||
get() {
|
|
||||||
return "TEST";
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mixins: [mockMixin]
|
|
||||||
});
|
|
||||||
|
|
||||||
const stringWithNoCustomAtrributes = wrapper.vm.checkForCustomStrings("{routerLink:clickedChangeVinLookupMethod,provide your VIN}")
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(stringWithNoCustomAtrributes).toEqual("{routerLink:clickedChangeVinLookupMethod,provide your VIN}")
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return zip when custom string notation with 'custom' for zip is called.", async () => {
|
|
||||||
// Arrange
|
|
||||||
const wrapper = shallowMount(alert, {
|
|
||||||
propsData: {modelValue: {zip: "12345"}},
|
|
||||||
computed: {
|
|
||||||
alertCopy: {
|
|
||||||
get() {
|
|
||||||
return "TEST";
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mixins: [mockMixin]
|
|
||||||
});
|
|
||||||
|
|
||||||
const stringWithNoCustomAtrributes = wrapper.vm.checkForCustomStrings("{custom:zip}")
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(stringWithNoCustomAtrributes).toEqual("12345")
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return custom datum specified when custom string notation with 'custom' for lookup is called.", async () => {
|
|
||||||
// Arrange
|
|
||||||
const wrapper = shallowMount(alert, {
|
|
||||||
propsData: {modelValue: {vehicleInfo: {year: "2020"}}},
|
|
||||||
computed: {
|
|
||||||
alertCopy: {
|
|
||||||
get() {
|
|
||||||
return "TEST";
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mixins: [mockMixin]
|
|
||||||
});
|
|
||||||
|
|
||||||
const stringWithNoCustomAtrributes = wrapper.vm.checkForCustomStrings("{custom:plateLookupYear}")
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(stringWithNoCustomAtrributes).toEqual("2020")
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
role="alert"
|
role="alert"
|
||||||
:class="[isDismissible ? 'alert-dismissible' : '', this.alertClass]"
|
:class="[isDismissible ? 'alert-dismissible' : '', this.alertClass]"
|
||||||
>
|
>
|
||||||
<p class="m-0 fw-bold small alert-heading" v-html="alertHeadline"></p>
|
<p class="m-0 fw-bold small alert-heading">{{ alertHeadline }}</p>
|
||||||
<p v-if="alertCopy.includes('routerLink:')">
|
<p v-if="splitAlertCopyForLink.length">
|
||||||
<template v-for="copy in alertCopy.split(/{(.*?)}/g)" :key="copy">
|
<template v-for="copy in splitAlertCopyForLink" :key="copy">
|
||||||
<span v-if="copy.includes('routerLink:')" class="m-0 text-body small">
|
<span v-if="copy.includes('routerLink:')" class="m-0 text-body small">
|
||||||
<router-link :to="{query: {fmgPage: `${copy.split(':')[1].split(',')[0]}`}, name: 'root'}">{{ copy.split(':')[1].split(',')[1] }}</router-link>
|
<router-link :to="{query: {fmgPage: `${copy.split(':')[1].split(',')[0]}`}, name: 'root'}">{{ copy.split(':')[1].split(',')[1] }}</router-link>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -34,7 +34,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import store from "@/store";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "alert",
|
name: "alert",
|
||||||
|
|
@ -51,52 +50,17 @@ export default {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
manualHeadline: String,
|
manualHeadline: String,
|
||||||
manualCopy: String,
|
manualCopy: String,
|
||||||
modelValue: {}
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
alertHeadline(){
|
alertHeadline(){
|
||||||
return this.cmsWidgetName ? this.checkForCustomStrings(this.getCmsContent(this.cmsWidgetName, 'HeadlineText')) : this.manualHeadline;
|
return this.cmsWidgetName ? this.getCmsContent(this.cmsWidgetName, 'HeadlineText') : this.manualHeadline;
|
||||||
},
|
},
|
||||||
alertCopy(){
|
alertCopy(){
|
||||||
return this.cmsWidgetName ? this.checkForCustomStrings(this.getCmsContent(this.cmsWidgetName, 'BodyText')) : this.manualCopy;
|
return this.cmsWidgetName ? this.getCmsContent(this.cmsWidgetName, 'BodyText') : this.manualCopy;
|
||||||
},
|
},
|
||||||
},
|
splitAlertCopyForLink(){
|
||||||
methods: {
|
// Splits content when brackets are found in text so that text can be looped through and router-link can be injected when needed
|
||||||
checkForCustomStrings(str){
|
return this.alertCopy.split(/{(.*?)}/g);
|
||||||
let returnElement = "";
|
|
||||||
|
|
||||||
if(str.includes("{custom:")){
|
|
||||||
const regexExp = new RegExp("{(.*?)}", "g");
|
|
||||||
|
|
||||||
const splitOnSpecialData = str.split(regexExp);
|
|
||||||
for(const item of splitOnSpecialData){
|
|
||||||
let itemToAdd;
|
|
||||||
if(item.includes("custom:")){
|
|
||||||
const splitItem = item.split(":");
|
|
||||||
const customDataAttribute = splitItem[1].includes("plateLookup") ? splitItem[1].split("plateLookup")[1].toLowerCase() : splitItem[1];
|
|
||||||
switch(customDataAttribute){
|
|
||||||
case "damage":
|
|
||||||
itemToAdd = store.getters.damage.glassToReplace.length > 1 ? "match" : store.getters.damage.glassToReplace[0].location;
|
|
||||||
break;
|
|
||||||
case "zip":
|
|
||||||
itemToAdd = this.modelValue.zip;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
itemToAdd = this.modelValue.vehicleInfo[customDataAttribute];
|
|
||||||
}
|
|
||||||
} else if(item.includes("routerLink:")){
|
|
||||||
itemToAdd = `{${item}}`;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
itemToAdd = item;
|
|
||||||
}
|
|
||||||
returnElement += itemToAdd;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
returnElement = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnElement;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue