CSR-343 Finish validation
This commit is contained in:
parent
8a1fc5bbe5
commit
06335ba625
5 changed files with 137 additions and 77 deletions
|
|
@ -9,8 +9,8 @@
|
||||||
<legend class="sr-only" :data-focus-target="groupName" :id="groupName" tabindex="-1">
|
<legend class="sr-only" :data-focus-target="groupName" :id="groupName" tabindex="-1">
|
||||||
{{(isMultiSelect && answers && answers.length > 1) ? 'Select one or more options below.' : 'Select an option below.' }}
|
{{(isMultiSelect && answers && answers.length > 1) ? 'Select one or more options below.' : 'Select an option below.' }}
|
||||||
</legend>
|
</legend>
|
||||||
<div :class="getComponentWrapperClasses">
|
<div :class="getComponentLoopWrapperClasses">
|
||||||
<div :class="isWide ? 'col-12' : 'col'" v-for="answer in answers" :key="answer.Name ? answer.Name : answer">
|
<div :class="getComponentWrapperClasses" v-for="answer in answers" :key="answer.Name ? answer.Name : answer">
|
||||||
<component
|
<component
|
||||||
:is="buttonType"
|
:is="buttonType"
|
||||||
@isCheckedChanged="handleCheckedChanged"
|
@isCheckedChanged="handleCheckedChanged"
|
||||||
|
|
@ -108,7 +108,7 @@ export default {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getComponentWrapperClasses() {
|
getComponentLoopWrapperClasses() {
|
||||||
let classes;
|
let classes;
|
||||||
switch (this.buttonType) {
|
switch (this.buttonType) {
|
||||||
case "listButton":
|
case "listButton":
|
||||||
|
|
@ -126,6 +126,17 @@ export default {
|
||||||
}
|
}
|
||||||
return classes;
|
return classes;
|
||||||
},
|
},
|
||||||
|
getComponentWrapperClasses() {
|
||||||
|
let classes = "";
|
||||||
|
|
||||||
|
classes += this.isWide ? "col-12" : "col";
|
||||||
|
|
||||||
|
if (this.buttonType == "radio") {
|
||||||
|
classes += " radio-button-container";
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes;
|
||||||
|
},
|
||||||
getColLength(){
|
getColLength(){
|
||||||
if(this.isWide) {
|
if(this.isWide) {
|
||||||
return "12"
|
return "12"
|
||||||
|
|
@ -163,6 +174,8 @@ export default {
|
||||||
this.selectedValues = val.value;
|
this.selectedValues = val.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.$emit("isCheckedChanged", val);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -188,6 +201,12 @@ export default {
|
||||||
}
|
}
|
||||||
.button-question {
|
.button-question {
|
||||||
color: $black;
|
color: $black;
|
||||||
|
|
||||||
|
.radio-button-container {
|
||||||
|
&:not(:last-child) {
|
||||||
|
padding-bottom: map-get($spacers, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.question-text {
|
.question-text {
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
|
|
|
||||||
|
|
@ -13,26 +13,25 @@
|
||||||
altText=""
|
altText=""
|
||||||
isRequired
|
isRequired
|
||||||
:groupName="`${glassLocation}-${glassName}`"
|
:groupName="`${glassLocation}-${glassName}`"
|
||||||
@isCheckedChanged="ResetTintAndPartSelections()"
|
@isCheckedChanged="ResetTintAndPartSelections"
|
||||||
validationRules="replace-options-required"
|
validationRules="replace-options-required"
|
||||||
>
|
>
|
||||||
<div class="row my-2" aria-live="polite">
|
<div class="row my-2" aria-live="polite">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
v-model="selectedPart"
|
v-model="selectedPartNumber"
|
||||||
buttonType="radio"
|
buttonType="radio"
|
||||||
class="radioQuestion"
|
class="radioQuestion"
|
||||||
:questionText="glassFeatureQuestion"
|
:questionText="glassFeatureQuestion"
|
||||||
:answers="featureListData[selectedTint]"
|
:answers="featureListData[selectedTint]"
|
||||||
:selectedValues="selectedPart"
|
textPosition="text-start"
|
||||||
textPosition="text-start"
|
:loaderEnabled="false"
|
||||||
:loaderEnabled="false"
|
isRequired
|
||||||
isRequired
|
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
|
||||||
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
|
:validationRules="`${glassLocation}-${glassName}-part-required`"
|
||||||
validationRules="part-required"
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</buttonQuestion>
|
</buttonQuestion>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -58,7 +57,8 @@ import { errorMessages } from "@/constants/error-messages";
|
||||||
// import { ErrorMessage } from "vee-validate";
|
// import { ErrorMessage } from "vee-validate";
|
||||||
|
|
||||||
defineRule("replace-options-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("replace-options-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
defineRule("part-required", required(errorMessages.OPTION_REQUIRED));
|
// defineRule("part-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
defineRule(`${this.glassLocation}-${this.glassName}-part-required`, required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "glass-part-question",
|
name: "glass-part-question",
|
||||||
|
|
@ -78,6 +78,7 @@ export default {
|
||||||
// validationRules: String,
|
// validationRules: String,
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
// this.setAllValidationRules();
|
||||||
this.LoadPreselectedValues();
|
this.LoadPreselectedValues();
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -108,15 +109,26 @@ export default {
|
||||||
return tintOptions;
|
return tintOptions;
|
||||||
},
|
},
|
||||||
|
|
||||||
selectedPart: {
|
selectedPartNumber: {
|
||||||
get: function () {
|
get() {
|
||||||
return this.modelValue;
|
console.log(this.modelValue)
|
||||||
|
return this.modelValue?.partNumber;
|
||||||
},
|
},
|
||||||
set: function (newValue) {
|
set(newValue) {
|
||||||
this.$emit("update:modelValue", newValue);
|
console.log("setting")
|
||||||
|
console.log(newValue)
|
||||||
|
|
||||||
|
this.$emit("update:modelValue", this.partsForSelectedTint.filter(part => part.partNumber == newValue)[0]);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
partsForSelectedTint() {
|
||||||
|
return this.PartDataFromApi.partsOrQuestions.filter(dataForGlassLocationAndName =>
|
||||||
|
dataForGlassLocationAndName.glassName == this.glassName &&
|
||||||
|
dataForGlassLocationAndName.glassLocation == this.glassLocation)[0]
|
||||||
|
.parts.filter(part => part.color == this.selectedTint);
|
||||||
|
},
|
||||||
|
|
||||||
// Creates a map of the feature list data in the correct Name/Value
|
// Creates a map of the feature list data in the correct Name/Value
|
||||||
// format for the button-question component.
|
// format for the button-question component.
|
||||||
featureListData() {
|
featureListData() {
|
||||||
|
|
@ -176,34 +188,47 @@ export default {
|
||||||
// Reset selections when tint changes for the same glass to ensure proper selection.
|
// Reset selections when tint changes for the same glass to ensure proper selection.
|
||||||
// Also checks if only a single part is present for the tint.
|
// Also checks if only a single part is present for the tint.
|
||||||
ResetTintAndPartSelections() {
|
ResetTintAndPartSelections() {
|
||||||
this.selectedTint = "";
|
console.log("Resetting!")
|
||||||
this.selectedPart = {};
|
// this.selectedTint = "";
|
||||||
|
this.selectedPartNumber = null;
|
||||||
this.AutoSelectIfSinglePart();
|
this.AutoSelectIfSinglePart();
|
||||||
},
|
},
|
||||||
|
|
||||||
// Check if only a single part is present for the tint and set the v-model if it is.
|
// Check if only a single part is present for the tint and set the v-model if it is.
|
||||||
AutoSelectIfSinglePart() {
|
AutoSelectIfSinglePart() {
|
||||||
// Check if the selected tint only has a single feature
|
console.log("Autoselecting, my dear")
|
||||||
Object.keys(this.PartDataFromApi.partsOrQuestions ?? {}).forEach(
|
console.log(this.PartDataFromApi.partsOrQuestions)
|
||||||
(key) => {
|
console.log(this.glassName)
|
||||||
const currentGlassSelection =
|
console.log(this.glassLocation)
|
||||||
this.PartDataFromApi.partsOrQuestions[key];
|
console.log(this.selectedTint)
|
||||||
|
console.log(this.partsForSelectedTint)
|
||||||
|
|
||||||
if (
|
if (this.partsForSelectedTint?.length == 1) {
|
||||||
currentGlassSelection.glassName === this.glassName &&
|
console.log("One!")
|
||||||
currentGlassSelection.glassLocation ===
|
this.selectedPartNumber = this.partsForSelectedTint[0].partNumber;
|
||||||
this.glassLocation
|
console.log(this.selectedPartNumber)
|
||||||
) {
|
}
|
||||||
if (currentGlassSelection.parts.length === 1) {
|
|
||||||
this.selectedPart = {
|
// this.$nextTick()
|
||||||
[currentGlassSelection.glassLocation]: [
|
console.log(this.selectedPartNumber)
|
||||||
currentGlassSelection.parts[0].partNumber,
|
|
||||||
],
|
// Check if the selected tint only has a single feature
|
||||||
};
|
// Object.keys(this.PartDataFromApi.partsOrQuestions ?? {}).forEach(
|
||||||
}
|
// (key) => {
|
||||||
}
|
// const currentGlassSelection =
|
||||||
}
|
// this.PartDataFromApi.partsOrQuestions[key];
|
||||||
);
|
|
||||||
|
// if (
|
||||||
|
// currentGlassSelection.glassName === this.glassName &&
|
||||||
|
// currentGlassSelection.glassLocation ===
|
||||||
|
// this.glassLocation
|
||||||
|
// ) {
|
||||||
|
// if (currentGlassSelection.parts.length === 1) {
|
||||||
|
// this.selectedPartNumber = currentGlassSelection.parts[0].partNumber
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// );
|
||||||
},
|
},
|
||||||
|
|
||||||
// Loads the preselected values from the store.
|
// Loads the preselected values from the store.
|
||||||
|
|
@ -211,12 +236,10 @@ export default {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.modelValue !== undefined) {
|
if (this.modelValue !== undefined) {
|
||||||
// Populate button-question model-value if parts data already exists in VueX
|
// Populate button-question model-value if parts data already exists in VueX
|
||||||
const alreadyPopulatedPartsData =
|
const alreadyPopulatedPartsData = this.$store.getters.lineItems.glassParts;
|
||||||
this.$store.getters.lineItems.glassParts;
|
|
||||||
|
|
||||||
Object.keys(alreadyPopulatedPartsData).forEach((key) => {
|
Object.keys(alreadyPopulatedPartsData).forEach((key) => {
|
||||||
const partNumber =
|
const partNumber = alreadyPopulatedPartsData[key].partNumber;
|
||||||
alreadyPopulatedPartsData[key].partNumber;
|
|
||||||
const tintColor = alreadyPopulatedPartsData[key].color;
|
const tintColor = alreadyPopulatedPartsData[key].color;
|
||||||
|
|
||||||
Object.keys(this.modelValue).forEach((key) => {
|
Object.keys(this.modelValue).forEach((key) => {
|
||||||
|
|
@ -233,10 +256,20 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// setAllValidationRules() {
|
||||||
|
// console.log("SETTING VALIDATION RULES")
|
||||||
|
// console.log(this.PartDataFromApi.partsOrQuestions)
|
||||||
|
// this.PartDataFromApi.partsOrQuestions.forEach(part => {
|
||||||
|
// console.log(`${this.glassLocation}-${this.glassName}-${this.selectedTint}-part-required`)
|
||||||
|
// defineRule(`${this.glassLocation}-${this.glassName}-part-required`, required(errorMessages.OPTION_REQUIRED));
|
||||||
|
// })
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
selectedTint(newTint, previousTint) {
|
selectedTint() {
|
||||||
this.selectedPart = null;
|
console.log("watch me")
|
||||||
|
this.selectedPartNumber = null;
|
||||||
|
this.AutoSelectIfSinglePart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ glassParts }}
|
||||||
<div v-for="(item, i) in PartsForQuestions" :key="i">
|
<div v-for="(item, i) in PartsOrQuestions" :key="i">
|
||||||
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
|
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
|
||||||
<div class="container-fluid">
|
<hr v-if="i > 0" />
|
||||||
<hr v-if="i > 0" />
|
|
||||||
</div>
|
|
||||||
<glassPartQuestion
|
<glassPartQuestion
|
||||||
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
|
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
|
||||||
v-model="glassParts[item.glassLocation + '-' + item.glassName]"
|
v-model="glassParts[item.glassLocation + '-' + item.glassName]"
|
||||||
|
|
@ -108,7 +106,7 @@ computed: {
|
||||||
isForwardActionDisabled() {
|
isForwardActionDisabled() {
|
||||||
return !this.glassParts || Object.values(this.glassParts).filter(value => value).length === 0;
|
return !this.glassParts || Object.values(this.glassParts).filter(value => value).length === 0;
|
||||||
},
|
},
|
||||||
PartsForQuestions() {
|
PartsOrQuestions() {
|
||||||
const partsData = this.PartsFromApi;
|
const partsData = this.PartsFromApi;
|
||||||
|
|
||||||
// Map API result data, to vehicle-parts data structure
|
// Map API result data, to vehicle-parts data structure
|
||||||
|
|
@ -164,26 +162,35 @@ methods: {
|
||||||
|
|
||||||
// Match them to the parts from the API.
|
// Match them to the parts from the API.
|
||||||
this.PartsFromApi.partsOrQuestions.forEach(part => {
|
this.PartsFromApi.partsOrQuestions.forEach(part => {
|
||||||
const selectedPartNumberForGlassLocationAndName = this.glassParts[`${part.glassLocation}-${part.glassName}`];
|
const selectedPartForGlassLocationAndName = this.glassParts[`${part.glassLocation}-${part.glassName}`];
|
||||||
const selectedPartData = part.parts.filter(part => part.partNumber == selectedPartNumberForGlassLocationAndName);
|
console.log(part)
|
||||||
|
console.log(this.glassParts)
|
||||||
|
console.log(`${part.glassLocation}-${part.glassName}`)
|
||||||
|
console.log(selectedPartForGlassLocationAndName)
|
||||||
|
const selectedPartData = part.parts.filter(part => selectedPartForGlassLocationAndName && part.partNumber == selectedPartForGlassLocationAndName?.partNumber)[0];
|
||||||
|
|
||||||
matchedParts.push(selectedPartData[0]);
|
if (selectedPartData)
|
||||||
|
matchedParts.push(selectedPartData);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(matchedParts)
|
||||||
|
|
||||||
// If no parts could be matched, throw an error.
|
// If no parts could be matched, throw an error.
|
||||||
if (matchedParts.length === 0) {
|
if (matchedParts.length !== this.PartsFromApi.length) {
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
throw new Error("Could not match any parts to the selected parts");
|
throw new Error("Could not match any parts to the selected parts");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.$refs.funnelFooter.removeLoader();
|
||||||
|
|
||||||
// Save parts to the store.
|
// Save parts to the store.
|
||||||
store.commit(storeMutations.UPDATE_GLASS_PARTS, matchedParts);
|
store.commit(storeMutations.UPDATE_GLASS_PARTS, matchedParts);
|
||||||
|
|
||||||
// // Navigate to the next page.
|
// Navigate to the next page.
|
||||||
// this.$router.navigateAfterSave(
|
this.$router.navigateAfterSave(
|
||||||
// this.navigationScenarios.SELECTED_PARTS,
|
this.navigationScenarios.SELECTED_PARTS,
|
||||||
// this.$route
|
this.$route
|
||||||
// );
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetDependentState() {
|
resetDependentState() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="'h-100 l' + colLength">
|
<div :class="{'h-100': !isWide}">
|
||||||
<div
|
<div
|
||||||
class="list-card w-100 rounded-3 d-flex align-items-center h-100"
|
class="list-card w-100 rounded-3 d-flex align-items-center"
|
||||||
:class="[
|
:class="[
|
||||||
isWide ? 'horizontal' : '',
|
isWide ? 'horizontal' : '',
|
||||||
(errors.length > 0 || hasError) ? 'has-error' : '',
|
(errors.length > 0 || hasError) ? 'has-error' : '',
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
:for="buttonID"
|
:for="buttonID"
|
||||||
:aria-labelledby="buttonID"
|
:aria-labelledby="buttonID"
|
||||||
class="d-flex w-100 align-items-center px-2 h-100"
|
class="d-flex w-100 align-items-center px-2"
|
||||||
:class="getLabelClasses"
|
:class="getLabelClasses"
|
||||||
@mouseup="triggerButton()"
|
@mouseup="triggerButton()"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ export default {
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.selectedValues) {
|
if (this.selectedValues) {
|
||||||
this.checkValue = this.selectedValues[0] === this.value;
|
this.checkValue = this.selectedValues === this.value;
|
||||||
}else{
|
} else{
|
||||||
this.checkValue = false;
|
this.checkValue = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -86,12 +86,13 @@ export default {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>yu78zas
|
<style lang="scss" scoped>
|
||||||
.form-check {
|
.form-check {
|
||||||
.form-check-input {
|
.form-check-input {
|
||||||
border: 1px solid $gray-500;
|
border: 1px solid $gray-500;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
|
margin-top: 0.12rem;
|
||||||
&:checked {
|
&:checked {
|
||||||
background-color: $white;
|
background-color: $white;
|
||||||
background-size: 71%;
|
background-size: 71%;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue