Merge remote-tracking branch 'origin/develop' into feature/CSR-731

This commit is contained in:
Scott Kiener 2022-11-03 08:37:13 -04:00
commit 2ae16d3f01
27 changed files with 607 additions and 334 deletions

3
.gitattributes vendored Normal file
View file

@ -0,0 +1,3 @@
*.js text eol=lf
*.vue text eol=lf
*.scss text eol=lf

View file

@ -20,13 +20,15 @@ resources:
- container: node - container: node
image: packagerepository.sagaws.net:8082/safelite/node-build:15 image: packagerepository.sagaws.net:8082/safelite/node-build:15
- container: awscli - container: awscli
image: packagerepository.sagaws.net:8082/safelite/awscli-build:3.7 image: packagerepository.sagaws.net:8082/safelite/awscli2-build:3.9
- container: prettier-node
image: packagerepository.sagaws.net:8082/safelite/prettier-node-build:18
repositories: repositories:
- repository: AzureDevOps - repository: AzureDevOps
type: github type: github
name: Safelite/AzureDevOps name: Safelite/AzureDevOps
endpoint: Safelite endpoint: Safelite
ref: refs/tags/t5.5.31 ref: refs/tags/t5.5.40
variables: variables:
- group: Digital-Infrastructure - group: Digital-Infrastructure
@ -35,17 +37,25 @@ variables:
stages: stages:
# PR's # PR's
- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
- stage: TestPr - stage: TestFormat
displayName: Run Unit Tests For PullRequest displayName: Test Code Format
jobs: jobs:
- template: templates/digital/vue-jest-run-unit-tests.yml@AzureDevOps - job: checkFormatting
parameters: displayName: Check formatting
nodeContainer: node container: prettier-node
npmLocation: $(Build.SourcesDirectory) steps:
testResultsFile: junit.xml - bash: prettier --check "$(Build.SourcesDirectory)/src/**/*.(js|vue)"
summaryFileLocation: $(Build.SourcesDirectory)/coverage/cobertura-coverage.xml displayName: Run Prettier check
- stage: TestPr
displayName: Run Unit Tests For PullRequest
jobs:
- template: templates/digital/vue-jest-run-unit-tests.yml@AzureDevOps
parameters:
nodeContainer: node
npmLocation: $(Build.SourcesDirectory)
testResultsFile: junit.xml
summaryFileLocation: $(Build.SourcesDirectory)/coverage/cobertura-coverage.xml
- ${{ else }}: - ${{ else }}:
# Dev Build/Deploy # Dev Build/Deploy
- stage: Dev - stage: Dev
@ -91,8 +101,66 @@ stages:
indexDeployVariables: indexDeployVariables:
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
cfDistributionId: $(cfDistributionId) cfDistributionId: $(vueCfDistributionId)
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
parameters:
awsCliContainer: awscli
distributionId: $(apiCfDistributionId)
paths: /fmg/*
awsProfile: $(devDeploymentProfile)
# Test Build/Deploy
- stage: Test
condition: eq(variables['Build.SourceBranch'], variables['test-branch'] )
variables:
- group: FixMyGlassTest
jobs:
- deployment: testBuildDeployment
displayName: Build and Deploy FMG - Test
environment: digitalCloud-sys
container: node
workspace:
clean: all
strategy:
runOnce:
deploy:
steps:
- checkout: self
clean: true
- template: templates/digital/step-build-vue.yml@AzureDevOps
parameters:
buildOutputDir: dist
environment: Test
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
parameters:
artifactName: vueDistTest
awsProfile: $(sysDeploymentProfile)
outputPath: /fmg/
deployBuckets:
safelite-sys-fmg-us-east-1:
clearFolder: true
deployFolder: ""
region: us-east-1
safelite-sys-fmg-us-east-2:
clearFolder: true
deployFolder: ""
region: us-east-2
appDeployVariables:
__VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__)
__VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__)
__VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__)
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
indexDeployVariables:
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
cfDistributionId: $(vueCfDistributionId)
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
parameters:
awsCliContainer: awscli
distributionId: $(apiCfDistributionId)
paths: /fmg/*
awsProfile: $(sysDeploymentProfile)
# QA Build/Deploy # QA Build/Deploy
- stage: Qa - stage: Qa
condition: eq(variables['Build.SourceBranch'], variables['qa-branch'] ) condition: eq(variables['Build.SourceBranch'], variables['qa-branch'] )
@ -137,7 +205,13 @@ stages:
indexDeployVariables: indexDeployVariables:
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
cfDistributionId: $(cfDistributionId) cfDistributionId: $(vueCfDistributionId)
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
parameters:
awsCliContainer: awscli
distributionId: $(apiCfDistributionId)
paths: /fmg/*
awsProfile: $(qaDeploymentProfile)
# Prod Build/Deploy # Prod Build/Deploy
- stage: Prod - stage: Prod
@ -183,7 +257,13 @@ stages:
indexDeployVariables: indexDeployVariables:
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
cfDistributionId: $(cfDistributionId) cfDistributionId: $(apiCfDistributionId)
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
parameters:
awsCliContainer: awscli
distributionId: $(apiCfDistributionId)
paths: /fmg/*
awsProfile: $(prodDeploymentProfile)
- template: templates/digital/auto-tag.yml@AzureDevOps - template: templates/digital/auto-tag.yml@AzureDevOps
parameters: parameters:
dependsOn: prodBuildDeployment dependsOn: prodBuildDeployment

View file

@ -16,7 +16,7 @@
aria-label="Close"></button> aria-label="Close"></button>
</div> </div>
<div class="modal-body ps-4 pe-4 pt-5 pb-4"> <div class="modal-body ps-4 pe-4 pt-5 pb-4">
<img :src="this.ModalImage" alt="" /> <img :src="this.ModalImage" class="w-100 mb-4" alt="" />
<h5 class="mb-4" v-html="this.ModalHeadline"></h5> <h5 class="mb-4" v-html="this.ModalHeadline"></h5>
<p class="fw-bold mb-2 subheader-text" v-html="this.ModalSubheadertext"></p> <p class="fw-bold mb-2 subheader-text" v-html="this.ModalSubheadertext"></p>
<p class="mb-0" v-html="this.ModalBodyText"></p> <p class="mb-0" v-html="this.ModalBodyText"></p>
@ -91,11 +91,6 @@ export default {
margin-bottom: 0; margin-bottom: 0;
} }
} }
img {
display: flex;
margin: 0 auto 1.5rem auto;
max-width: 100%;
}
} }
} }
&.modal-dialog-centered { &.modal-dialog-centered {

View file

@ -19,7 +19,7 @@ export function getDamageString() {
if (damageLocations.length > 1) { if (damageLocations.length > 1) {
returnString = "match"; returnString = "match";
} else { } else {
switch (damageLocations[0]?.location) { switch (damageLocations[0]?.glassLocation) {
case "Windshield": case "Windshield":
returnString = "windshield"; returnString = "windshield";
break; break;
@ -37,7 +37,7 @@ export function getDamageString() {
export function getIsWindshieldOnly() { export function getIsWindshieldOnly() {
const damageLocations = store.getters.damage.glassToReplace; const damageLocations = store.getters.damage.glassToReplace;
const returnString = const returnString =
damageLocations.length === 1 && damageLocations[0]?.location === "Windshield" damageLocations.length === 1 && damageLocations[0]?.glassLocation === "Windshield"
? "windshield" ? "windshield"
: "glass"; : "glass";
return returnString; return returnString;
@ -60,9 +60,9 @@ export async function isGlassAvailableForCarId(carId) {
for (const option of currentGlassOptions) { for (const option of currentGlassOptions) {
if ( if (
!newGlassOptions.data[optionsMap[option.location]].availableReplacementOptions.includes( !newGlassOptions.data[
option.name optionsMap[option.glassLocation]
) ].availableReplacementOptions.includes(option.glassName)
) { ) {
return false; return false;
} }

View file

@ -18,8 +18,8 @@ describe("damage-helper.js", () => {
it("Should return match when multiple selected damage options are in the store", () => { it("Should return match when multiple selected damage options are in the store", () => {
// Arrange / Act // Arrange / Act
store.getters.damage.glassToReplace = [ store.getters.damage.glassToReplace = [
{ location: "Windshield", name: "windshield" }, { glassLocation: "Windshield", glassName: "windshield" },
{ location: "Passenger", name: "sideWindow" }, { glassLocation: "Passenger", glassName: "sideWindow" },
]; ];
const damage = getDamageString(); const damage = getDamageString();
@ -32,7 +32,9 @@ describe("damage-helper.js", () => {
describe("damage-helper.js", () => { describe("damage-helper.js", () => {
it("Should return windshield when Windshield is the only selected damage option in the store", () => { it("Should return windshield when Windshield is the only selected damage option in the store", () => {
// Arrange / Act // Arrange / Act
store.getters.damage.glassToReplace = [{ location: "Windshield", name: "windshield" }]; store.getters.damage.glassToReplace = [
{ glassLocation: "Windshield", glassName: "windshield" },
];
const damage = getDamageString(); const damage = getDamageString();
@ -44,7 +46,9 @@ describe("damage-helper.js", () => {
describe("damage-helper.js", () => { describe("damage-helper.js", () => {
it("Should return side window when Driver or Passenger is the only selected damage option in the store", () => { it("Should return side window when Driver or Passenger is the only selected damage option in the store", () => {
// Arrange / Act // Arrange / Act
store.getters.damage.glassToReplace = [{ location: "Passenger", name: "sideWindow" }]; store.getters.damage.glassToReplace = [
{ glassLocation: "Passenger", glassName: "sideWindow" },
];
const damage = getDamageString(); const damage = getDamageString();
@ -56,7 +60,7 @@ describe("damage-helper.js", () => {
describe("damage-helper.js", () => { describe("damage-helper.js", () => {
it("Should return rear window when Rear is the only selected damage option in the store", () => { it("Should return rear window when Rear is the only selected damage option in the store", () => {
// Arrange / Act // Arrange / Act
store.getters.damage.glassToReplace = [{ location: "Rear", name: "rear" }]; store.getters.damage.glassToReplace = [{ glassLocation: "Rear", glassName: "rear" }];
const damage = getDamageString(); const damage = getDamageString();
@ -68,7 +72,9 @@ describe("damage-helper.js", () => {
describe("damage-helper.js", () => { describe("damage-helper.js", () => {
it("Should return true if no mismatches between each array exist", async () => { it("Should return true if no mismatches between each array exist", async () => {
// Arrange // Arrange
store.getters.damage.glassToReplace = [{ location: "Windshield", name: "windshield" }]; store.getters.damage.glassToReplace = [
{ glassLocation: "Windshield", glassName: "windshield" },
];
// Act // Act
const isGlassAvailable = await isGlassAvailableForCarId(); const isGlassAvailable = await isGlassAvailableForCarId();
@ -81,7 +87,9 @@ describe("damage-helper.js", () => {
describe("damage-helper.js", () => { describe("damage-helper.js", () => {
it("Should return false if any mismatches between each array exist", async () => { it("Should return false if any mismatches between each array exist", async () => {
// Arrange // Arrange
store.getters.damage.glassToReplace = [{ location: "Windshield", name: "sideWindow" }]; store.getters.damage.glassToReplace = [
{ glassLocation: "Windshield", glassName: "sideWindow" },
];
const isGlassAvailable = await isGlassAvailableForCarId(); const isGlassAvailable = await isGlassAvailableForCarId();

View file

@ -92,6 +92,7 @@ export const cookies = {
skey: "12345", skey: "12345",
}; };
// Removes test cookies for testing cookie-helper and order-helper
export function removeAllTestCookies() { export function removeAllTestCookies() {
Object.keys(cookies).forEach((key) => { Object.keys(cookies).forEach((key) => {
document.cookie = `${key}=;Max-Age=0;`; document.cookie = `${key}=;Max-Age=0;`;

View file

@ -18,7 +18,7 @@
<div v-for="(glass, i) in capabilityQuestionsData" :key="glass.key"> <div v-for="(glass, i) in capabilityQuestionsData" :key="glass.key">
<questionChain <questionChain
ref="questionChain" ref="questionChain"
v-model="selectedAnswers[glass.location + '-' + glass.name]" v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]"
:questionData="glass.capabilityQuestions" :questionData="glass.capabilityQuestions"
:glassIndex="i" :glassIndex="i"
v-if="showThisQuestionChain(glass, i)" v-if="showThisQuestionChain(glass, i)"
@ -99,7 +99,7 @@ export default {
}, },
windshieldPart() { windshieldPart() {
return this.pageData.partsOrQuestions.find( return this.pageData.partsOrQuestions.find(
(x) => x.location === damageLocationsSelected.WINDSHIELD (x) => x.glassLocation === damageLocationsSelected.WINDSHIELD
); );
}, },
windshieldPartInfo() { windshieldPartInfo() {
@ -152,8 +152,8 @@ export default {
); );
return { return {
location: glass.location, glassLocation: glass.glassLocation,
name: glass.name, glassName: glass.glassName,
result: glass.answerData.answerResult, result: glass.answerData.answerResult,
result1: glass.answerData.answerResult, result1: glass.answerData.answerResult,
result2: selectedAnswerResult2, result2: selectedAnswerResult2,
@ -178,12 +178,12 @@ export default {
let partsOrQuestions = this.pageData.partsOrQuestions; let partsOrQuestions = this.pageData.partsOrQuestions;
for (let answer of capabilityQuestionsAnswersArray) { for (let answer of capabilityQuestionsAnswersArray) {
const correspondingPart = partsOrQuestions.find( const correspondingPart = partsOrQuestions.find(
(partOrQuestion) => partOrQuestion.location === answer.location (partOrQuestion) => partOrQuestion.glassLocation === answer.glassLocation
); );
const partFromCapabilityQuestionAnswer = ( const partFromCapabilityQuestionAnswer = (
await this.dispatchStoreAction( await this.dispatchStoreAction(
storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER, storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER,
answer.location, answer.glassLocation,
false false
) )
).data; ).data;
@ -280,8 +280,8 @@ export default {
// Update the key to re-render this part's question-chain component // Update the key to re-render this part's question-chain component
this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].key =
this.capabilityQuestionsData[gpIndex].location + this.capabilityQuestionsData[gpIndex].glassLocation +
this.capabilityQuestionsData[gpIndex].name + this.capabilityQuestionsData[gpIndex].glassName +
Date.now().toString(); Date.now().toString();
// handle suppressing downstream in this question chain // handle suppressing downstream in this question chain
@ -392,8 +392,8 @@ export default {
// Update the key to re-render this part's question-chain component // Update the key to re-render this part's question-chain component
this.capabilityQuestionsData[gpIndex].key = this.capabilityQuestionsData[gpIndex].key =
this.capabilityQuestionsData[gpIndex].location + this.capabilityQuestionsData[gpIndex].glassLocation +
this.capabilityQuestionsData[gpIndex].name + this.capabilityQuestionsData[gpIndex].glassName +
Date.now().toString(); Date.now().toString();
} }
}); });

View file

@ -51,7 +51,6 @@
<alert <alert
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
class="my-3" class="my-3"
cmsWidgetName="AlertNonServiceableZipWidget"
:manualHeadline="AlertNonServiceableZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
:manualCopy="AlertNonServiceableZipBody" :manualCopy="AlertNonServiceableZipBody"
alertClass="alert-danger" alertClass="alert-danger"

View file

@ -19,7 +19,7 @@
<div v-for="(glass, i) in moldingQuestionsData" :key="glass.key"> <div v-for="(glass, i) in moldingQuestionsData" :key="glass.key">
<questionChain <questionChain
ref="questionChain" ref="questionChain"
v-model="selectedAnswers[glass.location + '-' + glass.name]" v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]"
:questionData="glass.questions" :questionData="glass.questions"
:glassIndex="i" :glassIndex="i"
v-if="showThisQuestionChain(glass, i)" v-if="showThisQuestionChain(glass, i)"
@ -135,8 +135,8 @@ export default {
async forwardButtonAction() { async forwardButtonAction() {
const questionAnswersArray = this.moldingQuestionsData.map((glass) => { const questionAnswersArray = this.moldingQuestionsData.map((glass) => {
return { return {
location: glass.location, glassLocation: glass.glassLocation,
name: glass.name, glassName: glass.glassName,
partNum: glass.answerData.answerResult, partNum: glass.answerData.answerResult,
answeredQuestions: glass.answerData.answeredQuestions, answeredQuestions: glass.answerData.answeredQuestions,
isSuppressedPart: glass.isSuppressedPart, isSuppressedPart: glass.isSuppressedPart,
@ -160,8 +160,8 @@ export default {
for (let answer of questionAnswersArray) { for (let answer of questionAnswersArray) {
partsOrQuestions.find((partOrQuestion) => { partsOrQuestions.find((partOrQuestion) => {
return ( return (
partOrQuestion.location === answer.location && partOrQuestion.glassLocation === answer.glassLocation &&
partOrQuestion.name === answer.name partOrQuestion.glassName === answer.glassName
); );
}).parts[0].childParts = [ }).parts[0].childParts = [
{ {
@ -256,8 +256,8 @@ export default {
// Update the key to re-render this part's question-chain component // Update the key to re-render this part's question-chain component
this.moldingQuestionsData[gpIndex].key = this.moldingQuestionsData[gpIndex].key =
this.moldingQuestionsData[gpIndex].location + this.moldingQuestionsData[gpIndex].glassLocation +
this.moldingQuestionsData[gpIndex].name + this.moldingQuestionsData[gpIndex].glassName +
Date.now().toString(); Date.now().toString();
// handle suppressing downstream in this question chain // handle suppressing downstream in this question chain
@ -368,8 +368,8 @@ export default {
// Update the key to re-render this part's question-chain component // Update the key to re-render this part's question-chain component
this.moldingQuestionsData[gpIndex].key = this.moldingQuestionsData[gpIndex].key =
this.moldingQuestionsData[gpIndex].location + this.moldingQuestionsData[gpIndex].glassLocation +
this.moldingQuestionsData[gpIndex].name + this.moldingQuestionsData[gpIndex].glassName +
Date.now().toString(); Date.now().toString();
} }
}); });

View file

@ -19,7 +19,7 @@
<div v-for="(glass, i) in partsQuestionsData" :key="glass.key"> <div v-for="(glass, i) in partsQuestionsData" :key="glass.key">
<questionChain <questionChain
ref="questionChain" ref="questionChain"
v-model="selectedAnswers[glass.location + '-' + glass.name]" v-model="selectedAnswers[glass.glassLocation + '-' + glass.glassName]"
:questionData="glass.questions" :questionData="glass.questions"
:glassIndex="i" :glassIndex="i"
v-if="showThisQuestionChain(glass, i)" v-if="showThisQuestionChain(glass, i)"
@ -130,8 +130,8 @@ export default {
async forwardButtonAction() { async forwardButtonAction() {
const questionAnswersArray = this.partsQuestionsData.map((glass) => { const questionAnswersArray = this.partsQuestionsData.map((glass) => {
return { return {
location: glass.location, glassLocation: glass.glassLocation,
name: glass.name, glassName: glass.glassName,
result: glass.answerData.answerResult, result: glass.answerData.answerResult,
answeredQuestions: glass.answerData.answeredQuestions, answeredQuestions: glass.answerData.answeredQuestions,
isSuppressedPart: glass.isSuppressedPart, isSuppressedPart: glass.isSuppressedPart,
@ -243,8 +243,8 @@ export default {
// Update the key to re-render this part's question-chain component // Update the key to re-render this part's question-chain component
this.partsQuestionsData[gpIndex].key = this.partsQuestionsData[gpIndex].key =
this.partsQuestionsData[gpIndex].location + this.partsQuestionsData[gpIndex].glassLocation +
this.partsQuestionsData[gpIndex].name + this.partsQuestionsData[gpIndex].glassName +
Date.now().toString(); Date.now().toString();
// handle suppressing downstream in this question chain // handle suppressing downstream in this question chain
@ -355,8 +355,8 @@ export default {
// Update the key to re-render this part's question-chain component // Update the key to re-render this part's question-chain component
this.partsQuestionsData[gpIndex].key = this.partsQuestionsData[gpIndex].key =
this.partsQuestionsData[gpIndex].location + this.partsQuestionsData[gpIndex].glassLocation +
this.partsQuestionsData[gpIndex].name + this.partsQuestionsData[gpIndex].glassName +
Date.now().toString(); Date.now().toString();
} }
}); });

View file

@ -80,8 +80,8 @@ describe("vehicle-damage.vue", () => {
const partsData = { const partsData = {
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: null, parts: null,
partQuestions: [ partQuestions: [
{ {
@ -154,10 +154,10 @@ describe("vehicle-damage.vue", () => {
}); });
const expectedGlassToReplace = [ const expectedGlassToReplace = [
{ location: "Windshield", name: "Single" }, { glassLocation: "Windshield", glassName: "Single" },
{ location: "Driver", name: "Back" }, { glassLocation: "Driver", glassName: "Back" },
{ location: "Passenger", name: "Quarter" }, { glassLocation: "Passenger", glassName: "Quarter" },
{ location: "Rear", name: "Stationary" }, { glassLocation: "Rear", glassName: "Stationary" },
]; ];
//Act //Act
@ -184,8 +184,8 @@ describe("vehicle-damage.vue", () => {
const partsData = { const partsData = {
partsOrQuestions: [ partsOrQuestions: [
{ {
location: "Windshield", glassLocation: "Windshield",
name: "Single", glassName: "Single",
partQuestions: null, partQuestions: null,
parts: [ parts: [
{ {
@ -205,8 +205,8 @@ describe("vehicle-damage.vue", () => {
], ],
}, },
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "DB09626GTYN", partNumber: "DB09626GTYN",
@ -253,7 +253,7 @@ describe("vehicle-damage.vue", () => {
selectedWindshieldDamageType: "Replace", selectedWindshieldDamageType: "Replace",
}; };
const expectedGlassToReplace = [{ location: "Windshield", name: "Single" }]; const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }];
//Act //Act
vehicleDamage.beforeRouteEnter.call( vehicleDamage.beforeRouteEnter.call(
@ -526,7 +526,7 @@ describe("vehicle-damage.vue", () => {
store.getters = { store.getters = {
vehicle: { carId: "C0000000" }, vehicle: { carId: "C0000000" },
eventBusItem: jest.fn(), eventBusItem: jest.fn(),
damage: { glassToReplace: [{ location: damageLocation }] }, damage: { glassToReplace: [{ glassLocation: damageLocation }] },
isRepair: true, isRepair: true,
}; };
@ -601,7 +601,7 @@ describe("vehicle-damage.vue", () => {
vehicle: { carId: "C0000000" }, vehicle: { carId: "C0000000" },
eventBusItem: jest.fn(), eventBusItem: jest.fn(),
damage: { damage: {
glassToReplace: [{ location: damageLocation, name: damageName }], glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
isRepair: isRepair, isRepair: isRepair,
numberOfChips: 2, numberOfChips: 2,
}, },
@ -637,7 +637,9 @@ describe("vehicle-damage.vue", () => {
store.getters = { store.getters = {
vehicle: { carId: "C0000000" }, vehicle: { carId: "C0000000" },
eventBusItem: jest.fn(), eventBusItem: jest.fn(),
damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, damage: {
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
},
isRepair: true, isRepair: true,
}; };
@ -671,7 +673,9 @@ describe("vehicle-damage.vue", () => {
store.getters = { store.getters = {
vehicle: { carId: "C0000000" }, vehicle: { carId: "C0000000" },
eventBusItem: jest.fn(), eventBusItem: jest.fn(),
damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, damage: {
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
},
isRepair: true, isRepair: true,
}; };
@ -703,7 +707,9 @@ describe("vehicle-damage.vue", () => {
store.getters = { store.getters = {
vehicle: { carId: "C0000000" }, vehicle: { carId: "C0000000" },
eventBusItem: jest.fn(), eventBusItem: jest.fn(),
damage: { glassToReplace: [{ location: damageLocation, name: damageName }] }, damage: {
glassToReplace: [{ glassLocation: damageLocation, glassName: damageName }],
},
isRepair: true, isRepair: true,
}; };

View file

@ -169,7 +169,7 @@ export default {
if ( if (
store.getters.damage.glassToReplace?.some((glass) => { store.getters.damage.glassToReplace?.some((glass) => {
return glass.location === damageLocationsSelected.WINDSHIELD; return glass.glassLocation === damageLocationsSelected.WINDSHIELD;
}) || }) ||
store.getters.damage.isRepair store.getters.damage.isRepair
) { ) {
@ -178,8 +178,8 @@ export default {
if ( if (
store.getters.damage.glassToReplace?.some((glass) => { store.getters.damage.glassToReplace?.some((glass) => {
return ( return (
glass.location === damageLocationsSelected.DRIVER || glass.glassLocation === damageLocationsSelected.DRIVER ||
glass.location === damageLocationsSelected.PASSENGER glass.glassLocation === damageLocationsSelected.PASSENGER
); );
}) })
) { ) {
@ -188,7 +188,7 @@ export default {
if ( if (
store.getters.damage.glassToReplace?.some((glass) => { store.getters.damage.glassToReplace?.some((glass) => {
return glass.location === damageLocationsSelected.REAR; return glass.glassLocation === damageLocationsSelected.REAR;
}) })
) { ) {
glassSelections.push(damageLocationsSelected.REARWINDOW); glassSelections.push(damageLocationsSelected.REARWINDOW);
@ -213,8 +213,8 @@ export default {
if ( if (
store.getters.damage.glassToReplace?.some((glass) => { store.getters.damage.glassToReplace?.some((glass) => {
return ( return (
glass.location === damageLocationsSelected.WINDSHIELD && glass.glassLocation === damageLocationsSelected.WINDSHIELD &&
glass.name === damageLocationsSelected.SINGLE glass.glassName === damageLocationsSelected.SINGLE
); );
}) })
) { ) {
@ -228,8 +228,8 @@ export default {
if ( if (
store.getters.damage.glassToReplace?.some((glass) => { store.getters.damage.glassToReplace?.some((glass) => {
return ( return (
glass.location === damageLocationsSelected.WINDSHIELD && glass.glassLocation === damageLocationsSelected.WINDSHIELD &&
glass.name === damageLocationsSelected.DRIVER glass.glassName === damageLocationsSelected.DRIVER
); );
}) })
) { ) {
@ -243,8 +243,8 @@ export default {
if ( if (
store.getters.damage.glassToReplace?.some((glass) => { store.getters.damage.glassToReplace?.some((glass) => {
return ( return (
glass.location === damageLocationsSelected.WINDSHIELD && glass.glassLocation === damageLocationsSelected.WINDSHIELD &&
glass.name === damageLocationsSelected.PASSENGER glass.glassName === damageLocationsSelected.PASSENGER
); );
}) })
) { ) {
@ -263,7 +263,7 @@ export default {
var doorSides = []; var doorSides = [];
if ( if (
store.getters.damage.glassToReplace?.some((glass) => { store.getters.damage.glassToReplace?.some((glass) => {
return glass.location === damageLocationsSelected.DRIVER; return glass.glassLocation === damageLocationsSelected.DRIVER;
}) })
) { ) {
doorSides.push(damageLocationsSelected.DRIVERSIDE); doorSides.push(damageLocationsSelected.DRIVERSIDE);
@ -271,7 +271,7 @@ export default {
if ( if (
store.getters.damage.glassToReplace?.some((glass) => { store.getters.damage.glassToReplace?.some((glass) => {
return glass.location === damageLocationsSelected.PASSENGER; return glass.glassLocation === damageLocationsSelected.PASSENGER;
}) })
) { ) {
doorSides.push(damageLocationsSelected.PASSENGERSIDE); doorSides.push(damageLocationsSelected.PASSENGERSIDE);
@ -284,8 +284,8 @@ export default {
var driverSideReplaceOptions = []; var driverSideReplaceOptions = [];
store.getters.damage.glassToReplace?.forEach((glass) => { store.getters.damage.glassToReplace?.forEach((glass) => {
if (glass.location === damageLocationsSelected.DRIVER) { if (glass.glassLocation === damageLocationsSelected.DRIVER) {
driverSideReplaceOptions.push(glass.name); driverSideReplaceOptions.push(glass.glassName);
} }
}); });
@ -296,8 +296,8 @@ export default {
var passengerSideReplaceOptions = []; var passengerSideReplaceOptions = [];
store.getters.damage.glassToReplace?.forEach((glass) => { store.getters.damage.glassToReplace?.forEach((glass) => {
if (glass.location === damageLocationsSelected.PASSENGER) { if (glass.glassLocation === damageLocationsSelected.PASSENGER) {
passengerSideReplaceOptions.push(glass.name); passengerSideReplaceOptions.push(glass.glassName);
} }
}); });
@ -306,8 +306,8 @@ export default {
getRearReplaceOptionsFromStore() { getRearReplaceOptionsFromStore() {
var rearReplaceOptions = store.getters.damage.glassToReplace?.filter( var rearReplaceOptions = store.getters.damage.glassToReplace?.filter(
(glass) => glass.location === damageLocationsSelected.REAR (glass) => glass.glassLocation === damageLocationsSelected.REAR
)[0]?.name; )[0]?.glassName;
return rearReplaceOptions; return rearReplaceOptions;
}, },
@ -348,8 +348,8 @@ export default {
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach( this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(
(wsItem) => { (wsItem) => {
selectedGlassToReplace.push({ selectedGlassToReplace.push({
location: damageLocationsSelected.WINDSHIELD, glassLocation: damageLocationsSelected.WINDSHIELD,
name: wsItem, glassName: wsItem,
}); });
} }
); );
@ -358,8 +358,8 @@ export default {
if (this.isDriverSideReplace) { if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => { this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => {
selectedGlassToReplace.push({ selectedGlassToReplace.push({
location: damageLocationsSelected.DRIVER, glassLocation: damageLocationsSelected.DRIVER,
name: driverItem, glassName: driverItem,
}); });
}); });
} }
@ -368,8 +368,8 @@ export default {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach( this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(
(passengerItem) => { (passengerItem) => {
selectedGlassToReplace.push({ selectedGlassToReplace.push({
location: damageLocationsSelected.PASSENGER, glassLocation: damageLocationsSelected.PASSENGER,
name: passengerItem, glassName: passengerItem,
}); });
} }
); );
@ -377,8 +377,8 @@ export default {
if (this.isRearWindowDamageLocation) { if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({ selectedGlassToReplace.push({
location: damageLocationsSelected.REAR, glassLocation: damageLocationsSelected.REAR,
name: this.selectedRearReplaceOptions, glassName: this.selectedRearReplaceOptions,
}); });
} }

View file

@ -29,8 +29,8 @@ const featureListData = {
], ],
}, },
], ],
locationProp: "Rear", glassLocationProp: "Rear",
nameProp: "Stationary", glassNameProp: "Stationary",
modelValueProp: {}, modelValueProp: {},
}; };
@ -54,7 +54,7 @@ describe("glass-part-question.vue", () => {
expect(wrapper.vm.featureListData["Gray Tint Privacy"][0].Name).toBe("DB12209YPYN"); expect(wrapper.vm.featureListData["Gray Tint Privacy"][0].Name).toBe("DB12209YPYN");
}); });
test("Tint mapper, should get tint image by location and tintColor", async () => { test("Tint mapper, should get tint image by glassLocation and tintColor", async () => {
//Arrange //Arrange
const { wrapper } = setupMocks(featureListData); const { wrapper } = setupMocks(featureListData);
@ -87,8 +87,8 @@ describe("glass-part-question.vue", () => {
store.getters.pageData.mockReturnValueOnce({ store.getters.pageData.mockReturnValueOnce({
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [{ partNumber: "DB12209GTYN", color: "Green Tint" }], parts: [{ partNumber: "DB12209GTYN", color: "Green Tint" }],
}, },
], ],
@ -135,8 +135,8 @@ describe("glass-part-question.vue", () => {
store.getters.pageData.mockReturnValueOnce({ store.getters.pageData.mockReturnValueOnce({
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [{ partNumber: "DB12209GTYN", color: "Green Tint" }], parts: [{ partNumber: "DB12209GTYN", color: "Green Tint" }],
}, },
], ],
@ -161,8 +161,8 @@ describe("glass-part-question.vue", () => {
store.getters.pageData.mockReturnValueOnce({ store.getters.pageData.mockReturnValueOnce({
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ partNumber: "DB12209GTYN", color: "Green Tint" }, { partNumber: "DB12209GTYN", color: "Green Tint" },
{ partNumber: "DB12209GTYNXXX", color: "Green Tint" }, { partNumber: "DB12209GTYNXXX", color: "Green Tint" },
@ -218,14 +218,14 @@ describe("glass-part-question.vue", () => {
]; ];
test.each(partsForSelectedTintTestCases)( test.each(partsForSelectedTintTestCases)(
"partsForSelectedTint returns correct parts", "partsForSelectedTint returns correct parts",
async (location, name, selectedTint, expectedResults) => { async (glassLocation, glassName, selectedTint, expectedResults) => {
// Arrange // Arrange
store.getters.pageData.mockReset(); store.getters.pageData.mockReset();
store.getters.pageData.mockReturnValueOnce({ store.getters.pageData.mockReturnValueOnce({
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ partNumber: "Glass1", color: "Green Tint" }, { partNumber: "Glass1", color: "Green Tint" },
{ partNumber: "Glass2", color: "Blue Tint" }, { partNumber: "Glass2", color: "Blue Tint" },
@ -237,8 +237,8 @@ describe("glass-part-question.vue", () => {
], ],
}, },
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: [ parts: [
{ partNumber: "Windshield1", color: "Green Tint" }, { partNumber: "Windshield1", color: "Green Tint" },
{ partNumber: "Windshield2", color: "Green Tint" }, { partNumber: "Windshield2", color: "Green Tint" },
@ -247,8 +247,8 @@ describe("glass-part-question.vue", () => {
], ],
}); });
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
locationProp: location, glassLocationProp: glassLocation,
nameProp: name, glassNameProp: glassName,
colorAnswersProp: [], colorAnswersProp: [],
}); });
@ -261,10 +261,10 @@ describe("glass-part-question.vue", () => {
); );
}); });
function setupMocks({ nameProp, locationProp, colorAnswersProp, modelValueProp }) { function setupMocks({ glassNameProp, glassLocationProp, colorAnswersProp, modelValueProp }) {
//Mock store //Mock store
store.getters.pageData.mockReturnValueOnce({ store.getters.pageData.mockReturnValueOnce({
partsOrQuestions: [{ name: "Stationary", location: "Rear", parts: [] }], partsOrQuestions: [{ glassName: "Stationary", glassLocation: "Rear", parts: [] }],
}); });
store.getters.lineItems = { glassParts: {} }; store.getters.lineItems = { glassParts: {} };
@ -280,8 +280,8 @@ function setupMocks({ nameProp, locationProp, colorAnswersProp, modelValueProp }
}); });
mountOptions.propsData = { mountOptions.propsData = {
name: nameProp, glassName: glassNameProp,
location: locationProp, glassLocation: glassLocationProp,
colorAnswers: colorAnswersProp, colorAnswers: colorAnswersProp,
modelValue: modelValueProp, modelValue: modelValueProp,
}; };

View file

@ -12,7 +12,7 @@
:isWide="true" :isWide="true"
altText="" altText=""
isRequired isRequired
:groupName="`${location}-${name}`" :groupName="`${glassLocation}-${glassName}`"
:validationRules="tintValidationRules"> :validationRules="tintValidationRules">
<div class="row my-2" aria-live="polite"> <div class="row my-2" aria-live="polite">
<div class="col"> <div class="col">
@ -25,7 +25,7 @@
textPosition="text-start" textPosition="text-start"
:loaderEnabled="false" :loaderEnabled="false"
isRequired isRequired
:groupName="`${location}-${name}-${selectedTint}`" :groupName="`${glassLocation}-${glassName}-${selectedTint}`"
:validationRules="partValidationRules" /> :validationRules="partValidationRules" />
</div> </div>
</div> </div>
@ -57,8 +57,8 @@ export default {
}; };
}, },
props: { props: {
name: String, glassName: String,
location: String, glassLocation: String,
colorAnswers: Array, colorAnswers: Array,
modelValue: Object, modelValue: Object,
alreadyPopulatedPartsData: { alreadyPopulatedPartsData: {
@ -74,14 +74,14 @@ export default {
}, },
computed: { computed: {
tintValidationRules() { tintValidationRules() {
const validationRuleName = `${this.location}-${this.name}-tint-required`; const validationRuleName = `${this.glassLocation}-${this.glassName}-tint-required`;
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED)); defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
return validationRuleName; return validationRuleName;
}, },
partValidationRules() { partValidationRules() {
const validationRuleName = `${this.location}-${this.name}-part-required`; const validationRuleName = `${this.glassLocation}-${this.glassName}-part-required`;
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED)); defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
return validationRuleName; return validationRuleName;
@ -89,7 +89,7 @@ export default {
colorQuestionText() { colorQuestionText() {
return getCustomTransformValue( return getCustomTransformValue(
this.glassColorQuestion, this.glassColorQuestion,
`${this.location} ${this.name}` `${this.glassLocation} ${this.glassName}`
); );
}, },
@ -101,7 +101,7 @@ export default {
value: tintOption, value: tintOption,
buttonLabel: tintOption, buttonLabel: tintOption,
buttonImage: require(`@/assets/img/tints/${this.getTintSourceImage( buttonImage: require(`@/assets/img/tints/${this.getTintSourceImage(
this.location, this.glassLocation,
tintOption tintOption
)}`), )}`),
}); });
@ -125,8 +125,8 @@ export default {
partsForSelectedTint() { partsForSelectedTint() {
const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter( const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter(
(dataForGlassLocationAndName) => (dataForGlassLocationAndName) =>
dataForGlassLocationAndName.name == this.name && dataForGlassLocationAndName.glassName == this.glassName &&
dataForGlassLocationAndName.location == this.location dataForGlassLocationAndName.glassLocation == this.glassLocation
); );
const matchingGlassParts = matchingGlass?.length == 1 ? matchingGlass[0].parts : []; const matchingGlassParts = matchingGlass?.length == 1 ? matchingGlass[0].parts : [];
return matchingGlassParts.filter((part) => part.color == this.selectedTint) ?? []; return matchingGlassParts.filter((part) => part.color == this.selectedTint) ?? [];
@ -170,8 +170,8 @@ export default {
// Gets tint images based on the glass type, and tint name. // Gets tint images based on the glass type, and tint name.
// Returns an empty string if the src or object is undefined. // Returns an empty string if the src or object is undefined.
getTintSourceImage(location, tintColor) { getTintSourceImage(glassLocation, tintColor) {
const tintSourceObject = getTintImage(location, tintColor); const tintSourceObject = getTintImage(glassLocation, tintColor);
if (tintSourceObject === undefined || tintSourceObject.src == undefined) { if (tintSourceObject === undefined || tintSourceObject.src == undefined) {
return ""; return "";

View file

@ -47,8 +47,8 @@ store.getters = {
const basePartResponse = { const basePartResponse = {
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "DB12209GTYN", partNumber: "DB12209GTYN",
@ -217,8 +217,8 @@ describe("vehicle-parts.vue", () => {
return { return {
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: null, parts: null,
partQuestions: [ partQuestions: [
{ {
@ -302,8 +302,8 @@ describe("vehicle-parts.vue", () => {
store.getters.pageData.mockReturnValueOnce({ store.getters.pageData.mockReturnValueOnce({
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: [ parts: [
{ {
partNumber: "FW03861GTYN", partNumber: "FW03861GTYN",
@ -383,8 +383,8 @@ describe("vehicle-parts.vue", () => {
store.getters.pageData.mockReturnValueOnce({ store.getters.pageData.mockReturnValueOnce({
partsOrQuestions: [ partsOrQuestions: [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: [ parts: [
{ {
partNumber: "DB12209GTYN", partNumber: "DB12209GTYN",

View file

@ -24,10 +24,10 @@
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) --> <!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
<hr v-if="i > 0" /> <hr v-if="i > 0" />
<glassPartQuestion <glassPartQuestion
:ref="`${RefPrefix}-${item.location}-${item.name}`" :ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
v-model="selectedGlassParts[item.location + '-' + item.name]" v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]"
:location="item.location" :glassLocation="item.glassLocation"
:name="item.name" :glassName="item.glassName"
:colorAnswers="item.colorAnswers" :colorAnswers="item.colorAnswers"
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" /> :alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
</div> </div>
@ -117,8 +117,8 @@ export default {
// Map API result data, to vehicle-parts data structure // Map API result data, to vehicle-parts data structure
const mappedData = partsData.partsOrQuestions.map((g) => { const mappedData = partsData.partsOrQuestions.map((g) => {
return { return {
name: g.name, glassName: g.glassName,
location: g.location, glassLocation: g.glassLocation,
colorAnswers: g.parts?.reduce((arr, p) => { colorAnswers: g.parts?.reduce((arr, p) => {
arr.push({ arr.push({
ColorAnswerText: p.color, ColorAnswerText: p.color,
@ -169,8 +169,8 @@ export default {
if (isMatched) { if (isMatched) {
matchedParts.push({ matchedParts.push({
location: value.location, glassLocation: value.glassLocation,
name: value.name, glassName: value.glassName,
parts: [currentPart], parts: [currentPart],
}); });
} }
@ -205,7 +205,7 @@ export default {
const partNumber = this.alreadyPopulatedPartsData[key].partNumber; const partNumber = this.alreadyPopulatedPartsData[key].partNumber;
g.parts.forEach((p) => { g.parts.forEach((p) => {
if (p.partNumber === partNumber) { if (p.partNumber === partNumber) {
this.selectedGlassParts[g.location + "-" + g.name] = p; this.selectedGlassParts[g.glassLocation + "-" + g.glassName] = p;
} }
}); });
}); });

View file

@ -220,6 +220,28 @@ describe("vin-lookup.vue", () => {
expect(wrapper.vm.displayInvalidZipAlert).toEqual(true); expect(wrapper.vm.displayInvalidZipAlert).toEqual(true);
expect(wrapper.findComponent({ ref: "alertInvalidZip" }).exists()).toBe(true); expect(wrapper.findComponent({ ref: "alertInvalidZip" }).exists()).toBe(true);
}); });
test("alerts are displayed and continue button is clicked with issues fixed => alerts are reset", async () => {
// Arrange
const { wrapper } = setupMocks({});
mockOutPromises({ isZipValid: true, isZipServiceable: true, carId: "CARID" });
await wrapper.setData({
displayInvalidZipAlert: true,
displayMatchedDifferentVehicleAlert: true,
displayNonServiceableZipAlert: true,
displayVinNotFoundAlert: true,
});
// sanity check that there are alerts
expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(4);
// Act
wrapper.vm.forwardButtonAction();
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(0);
});
}); });
}); });
@ -244,8 +266,8 @@ function mockOutPromises({ carId, isZipValid = true, isZipServiceable = true })
carId: carId, carId: carId,
}, },
zipCodeData: { zipCodeData: {
isValid: true, isValid: isZipValid,
isServiceable: true, isServiceable: isZipServiceable,
state: "OH", state: "OH",
}, },
}; };

View file

@ -226,6 +226,8 @@ export default {
} }
}, },
async forwardButtonAction() { async forwardButtonAction() {
this.resetAlerts();
// If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation // If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation
if (!this.vinPopulatedOnPageLoad) { if (!this.vinPopulatedOnPageLoad) {
const vehicleLookupResponse = this.dispatchStoreAction( const vehicleLookupResponse = this.dispatchStoreAction(
@ -372,6 +374,12 @@ export default {
await this.navigateForwardWithSingleCarMatch(); await this.navigateForwardWithSingleCarMatch();
} }
}, },
resetAlerts() {
this.displayMatchedDifferentVehicleAlert = false;
this.displayNonServiceableZipAlert = false;
this.displayInvalidZipAlert = false;
this.displayVinNotFoundAlert = false;
},
}, },
mounted() { mounted() {
this.attachCustomEvents(); this.attachCustomEvents();

View file

@ -68,7 +68,7 @@ export default {
return this.comparePageIndices(currentPage, fmgPage) > 0; return this.comparePageIndices(currentPage, fmgPage) > 0;
}, },
setupInitialData(glass, i, alreadyAnsweredQuestions, vm) { setupInitialData(glass, i, alreadyAnsweredQuestions, vm) {
glass.key = glass.location + "-" + glass.name; glass.key = glass.glassLocation + "-" + glass.glassName;
const self = vm ?? this; const self = vm ?? this;
// clear answerData if no questions are already answered // clear answerData if no questions are already answered
if (!alreadyAnsweredQuestions) { if (!alreadyAnsweredQuestions) {
@ -78,8 +78,8 @@ export default {
alreadyAnsweredQuestions?.forEach((answeredGlass) => { alreadyAnsweredQuestions?.forEach((answeredGlass) => {
// if answeredGlass lacks any of these properties then exit // if answeredGlass lacks any of these properties then exit
if ( if (
!answeredGlass.location || !answeredGlass.glassLocation ||
!answeredGlass.name || !answeredGlass.glassName ||
!answeredGlass.answeredQuestions || !answeredGlass.answeredQuestions ||
(!answeredGlass.result && !answeredGlass.partNum) (!answeredGlass.result && !answeredGlass.partNum)
) { ) {
@ -88,8 +88,8 @@ export default {
// test if glass parts match // test if glass parts match
if ( if (
glass.location === answeredGlass.location && glass.glassLocation === answeredGlass.glassLocation &&
glass.name === answeredGlass.name glass.glassName === answeredGlass.glassName
) { ) {
let answerString = ""; let answerString = "";
@ -138,7 +138,7 @@ export default {
// Set up watch for each set of glass questions // Set up watch for each set of glass questions
// (updated when all questions for a glass have been answered in question-chain) // (updated when all questions for a glass have been answered in question-chain)
self.$watch( self.$watch(
"selectedAnswers." + glass.location + "-" + glass.name, "selectedAnswers." + glass.glassLocation + "-" + glass.glassName,
(newValue) => { (newValue) => {
if (newValue) { if (newValue) {
self.handleAnswerUpdates(newValue); self.handleAnswerUpdates(newValue);

View file

@ -73,8 +73,8 @@ describe("vehicle-questions-mixin", () => {
// Act // Act
const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([
{ {
name: "Something", glassName: "Something",
location: "somewhere", glassLocation: "somewhere",
parts: [ parts: [
{ {
partNumber: "1234567", partNumber: "1234567",
@ -94,8 +94,8 @@ describe("vehicle-questions-mixin", () => {
// Act // Act
const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([
{ {
name: "Something", glassName: "Something",
location: "somewhere", glassLocation: "somewhere",
parts: [ parts: [
{ {
partNumber: "1234567", partNumber: "1234567",
@ -103,8 +103,8 @@ describe("vehicle-questions-mixin", () => {
], ],
}, },
{ {
name: "Another glass", glassName: "Another glass",
location: "somewhere else", glassLocation: "somewhere else",
parts: [ parts: [
{ {
partNumber: "1234568", partNumber: "1234568",
@ -112,8 +112,8 @@ describe("vehicle-questions-mixin", () => {
], ],
}, },
{ {
name: "Special glass", glassName: "Special glass",
location: "Another where", glassLocation: "Another where",
parts: [ parts: [
{ {
partNumber: "1234569", partNumber: "1234569",
@ -133,8 +133,8 @@ describe("vehicle-questions-mixin", () => {
// Act // Act
const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([ const hasGlassLocationWithMultipleParts = wrapper.vm.hasGlassLocationWithMultipleParts([
{ {
name: "Something", glassName: "Something",
location: "somewhere", glassLocation: "somewhere",
parts: [ parts: [
{ {
partNumber: "1234567", partNumber: "1234567",
@ -142,8 +142,8 @@ describe("vehicle-questions-mixin", () => {
], ],
}, },
{ {
name: "Another glass", glassName: "Another glass",
location: "somewhere else", glassLocation: "somewhere else",
parts: [ parts: [
{ {
partNumber: "1234568", partNumber: "1234568",
@ -151,8 +151,8 @@ describe("vehicle-questions-mixin", () => {
], ],
}, },
{ {
name: "Special glass", glassName: "Special glass",
location: "Another where", glassLocation: "Another where",
parts: [ parts: [
{ {
partNumber: "1234569", partNumber: "1234569",
@ -342,8 +342,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
const glass = { const glass = {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
}; };
const i = 0; const i = 0;
@ -359,8 +359,8 @@ describe("vehicle-questions-mixin", () => {
test("should return glass with answerData of null", async () => { test("should return glass with answerData of null", async () => {
// Arrange // Arrange
const glass = { const glass = {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
}; };
const i = 0; const i = 0;
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
@ -377,8 +377,8 @@ describe("vehicle-questions-mixin", () => {
test("should return glass with answerResult within answerData", async () => { test("should return glass with answerResult within answerData", async () => {
// Arrange // Arrange
const glass = { const glass = {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
questions: [ questions: [
{ {
questionSequence: 1, questionSequence: 1,
@ -402,8 +402,8 @@ describe("vehicle-questions-mixin", () => {
const i = 0; const i = 0;
const alreadyAnsweredQuestions = [ const alreadyAnsweredQuestions = [
{ {
location: "Windshield", glassLocation: "Windshield",
name: "Single", glassName: "Single",
partNum: "WKT D1106 C", partNum: "WKT D1106 C",
answeredQuestions: [ answeredQuestions: [
{ {
@ -436,8 +436,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: null, parts: null,
partQuestions: [ partQuestions: [
{ {
@ -483,8 +483,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: null, parts: null,
partQuestions: [ partQuestions: [
{ {
@ -507,8 +507,8 @@ describe("vehicle-questions-mixin", () => {
], ],
}, },
{ {
name: "Front", glassName: "Front",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DD08158GTYN", partNumber: "DD08158GTYN",
@ -522,8 +522,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Quarter", glassName: "Quarter",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DQ08162GTYN", partNumber: "DQ08162GTYN",
@ -537,8 +537,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "SideDoor", glassName: "SideDoor",
location: "Driver", glassLocation: "Driver",
parts: null, parts: null,
partQuestions: [ partQuestions: [
{ {
@ -560,8 +560,8 @@ describe("vehicle-questions-mixin", () => {
], ],
}, },
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "DB08165GTNN", partNumber: "DB08165GTNN",
@ -598,8 +598,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: null, parts: null,
partQuestions: [ partQuestions: [
{ {
@ -622,8 +622,8 @@ describe("vehicle-questions-mixin", () => {
], ],
}, },
{ {
name: "Front", glassName: "Front",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DD08158GTYN", partNumber: "DD08158GTYN",
@ -637,8 +637,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Quarter", glassName: "Quarter",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DQ08162GTYN", partNumber: "DQ08162GTYN",
@ -652,8 +652,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "SideDoor", glassName: "SideDoor",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DD08160GTYN", partNumber: "DD08160GTYN",
@ -667,8 +667,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "DB08165GTNN", partNumber: "DB08165GTNN",
@ -705,8 +705,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: null, parts: null,
partQuestions: [ partQuestions: [
{ {
@ -729,8 +729,8 @@ describe("vehicle-questions-mixin", () => {
], ],
}, },
{ {
name: "Front", glassName: "Front",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DD08158GTYN", partNumber: "DD08158GTYN",
@ -744,8 +744,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Quarter", glassName: "Quarter",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DQ08162GTYN", partNumber: "DQ08162GTYN",
@ -767,8 +767,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "SideDoor", glassName: "SideDoor",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DD08160GTYN", partNumber: "DD08160GTYN",
@ -790,8 +790,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "DB08165GTNN", partNumber: "DB08165GTNN",
@ -862,8 +862,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "FB25724GTYN", partNumber: "FB25724GTYN",
@ -908,8 +908,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: [ parts: [
{ {
partNumber: "FW03647GTNN", partNumber: "FW03647GTNN",
@ -929,8 +929,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Back", glassName: "Back",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "FD25747GTYN", partNumber: "FD25747GTYN",
@ -944,8 +944,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Front", glassName: "Front",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "FD25719GTYN", partNumber: "FD25719GTYN",
@ -959,8 +959,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Vent", glassName: "Vent",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "FV25749GTNN", partNumber: "FV25749GTNN",
@ -974,8 +974,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "FB25724GTYN", partNumber: "FB25724GTYN",
@ -1020,8 +1020,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: [ parts: [
{ {
partNumber: "DW02101GTYN", partNumber: "DW02101GTYN",
@ -1035,8 +1035,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Back", glassName: "Back",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DD12202GTYN", partNumber: "DD12202GTYN",
@ -1058,8 +1058,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Front", glassName: "Front",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DD12198GTYN", partNumber: "DD12198GTYN",
@ -1081,8 +1081,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Quarter", glassName: "Quarter",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "DQ12204GTYNOEM", partNumber: "DQ12204GTYNOEM",
@ -1152,8 +1152,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "DB12209GTYN", partNumber: "DB12209GTYN",
@ -1200,8 +1200,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "FB25724GTYN", partNumber: "FB25724GTYN",
@ -1259,8 +1259,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: [ parts: [
{ {
partNumber: "FB25724GTYN", partNumber: "FB25724GTYN",
@ -1301,8 +1301,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: [ parts: [
{ {
partNumber: "FW04186GTYN", partNumber: "FW04186GTYN",
@ -1338,8 +1338,8 @@ describe("vehicle-questions-mixin", () => {
// Arrange // Arrange
const partsOrQuestions = [ const partsOrQuestions = [
{ {
name: "Single", glassName: "Single",
location: "Windshield", glassLocation: "Windshield",
parts: [ parts: [
{ {
partNumber: "FW04186GTYN", partNumber: "FW04186GTYN",
@ -1359,8 +1359,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Back", glassName: "Back",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "FD25457GTYN", partNumber: "FD25457GTYN",
@ -1374,8 +1374,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Front", glassName: "Front",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "FD27090GTYN", partNumber: "FD27090GTYN",
@ -1389,8 +1389,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Vent", glassName: "Vent",
location: "Driver", glassLocation: "Driver",
parts: [ parts: [
{ {
partNumber: "FV25459GTNN", partNumber: "FV25459GTNN",
@ -1404,8 +1404,8 @@ describe("vehicle-questions-mixin", () => {
partQuestions: null, partQuestions: null,
}, },
{ {
name: "Stationary", glassName: "Stationary",
location: "Rear", glassLocation: "Rear",
parts: [ parts: [
{ {
partNumber: "FB25460GTYN", partNumber: "FB25460GTYN",

View file

@ -33,11 +33,6 @@ import quote from "@/layouts/quote/quote.vue";
import datePicker from "@/common-components/date-picker/date-picker.vue"; import datePicker from "@/common-components/date-picker/date-picker.vue";
const routes = [ const routes = [
{
path: "/quote", // This is a temporary route for testing.
name: "quote",
component: quote,
},
{ {
path: "/date-picker", // This is a temporary route for testing. path: "/date-picker", // This is a temporary route for testing.
name: "date-picker", name: "date-picker",

View file

@ -405,6 +405,49 @@ export const getters = {
applicationUser: (state) => state.applicationUser, applicationUser: (state) => state.applicationUser,
order: (state) => state.order, order: (state) => state.order,
payment: (state) => state.order.payment, payment: (state) => state.order.payment,
experimentOrder: (state) => {
return {
funnelVehicleYear: state.order.vehicle.year,
funnelVehicleMake: state.order.vehicle.make,
funnelVehicleModel: state.order.vehicle.model,
funnelVehicleStyle: state.order.vehicle.style,
funnelIsRepair: state.order.damage.isRepair,
funnelNumberOfChips: state.order.damage.numberOfChips,
funnelCarId: state.order.vehicle.carId,
funnelServiceCity: state.order.serviceLocation.city,
funnelServiceState: state.order.serviceLocation.state,
funnelServiceZipCode: state.order.serviceLocation.zipCode,
funnelParentAccountNumber: state.order.accountNumber,
funnelIsCoverageVerified: state.order.payment.insuranceCoverage.isVerified,
funnelHasRecalibrationPart: getHasRecalibrationPart(state),
funnelSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1,
funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.WINDSHIELD),
funnelSelectedBackGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.REAR),
funnelSelectedDriverSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.DRIVER),
funnelSelectedPassengerSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(
state.order.damage.glassToReplace,
"glassLocation"
).includes(damageLocationsSelected.PASSENGER),
return matchedEvent !== undefined ? matchedEvent.eventValue : undefined;
},
eventBus: (state) => state.applicationUser.eventBus,
damage: (state) => state.order.damage,
lineItems: (state) => state.order.lineItems,
pageData: (state) => (page) => {
return state.applicationUser.pageData[page];
},
applicationUser: (state) => state.applicationUser,
order: (state) => state.order,
payment: (state) => state.order.payment,
experimentOrder: (state) => { experimentOrder: (state) => {
return { return {
funnelVehicleYear: state.order.vehicle.year, funnelVehicleYear: state.order.vehicle.year,
@ -822,24 +865,24 @@ export const actions = {
const zipCode = order.serviceLocation.zipCode; const zipCode = order.serviceLocation.zipCode;
const vin = vehicle.vin; const vin = vehicle.vin;
// create a new array to avoid mutating state
const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray);
const response = await globalMethods.callHttpClient({ const response = await globalMethods.callHttpClient({
method: endpoints.GetPartsOrQuestions.method, method: endpoints.GetPartsOrQuestions.method,
endpoint: endpoints.GetPartsOrQuestions.url, endpoint: endpoints.GetPartsOrQuestions.url,
payload: { payload: {
carId: carId, carId: carId,
glassPieces: glassArray ?? [], glassPieces: glassArrayForPayload,
zip: zipCode, zip: zipCode,
vin: vin, vin: vin,
}, },
}); });
// Flatten location and name properties // Flatten location and name properties
response.data.partsOrQuestions.map((glass) => { response.data.partsOrQuestions = convertGlassPieceNamingFromApi(
glass.location = glass.glassPiece.location; response.data.partsOrQuestions
glass.name = glass.glassPiece.name; );
delete glass.glassPiece;
return glass;
});
return response; return response;
}, },
@ -856,25 +899,26 @@ export const actions = {
const zipCode = order.serviceLocation.zipCode; const zipCode = order.serviceLocation.zipCode;
const vin = vehicle.vin; const vin = vehicle.vin;
// Flatten location and name properties // create a new array to avoid mutating state
const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray);
const resultsArrayForPayload = convertResultsForApi(resultsArray);
const response = await globalMethods.callHttpClient({ const response = await globalMethods.callHttpClient({
method: endpoints.GetParts.method, method: endpoints.GetParts.method,
endpoint: endpoints.GetParts.url, endpoint: endpoints.GetParts.url,
payload: { payload: {
carId: carId, carId: carId,
glassPieces: glassArray, glassPieces: glassArrayForPayload,
answerResults: resultsArray, answerResults: resultsArrayForPayload,
zip: zipCode, zip: zipCode,
vin: vin, vin: vin,
}, },
}); });
response.data.glassPieceParts.map((glass) => { // Flatten location and name properties
glass.location = glass.glassPiece.location; response.data.glassPieceParts = convertGlassPieceNamingFromApi(
glass.name = glass.glassPiece.name; response.data.glassPieceParts
delete glass.glassPiece; );
return glass;
});
return response; return response;
}, },
@ -889,10 +933,11 @@ export const actions = {
getPartFromCapabilityQuestionAnswer(context, glassLocation) { getPartFromCapabilityQuestionAnswer(context, glassLocation) {
const pageData = context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS); const pageData = context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS);
const part = pageData.partsOrQuestions.find((x) => x.location === glassLocation).parts[0]; const part = pageData.partsOrQuestions.find((x) => x.glassLocation === glassLocation)
.parts[0];
const capabilityQuestionAnswers = context.getters.damage.capabilityQuestionAnswers; const capabilityQuestionAnswers = context.getters.damage.capabilityQuestionAnswers;
const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find( const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find(
(x) => x.location === glassLocation (x) => x.glassLocation === glassLocation
); );
return globalMethods.callHttpClient({ return globalMethods.callHttpClient({
@ -913,52 +958,72 @@ export const actions = {
const applicationUser = context.getters.applicationUser; const applicationUser = context.getters.applicationUser;
const lineItems = context.state.order.lineItems; const lineItems = context.state.order.lineItems;
// create a new array to avoid mutating state
const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace);
return globalMethods.callHttpClient({ return globalMethods.callHttpClient({
method: endpoints.SaveSession.method, method: endpoints.SaveSession.method,
endpoint: endpoints.SaveSession.url, endpoint: endpoints.SaveSession.url,
payload: { payload: {
vehicle: { applicationUser: {
carId: vehicle.carId, crmCustomerId: applicationUser.crmCustomerId,
year: vehicle.year, experiments: applicationUser.experiments,
make: vehicle.make, lastPage: applicationUser.lastPageVisited,
model: vehicle.model, pageData: applicationUser.pageData,
style: vehicle.style, savedSessionId: applicationUser.savedSessionId,
vin: vehicle.vin, },
registration: { order: {
firstName: vehicle.registration.firstName, vehicle: {
lastName: vehicle.registration.lastName, carId: vehicle.carId,
streetAddress: vehicle.registration.address, year: vehicle.year,
city: vehicle.registration.city, make: vehicle.make,
state: vehicle.registration.state, model: vehicle.model,
zipCode: vehicle.registration.zipCode, style: vehicle.style,
licensePlateNumber: vehicle.registration.licensePlate, vin: vehicle.vin,
registration: {
firstName: vehicle.registration.firstName,
lastName: vehicle.registration.lastName,
streetAddress: vehicle.registration.address,
city: vehicle.registration.city,
state: vehicle.registration.state,
zipCode: vehicle.registration.zipCode,
licensePlateNumber: vehicle.registration.licensePlate,
},
}, },
customer: {
emailAddress: order.customer.emailAddress,
},
damage: {
numberOfChips: damage.numberOfChips,
glassToReplace: newGlassToReplace,
isRepair: damage.isRepair,
partQuestionAnswers: order.damage.partQuestionAnswers,
moldingQuestionAnswers: order.damage.moldingQuestionAnswers,
capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers,
},
lineItems: {
glassParts: lineItems.glassParts,
},
payment: {
InsuranceCoverage: {
isVerified: order.payment.insuranceCoverage.isVerified ?? false,
},
isInsurance: order.payment.isInsurance ?? false,
},
accountNumber: order.accountNumber?.toString(),
providerNumber: "",
serviceLocation: {
streetAddress: order.serviceLocation.address,
city: order.serviceLocation.city,
state: order.serviceLocation.state,
zipCode: order.serviceLocation.zipCode,
},
existingPromoCode: null,
referralCorrelationId: order.referralCorrelationId,
referralDate: order.referralDate,
referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place
referralSequenceNumber: order.referralNumber?.toString(), // TODO Pass the referralSequence number once insurance flow creates it
}, },
damage: {
numberOfChips: damage.numberOfChips,
glassToReplace: damage.glassToReplace,
isRepair: damage.isRepair,
},
customer: {
emailAddress: order.customer.emailAddress,
},
lineItems: {
glassParts: lineItems.glassParts,
},
serviceLocation: {
streetAddress: order.serviceLocation.address,
city: order.serviceLocation.city,
state: order.serviceLocation.state,
zipCode: order.serviceLocation.zipCode,
},
referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place
referralDate: order.referralDate,
accountNumber: order.accountNumber?.toString(),
existingPromoCode: null,
lastPage: applicationUser.lastPageVisited,
crmCustomerId: applicationUser.crmCustomerId,
savedSessionId: applicationUser.savedSessionId,
experiments: applicationUser.experiments,
}, },
}); });
}, },
@ -975,6 +1040,15 @@ export const actions = {
}, },
}) })
.then((response) => { .then((response) => {
// Flatten location and name properties
response.data.damage?.glassToReplace?.map((glass) => {
glass.glassLocation = glass.location;
glass.glassName = glass.name;
delete glass.location;
delete glass.name;
return glass;
});
// clear the state if the existing EON does not equal what is returned from loadSession // clear the state if the existing EON does not equal what is returned from loadSession
if (context.state.order.eon && context.state.order.eon != response.data.eon) { if (context.state.order.eon && context.state.order.eon != response.data.eon) {
context.commit(storeMutations.RESET_STATE); context.commit(storeMutations.RESET_STATE);
@ -1375,3 +1449,38 @@ function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
else return 0; else return 0;
}); });
} }
function convertGlassPieceNamingForApi(glassArray) {
if (!glassArray) return [];
const converted = [];
glassArray.forEach((glass) => {
converted.push({
location: glass.glassLocation,
name: glass.glassName,
});
});
return converted;
}
function convertResultsForApi(resultsArray) {
if (!resultsArray) return [];
const converted = [];
resultsArray.forEach((answer) => {
converted.push({
location: answer.glassLocation,
name: answer.glassName,
result: answer.result,
});
});
return converted;
}
function convertGlassPieceNamingFromApi(glassArray) {
glassArray.forEach((glass) => {
glass.glassLocation = glass.glassPiece.location;
glass.glassName = glass.glassPiece.name;
delete glass.glassPiece;
return glass;
});
return glassArray;
}

View file

@ -580,6 +580,14 @@ describe("Actions", () => {
vehicle: { vehicle: {
registration: {}, registration: {},
}, },
order: {
damage: {
numberOfChips: "2",
partQuestionAnswers: {},
moldingQuestionAnswers: {},
capabilityQuestionAnswers: {},
},
},
damage: {}, damage: {},
applicationUser: { applicationUser: {
lastPageVisited: "test-page", lastPageVisited: "test-page",
@ -589,6 +597,18 @@ describe("Actions", () => {
}; };
context.state = { context.state = {
order: { order: {
damage: {
numberOfChips: "2",
partQuestionAnswers: {},
moldingQuestionAnswers: {},
capabilityQuestionAnswers: {},
},
payment: {
insuranceCoverage: {
isVerified: false,
},
isInsurance: false,
},
serviceLocation: {}, serviceLocation: {},
customer: {}, customer: {},
lineItems: {}, lineItems: {},

View file

@ -2,8 +2,18 @@ html {
.has-error { .has-error {
&.list-button, &.list-button,
&.list-card, &.list-card,
&.list-card.list-button { &.list-button-horizontal {
border: 1px solid $red;
.button-content {
border: none;
}
}
&.list-button,
&.list-card {
color: $red; color: $red;
input[type="checkbox"]:focus + label, input[type="checkbox"]:focus + label,
input[type="radio"]:focus + label { input[type="radio"]:focus + label {
box-shadow: 0 0 0 2.5px $red; box-shadow: 0 0 0 2.5px $red;
@ -38,6 +48,7 @@ html {
box-shadow: 0 0 1px $red; box-shadow: 0 0 1px $red;
} }
} }
&.grid-item { &.grid-item {
input[type="radio"] { input[type="radio"] {
+ label { + label {

View file

@ -6,7 +6,8 @@
{ strong: isStrongStyling }, { strong: isStrongStyling },
]" ]"
v-model="selectedValue"> v-model="selectedValue">
<div class="list-button-horizontal-content d-flex flex-column justify-content-center p-3"> <div
class="button-content list-button-horizontal-content d-flex flex-column justify-content-center p-3">
<span class="m-0" :class="textPosition"> <span class="m-0" :class="textPosition">
{{ buttonLabel }} {{ buttonLabel }}
</span> </span>
@ -165,9 +166,15 @@ export default {
} }
} }
.col { .col,
.list-group {
border-radius: 0;
&:first-of-type { &:first-of-type {
.list-button-horizontal { .list-button-horizontal {
border-bottom-left-radius: 0.5rem;
border-top-left-radius: 0.5rem;
.list-button-horizontal-content { .list-button-horizontal-content {
border-bottom-left-radius: 0.5rem; border-bottom-left-radius: 0.5rem;
border-top-left-radius: 0.5rem; border-top-left-radius: 0.5rem;
@ -177,6 +184,9 @@ export default {
&:last-of-type { &:last-of-type {
.list-button-horizontal { .list-button-horizontal {
border-bottom-right-radius: 0.5rem;
border-top-right-radius: 0.5rem;
.list-button-horizontal-content { .list-button-horizontal-content {
border-bottom-right-radius: 0.5rem; border-bottom-right-radius: 0.5rem;
border-top-right-radius: 0.5rem; border-top-right-radius: 0.5rem;

View file

@ -5,7 +5,7 @@
v-model="selectedValue"> v-model="selectedValue">
<div <div
:aria-label="buttonLabel" :aria-label="buttonLabel"
class="list-button-content d-flex flex-column justify-content-center py-3 px-4"> class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4">
<span class="m-0" :class="textPosition"> <span class="m-0" :class="textPosition">
{{ buttonLabel }} {{ buttonLabel }}
</span> </span>
@ -31,7 +31,6 @@ export default {
name: "listButton", name: "listButton",
mixins: [inputButtonWrapperMixin], mixins: [inputButtonWrapperMixin],
props: { props: {
selectingInitiatesLoad: Boolean,
loaderColor: String, loaderColor: String,
loaderPosition: { loaderPosition: {
type: String, type: String,

View file

@ -7,7 +7,7 @@
]" ]"
v-model="selectedValue"> v-model="selectedValue">
<div <div
class="d-flex w-100 align-items-center px-2 h-100 list-card-content" class="d-flex w-100 align-items-center px-2 h-100 list-card-content button-content rounded-3"
:class="labelClasses"> :class="labelClasses">
<img <img
:id="buttonImageId" :id="buttonImageId"
@ -57,12 +57,27 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
@mixin list-card-focus($box-shadow-color) {
&:focus-visible + .list-card-content {
box-shadow: 0 0 0 2.5px $box-shadow-color;
border-radius: 0.5rem;
}
&:focus + .list-card-content {
box-shadow: 0 0 0 2.5px $box-shadow-color;
border-radius: 0.5rem;
}
&:checked:focus + .list-card-content {
box-shadow: 0 0 0 2.5px $box-shadow-color;
}
}
.list-card { .list-card {
border: 1px solid $gray-500; border: 1px solid $gray-500;
&.has-error { &.has-error {
//Red border if invalid input[type="checkbox"],
border: 1px solid $red; input[type="radio"] {
@include list-card-focus($red);
}
} }
img { img {
@ -108,17 +123,9 @@ export default {
box-shadow: 0 0 0 1px $blue; box-shadow: 0 0 0 1px $blue;
border-radius: 0.5rem; border-radius: 0.5rem;
} }
&:focus-visible + .list-card-content {
box-shadow: 0 0 0 2.5px $blue; @include list-card-focus($blue);
border-radius: 0.5rem;
}
&:focus + .list-card-content {
box-shadow: 0 0 0 2.5px $blue;
border-radius: 0.5rem;
}
&:checked:focus + .list-card-content {
box-shadow: 0 0 0 2.5px $blue;
}
&:checked + .list-card-content { &:checked + .list-card-content {
p { p {
color: $black; color: $black;