Refactoring global rules

This commit is contained in:
brydon1 2023-07-07 14:20:22 -04:00
parent c0352e703b
commit d78a082f6a
15 changed files with 206 additions and 133 deletions

View file

@ -0,0 +1,13 @@
const globalRules = {
POLICYHOLDER_FIRST_NAME_REQUIRED: 'policyholder-first-name-required',
POLICYHOLDER_LAST_NAME_REQUIRED: 'policyholder-last-name-required',
FIRST_NAME_REQUIRED: 'first-name-required',
LAST_NAME_REQUIRED: 'last-name-required',
PHONE_NUMBER_REQUIRED: 'phone-number-required',
EMAIL_ADDRESS_REQUIRED: 'email-required',
EMAIL_ADDRESS_FORMAT: 'email-address-format',
PHONE_NUMBER_FORMAT: 'phone-number-format',
OPTION_REQUIRED: 'option-required'
};
export default globalRules;

View file

@ -8,7 +8,7 @@
ref="firstName" ref="firstName"
inputId="08497a2efd9a4a73a70360ab47b4838d" inputId="08497a2efd9a4a73a70360ab47b4838d"
disableAutoFill disableAutoFill
validationRules="first-name-required" /> :validationRules="rules.firstName" />
</div> </div>
</div> </div>
<div class="row mb-4"> <div class="row mb-4">
@ -19,21 +19,15 @@
ref="lastName" ref="lastName"
inputId="0030e56a57e74a4ab92de7fb8e97fec5" inputId="0030e56a57e74a4ab92de7fb8e97fec5"
disableAutoFill disableAutoFill
validationRules="last-name-required" /> :validationRules="rules.lastName" />
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import addressQuestions from "@/iss-components/address-questions/address-questions"; import addressQuestions from '@/iss-components/address-questions/address-questions.vue';
import textboxQuestion from "@/digital-components/textbox-question/textbox-question"; import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import { defineRule } from "vee-validate"; import globalRules from '@/constants/global-rules';
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
// DEFINE VALIDATION RULES
defineRule("first-name-required", required(errorMessages.FIRST_NAME_REQUIRED));
defineRule("last-name-required", required(errorMessages.LAST_NAME_REQUIRED));
export default { export default {
name: "customer-questions", name: "customer-questions",
@ -56,6 +50,14 @@ export default {
}, },
validationRules: String, validationRules: String,
}, },
data() {
return {
rules: {
firstName: globalRules.FIRST_NAME_REQUIRED,
lastName: globalRules.LAST_NAME_REQUIRED
}
};
},
computed: { computed: {
customerModel: { customerModel: {
get: function () { get: function () {

View file

@ -11,7 +11,7 @@
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader" :alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy" :alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
:questionsData="questionsData" :questionsData="questionsData"
validationRules="questions-required" :validationRules="rules.optionRequired"
v-model="selectedAnswers" v-model="selectedAnswers"
@forwardButtonAction="forwardButtonAction" @forwardButtonAction="forwardButtonAction"
@back-click="navigateBack" @back-click="navigateBack"
@ -26,14 +26,11 @@ import { settleAllPromises } from '@/helpers/layout-helper';
// Import Component // Import Component
import baseFormMixin from '@/mixins/base-form-mixin'; import baseFormMixin from '@/mixins/base-form-mixin';
import { issPageValues } from "@/router/router-constants/issPage-values"; import { issPageValues } from "@/router/router-constants/issPage-values";
import { Form, defineRule } from "vee-validate"; import { Form } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import { useMainStore } from "@/store"; import { useMainStore } from "@/store";
import { errorMessages } from "@/constants/error-messages"; import globalRules from '@/constants/global-rules';
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import questionsPageLayout from "@/iss-components/questions-page-layout/questions-page-layout.vue"; import questionsPageLayout from "@/iss-components/questions-page-layout/questions-page-layout.vue";
// DEFINE VALIDATION RULES
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
export default { export default {
name: 'capability-questions', name: 'capability-questions',
@ -45,8 +42,11 @@ export default {
data() { data() {
return { return {
questionsData: [], questionsData: [],
selectedAnswers: {}, selectedAnswers: {},
currentGlassIndex: 0, currentGlassIndex: 0,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
}; };
}, },
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {

View file

@ -4,7 +4,7 @@ import contactDetails from '@/layouts/contact-details/contact-details.vue';
// Supporting Files // Supporting Files
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper'; import { getMountOptions } from '@/helpers/unit-test-helper';
import { getRandomString } from '@/helpers/data-generator'; import { getRandomString } from '@/helpers/data-generation';
// import { useMainStore } from '@/store'; // import { useMainStore } from '@/store';
// import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin'; // import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
// import { nextTick } from 'vue'; // import { nextTick } from 'vue';
@ -75,13 +75,24 @@ describe('contactDetails.vue', () => {
}); });
test('Should render text updates checkbox subcomponent', () => { test('Should render text updates checkbox subcomponent', () => {
// Arrange // Arrange
const wrapper = shallowMount(contactDetails, getMountOptions()); const checkboxLabel = getRandomString(50, 100);
const mockMixin = {
methods: {
getCmsContent: jest.fn().mockImplementation(() =>
checkboxLabel),
setCmsContent: jest.fn()
}
};
const mountOptions = getMountOptions();
mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(contactDetails, mountOptions);
// Act // Act
const textUpdatesCheckbox = wrapper.findComponent({ ref: 'requestTextUpdatesCheckbox' }); const textUpdatesCheckbox = wrapper.findComponent({ ref: 'requestTextUpdatesCheckbox' });
// Assert // Assert
expect(textUpdatesCheckbox.exists()).toBe(true); expect(textUpdatesCheckbox.exists()).toBe(true);
expect(wrapper.vm.textContentText).toBe(`${checkboxLabel}*`);
}); });
test('Should render technician notes textarea question subcomponent', () => { test('Should render technician notes textarea question subcomponent', () => {
// Arrange // Arrange
@ -93,29 +104,48 @@ describe('contactDetails.vue', () => {
// Assert // Assert
expect(notesQuestion.exists()).toBe(true); expect(notesQuestion.exists()).toBe(true);
}); });
test.only('Should render disclaimer text', () => { test('Should render disclaimer text', () => {
// Arrange // Arrange
const disclaimerText = 'the disclaimer.'; const disclaimerText = getRandomString(50, 100);
const mockMixin = { const mockMixin = {
methods: { methods: {
getCmsContent: jest.fn().mockImplementation(() => getCmsContent: jest.fn().mockImplementation(() =>
disclaimerText) disclaimerText),
setCmsContent: jest.fn()
} }
}; };
const mountOptions = getMountOptions(); const mountOptions = getMountOptions();
mountOptions.mixins = [mockMixin]; mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(contactDetails, mountOptions); const wrapper = shallowMount(contactDetails, mountOptions);
wrapper.vm.setCmsContent = jest.fn();
const expectedDisclaimerText = `*${disclaimerText} I also agree to Safelite\'s`; const expectedDisclaimerText = `*${disclaimerText} I also agree to Safelite\'s`;
// Act // Act
const componentText = wrapper.text(); const componentText = wrapper.text();
// Assert // Assert
expect(wrapper.vm.textUpdateDisclaimerText).toBe(`*${disclaimerText}`);
expect(componentText).toContain(expectedDisclaimerText); expect(componentText).toContain(expectedDisclaimerText);
}); });
test('Should render privacy policy link', () => {}); test('Should render privacy policy link', () => {
test('Should render terms of use link', () => {}); // Arrange
const wrapper = shallowMount(contactDetails, getMountOptions());
// Act
const privacyPolicyLink = wrapper.findComponent({ ref: 'privacyPolicyLink' });
// Assert
expect(privacyPolicyLink.exists()).toBe(true);
});
test('Should render terms of use link', () => {
// Arrange
const wrapper = shallowMount(contactDetails, getMountOptions());
// Act
const termsOfUseLink = wrapper.findComponent({ ref: 'termsOfUseLink' });
// Assert
expect(termsOfUseLink.exists()).toBe(true);
});
test('Should render site footer', () => { test('Should render site footer', () => {
// Arrange // Arrange
const wrapper = shallowMount(contactDetails, getMountOptions()); const wrapper = shallowMount(contactDetails, getMountOptions());
@ -137,6 +167,7 @@ describe('contactDetails.vue', () => {
}); });
}); });
// move error tests
describe('Errors', () => { describe('Errors', () => {
test('Error rendered when first name cleared', () => {}); test('Error rendered when first name cleared', () => {});
test('Error rendered when last name cleared', () => {}); test('Error rendered when last name cleared', () => {});

View file

@ -8,45 +8,45 @@
<div class="fade-on-route-transition position-relative"> <div class="fade-on-route-transition position-relative">
<siteHeader <siteHeader
ref="siteHeader" ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" /> :cmsWidgetName="widget.siteHeader" />
<div class="container-fluid pb-2"> <div class="container-fluid pb-2">
<siteSubHeader <siteSubHeader
id="sub-header" id="sub-header"
ref="siteSubHeader" ref="siteSubHeader"
class="margin-top-16" class="margin-top-16"
cmsWidgetName="SiteSubHeaderWidget" /> :cmsWidgetName="widget.siteSubHeader" />
<textboxQuestion <textboxQuestion
ref="firstNameQuestion" ref="firstNameQuestion"
v-model="firstName" v-model="firstName"
class="margin-top-24" class="margin-top-24"
inputId="firstName" inputId="firstName"
cmsWidgetName="FirstNameQuestionWidget" :cmsWidgetName="widget.firstNameQuestion"
isRequired isRequired
validationRules="first-name-required" /> :validationRules="rules.firstName" />
<textboxQuestion <textboxQuestion
ref="lastNameQuestion" ref="lastNameQuestion"
v-model="lastName" v-model="lastName"
class="margin-top-16" class="margin-top-16"
inputId="lastName" inputId="lastName"
cmsWidgetName="LastNameQuestionWidget" :cmsWidgetName="widget.lastNameQuestion"
isRequired isRequired
validationRules="last-name-required" /> :validationRules="rules.lastName" />
<textboxQuestion <textboxQuestion
ref="emailQuestion" ref="emailQuestion"
v-model="email" v-model="email"
class="margin-top-16" class="margin-top-16"
inputId="email" inputId="email"
cmsWidgetName="EmailQuestionWidget" :cmsWidgetName="widget.emailQuestion"
isRequired isRequired
validationRules="email-address-required|email-address-format" /> :validationRules="rules.email" />
<textboxQuestion <textboxQuestion
ref="phoneNumberQuestion" ref="phoneNumberQuestion"
v-model="phoneNumber" v-model="phoneNumber"
class="margin-top-16" class="margin-top-16"
inputId="phoneNumber" inputId="phoneNumber"
cmsWidgetName="PhoneNumberQuestionWidget" :cmsWidgetName="widget.phoneNumberQuestion"
isRequired isRequired
validationRules="phone-number-required|phone-number-format" /> :validationRules="rules.phoneNumber" />
<checkbox <checkbox
ref="requestTextUpdatesCheckbox" ref="requestTextUpdatesCheckbox"
v-model="requestTextUpdates" v-model="requestTextUpdates"
@ -63,7 +63,7 @@
:isDisabled="false" :isDisabled="false"
:isRequired="false" :isRequired="false"
hasError="hasError" hasError="hasError"
cmsWidgetName="NotesQuestionWidget" :cmsWidgetName="widget.notesQuestion"
maxLength="500" maxLength="500"
inputRows="30" /> inputRows="30" />
@ -72,6 +72,7 @@
class="disclaimer margin-top-24"> class="disclaimer margin-top-24">
{{ textUpdateDisclaimerText }} I also agree to Safelite's {{ textUpdateDisclaimerText }} I also agree to Safelite's
<textLink <textLink
ref="privacyPolicyLink"
class="disclaimer-link" class="disclaimer-link"
linkType="text" linkType="text"
text="Privacy Policy" text="Privacy Policy"
@ -79,6 +80,7 @@
target="_blank" /> target="_blank" />
and and
<textLink <textLink
ref="termsOfUseLink"
class="disclaimer-link" class="disclaimer-link"
linkType="text" linkType="text"
text="Terms of Use" text="Terms of Use"
@ -88,7 +90,7 @@
<siteFooter <siteFooter
ref="siteFooter" ref="siteFooter"
cmsWidgetName="SiteFooterWidget" :cmsWidgetName="widget.siteFooter"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@forwardClicked="navigateForward" @forwardClicked="navigateForward"
@backClicked="backButtonAction" /> @backClicked="backButtonAction" />
@ -110,23 +112,10 @@ import textLink from '@/ux-components/text-link/text-link.vue';
// Supporting files // Supporting files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { settleAllPromises } from '@/helpers/layout-helper'; import { settleAllPromises } from '@/helpers/layout-helper';
import { Form, defineRule } from 'vee-validate'; import { Form } from 'vee-validate';
import { errorMessages } from '@/constants/error-messages';
import BaseFormMixin from '@/mixins/base-form-mixin'; import BaseFormMixin from '@/mixins/base-form-mixin';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { required, regex } from '@/helpers/validation-rules'; import globalRules from '@/constants/global-rules';
// TODO define these globally and reuse
defineRule('first-name-required', required(errorMessages.FIRST_NAME_REQUIRED));
defineRule('last-name-required', required(errorMessages.LAST_NAME_REQUIRED));
defineRule('phone-number-required', required(errorMessages.PHONE_NUMBER_REQUIRED));
defineRule('phone-number-format',
regex(/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/,
errorMessages.PHONE_NUMBER_FORMAT));
defineRule('email-address-required', required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule('email-address-format',
regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT));
export default { export default {
name: 'contact-details', name: 'contact-details',
@ -168,15 +157,33 @@ export default {
email: useMainStore().order.customer.emailAddress, email: useMainStore().order.customer.emailAddress,
phoneNumber: useMainStore().order.customer.phoneNumber, phoneNumber: useMainStore().order.customer.phoneNumber,
requestTextUpdates: false, requestTextUpdates: false,
notesForTechnician: '' notesForTechnician: '',
widget: {
siteHeader: 'SiteHeaderWidget',
siteSubHeader: 'SiteSubHeaderWidget',
firstNameQuestion: 'FirstNameQuestionWidget',
lastNameQuestion: 'LastNameQuestionWidget',
emailQuestion: 'EmailQuestionWidget',
phoneNumberQuestion: 'PhoneNumberQuestionWidget',
requestTextUpdates: 'TextContentWidget',
notesQuestion: 'NotesQuestionWidget',
disclaimer: 'TextUpdateDisclaimerWidget',
siteFooter: 'SiteFooterWidget'
},
rules: {
firstName: globalRules.FIRST_NAME_REQUIRED,
lastName: globalRules.LAST_NAME_REQUIRED,
email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`,
phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`
}
}; };
}, },
computed: { computed: {
textContentText() { textContentText() {
return `${this.getCmsContent('TextContentWidget', 'Text')}*`; return `${this.getCmsContent(this.widget.requestTextUpdates, 'Text')}*`;
}, },
textUpdateDisclaimerText() { textUpdateDisclaimerText() {
return `*${this.getCmsContent('TextUpdateDisclaimerWidget', 'Text')}`; return `*${this.getCmsContent(this.widget.disclaimer, 'Text')}`;
} }
}, },
methods: methods:

View file

@ -12,7 +12,7 @@
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader" :alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy" :alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
:questionsData="questionsData" :questionsData="questionsData"
validationRules="questions-required" :validationRules="rules.optionRequired"
v-model="selectedAnswers" v-model="selectedAnswers"
@forwardButtonAction="forwardButtonAction" @forwardButtonAction="forwardButtonAction"
@back-click="navigateBack" @back-click="navigateBack"
@ -25,9 +25,7 @@
// Import Supporting Files // Import Supporting Files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { defineRule } from "vee-validate"; import globalRules from '@/constants/global-rules';
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { useMainStore } from "@/store"; import { useMainStore } from "@/store";
import { issPageValues } from "@/router/router-constants/issPage-values"; import { issPageValues } from "@/router/router-constants/issPage-values";
@ -37,9 +35,6 @@ import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { Form } from "vee-validate"; import { Form } from "vee-validate";
import questionsPageLayout from "@/iss-components/questions-page-layout/questions-page-layout.vue"; import questionsPageLayout from "@/iss-components/questions-page-layout/questions-page-layout.vue";
// DEFINE VALIDATION RULES
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
export default { export default {
name: "molding-questions", name: "molding-questions",
mixins: [BaseFormMixin, vehicleQuestionsMixin], mixins: [BaseFormMixin, vehicleQuestionsMixin],
@ -65,6 +60,9 @@ export default {
questionsData: [], questionsData: [],
selectedAnswers: {}, selectedAnswers: {},
currentGlassIndex: 0, currentGlassIndex: 0,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
}; };
}, },
computed: { computed: {

View file

@ -6,7 +6,7 @@
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader" :alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy" :alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
:questionsData="questionsData" :questionsData="questionsData"
validationRules="questions-required" :validationRules="rules.optionRequired"
v-model="selectedAnswers" v-model="selectedAnswers"
@forwardButtonAction="forwardButtonAction" @forwardButtonAction="forwardButtonAction"
@back-click="navigateBack" @back-click="navigateBack"
@ -23,14 +23,10 @@ import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { issPageValues } from "@/router/router-constants/issPage-values"; import { issPageValues } from "@/router/router-constants/issPage-values";
import { Form, defineRule } from "vee-validate"; import { Form } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import globalRules from '@/helpers/global-rules';
// DEFINE VALIDATION RULES
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
export default { export default {
name: "part-questions", name: "part-questions",
@ -59,6 +55,9 @@ export default {
questionsData: [], questionsData: [],
selectedAnswers: {}, selectedAnswers: {},
currentGlassIndex: 0, currentGlassIndex: 0,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
}; };
}, },
computed: { computed: {

View file

@ -15,7 +15,7 @@
isRequired isRequired
ref="policyHolderFirstName" ref="policyHolderFirstName"
disableAutoFill disableAutoFill
validationRules="first-name-required" /> :validationRules="rules.firstName" />
<textboxQuestion <textboxQuestion
class="mt-4" class="mt-4"
inputId="lastNameField" inputId="lastNameField"
@ -24,7 +24,7 @@
isRequired isRequired
ref="policyHolderLastName" ref="policyHolderLastName"
disableAutoFill disableAutoFill
validationRules="last-name-required" /> :validationRules="rules.lastName" />
</div> </div>
</div> </div>
<siteFooter <siteFooter
@ -51,16 +51,11 @@ import siteFooter from "@/iss-components/site-footer/site-footer";
// Supporting files // Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { Form, defineRule } from "vee-validate"; import { Form } from "vee-validate";
import { required } from "@/helpers/validation-rules"; import globalRules from '@/constants/global-rules';
import { errorMessages } from "@/constants/error-messages";
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
//define validation rules
defineRule("first-name-required", required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED));
defineRule("last-name-required", required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED));
export default { export default {
name: "policy-holder-details", name: "policy-holder-details",
mixins: [BaseFormMixin], mixins: [BaseFormMixin],
@ -68,6 +63,10 @@ export default {
return { return {
customerQuestions: this.getPolicyHolderDetailsFromStore(), customerQuestions: this.getPolicyHolderDetailsFromStore(),
vehiclesFound: [], vehiclesFound: [],
rules: {
firstName: globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED,
lastName: globalRules.POLICYHOLDER_LAST_NAME_REQUIRED
}
}; };
}, },
setup() { setup() {

View file

@ -13,7 +13,7 @@
class="px-4" class="px-4"
cmsWidgetName="PolicyVehiclesQuestion" cmsWidgetName="PolicyVehiclesQuestion"
:vehicles="VehiclesForQuestions" :vehicles="VehiclesForQuestions"
validationRules="option-required" :validationRules="rules.optionRequired"
v-model="selectedVehicleVin" v-model="selectedVehicleVin"
/> />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" :isForwardActionDisabled="!meta.valid" @ForwardClicked="forwardButtonAction" @back-clicked="backButtonAction"/> <siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" :isForwardActionDisabled="!meta.valid" @ForwardClicked="forwardButtonAction" @back-clicked="backButtonAction"/>
@ -35,17 +35,14 @@ import policyVehiclesQuestion from "@/layouts/policy-vehicles/policy-vehicles-qu
// Supporting files // Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { required } from "@/helpers/validation-rules"; import { Form } from "vee-validate";
import { Form, defineRule } from "vee-validate";
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { issPageValues } from "@/router/router-constants/issPage-values"; import { issPageValues } from "@/router/router-constants/issPage-values";
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { errorMessages } from "@/constants/error-messages"; import globalRules from '@/constants/global-rules';
import { vehicleSelectionOptions } from "@/constants/vehicle-selection-options"; import { vehicleSelectionOptions } from "@/constants/vehicle-selection-options";
import { endorsementOptions } from "@/constants/endorsement-options"; import { endorsementOptions } from "@/constants/endorsement-options";
// DEFINE VALIDATION RULES
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
export default { export default {
name: "policy-vehicles", name: "policy-vehicles",
mixins: [BaseFormMixin], mixins: [BaseFormMixin],
@ -57,7 +54,10 @@ export default {
? policyVehicles[0].vin ? policyVehicles[0].vin
: "", : "",
displayGeneric: true, displayGeneric: true,
bailout: false bailout: false,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
} }
}, },
async beforeRouteEnter(to, from, next) async beforeRouteEnter(to, from, next)

View file

@ -11,7 +11,7 @@
groupName="prefQuestions" groupName="prefQuestions"
buttonTypeString="providerPrefRadio" buttonTypeString="providerPrefRadio"
v-model="selectedProvider" v-model="selectedProvider"
validationRules="option-required" :validationRules="rules.optionRequired"
isRequired isRequired
class="mx-5" /> class="mx-5" />
<div class="px-5"> <div class="px-5">
@ -44,7 +44,6 @@
// Import Supporting Files // Import Supporting Files
import { fetchCmsContentForPage, setupModalLinks, processIfStatements } from '@/helpers/cms-content-helper'; import { fetchCmsContentForPage, setupModalLinks, processIfStatements } from '@/helpers/cms-content-helper';
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
import buttonQuestion from "@/digital-components/button-question/button-question"; import buttonQuestion from "@/digital-components/button-question/button-question";
import contentGroupModal from "@/iss-components/content-group-modal/content-group-modal"; import contentGroupModal from "@/iss-components/content-group-modal/content-group-modal";
@ -52,7 +51,7 @@ import { issPageValues } from "@/router/router-constants/issPage-values";
// Import Component // Import Component
import baseFormMixin from "@/mixins/base-form-mixin"; import baseFormMixin from "@/mixins/base-form-mixin";
import { Form, defineRule } from "vee-validate"; import { Form } from "vee-validate";
import siteFooter from "@/iss-components/site-footer/site-footer"; import siteFooter from "@/iss-components/site-footer/site-footer";
import siteHeader from "@/iss-components/site-header/site-header"; import siteHeader from "@/iss-components/site-header/site-header";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header"; import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
@ -61,9 +60,8 @@ import recalModal from "@/layouts/coverage-statement/recal-modal/recal-modal";
import steeringModal from "@/layouts/provider-preference/steering-modal/steering-modal"; import steeringModal from "@/layouts/provider-preference/steering-modal/steering-modal";
import shopPreferenceModal from "@/layouts/provider-preference/shop-preference-modal/shop-preference-modal"; import shopPreferenceModal from "@/layouts/provider-preference/shop-preference-modal/shop-preference-modal";
import tpaRecalModal from "@/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue" import tpaRecalModal from "@/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue"
import globalRules from '@/constants/global-rules';
// DEFINE VALIDATION RULES
defineRule('option-required', required(errorMessages.OPTION_REQUIRED));
const options = { SAFELITE: 'SafeliteOption', TPA: 'TPAOption' }; const options = { SAFELITE: 'SafeliteOption', TPA: 'TPAOption' };
export default { export default {
@ -88,6 +86,9 @@ export default {
selectedProvider : null, selectedProvider : null,
showSteeringLink: false, showSteeringLink: false,
tpaAcknowledgement: false, tpaAcknowledgement: false,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
}; };
}, },
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {

View file

@ -13,7 +13,7 @@
<checkBox <checkBox
class="mb-2" class="mb-2"
:class="showError && ' has-error'" :class="showError && ' has-error'"
validationRules="option-required" :validationRules="rules.optionRequired"
checkboxName="tpaAcknowledgement" checkboxName="tpaAcknowledgement"
buttonID="tpaAcknowledgement" buttonID="tpaAcknowledgement"
:tabIndex="0" :tabIndex="0"
@ -35,6 +35,7 @@
import modal from "@/digital-components/modal/modal"; import modal from "@/digital-components/modal/modal";
import tpaRecalToggle from "@/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue" import tpaRecalToggle from "@/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue"
import checkBox from "@/ux-components/checkbox/checkbox.vue" import checkBox from "@/ux-components/checkbox/checkbox.vue"
import globalRules from "@/constants/global-rules";
export default { export default {
name: "content-group-modal", name: "content-group-modal",
@ -45,7 +46,10 @@ export default {
data() { data() {
return { return {
acknowledged: false, acknowledged: false,
showError: false showError: false,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
}; };
}, },
emits: ["buttonClick"], emits: ["buttonClick"],

View file

@ -14,7 +14,7 @@
:availableLineItems="availableLineItems" :availableLineItems="availableLineItems"
@vapsItemsSelected="vapsItemsSelectedAction" @vapsItemsSelected="vapsItemsSelectedAction"
v-on:link-event="openModalAction" v-on:link-event="openModalAction"
validationRules="option-required" :validationRules="rules.optionRequired"
isRequired isRequired
/> />
<p class="caption disclaimer" v-html="PriceDisclaimerText"></p> <p class="caption disclaimer" v-html="PriceDisclaimerText"></p>
@ -52,8 +52,7 @@ import { required } from '@/helpers/validation-rules';
import { errorMessages } from '@/constants/error-messages'; import { errorMessages } from '@/constants/error-messages';
import { Form, defineRule } from 'vee-validate'; import { Form, defineRule } from 'vee-validate';
import { allGlassPartsAndItemsHavePrices } from '@/layouts/service-packages/service-package-helper/service-package-helper' import { allGlassPartsAndItemsHavePrices } from '@/layouts/service-packages/service-package-helper/service-package-helper'
import globalRules from "@/constants/global-rules";
defineRule('option-required', required(errorMessages.OPTION_REQUIRED));
const store = useMainStore(); const store = useMainStore();
@ -112,7 +111,10 @@ export default {
selectedVaps: [], selectedVaps: [],
availableLineItems: [], availableLineItems: [],
supportingItems: [], supportingItems: [],
pricedGlassParts: [] pricedGlassParts: [],
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
}; };
}, },
computed: { computed: {

View file

@ -5,7 +5,7 @@
button-type-string="listButton" button-type-string="listButton"
:question-text="questionTextFromCms" :question-text="questionTextFromCms"
is-required is-required
validation-rules="option-required" :validation-rules="rules.optionRequired"
data-test-id="vin-lookup-methods-button-question" data-test-id="vin-lookup-methods-button-question"
/> />
</template> </template>
@ -13,32 +13,30 @@
<script> <script>
// Import Other Supporting Files // Import Other Supporting Files
import { defineRule } from 'vee-validate';
import { required } from '@/helpers/validation-rules';
import { errorMessages } from '@/constants/error-messages';
import { useMainStore } from "@/store"; import { useMainStore } from "@/store";
import {vinLookupMethodSelections} from '@/constants/vin-lookup-methods'; import { vinLookupMethodSelections } from '@/constants/vin-lookup-methods';
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import globalRules from '@/constants/global-rules';
// Import Component // Import Component
import ButtonQuestion from '@/digital-components/button-question/button-question.vue'; import ButtonQuestion from '@/digital-components/button-question/button-question.vue';
// Define Validation Rules
defineRule('option-required', required(errorMessages.OPTION_REQUIRED));
export default { export default {
name: 'vin-lookup-methods', name: 'vin-lookup-methods',
data() { data() {
return { return {
questionTextFromCms: '', questionTextFromCms: '',
answersFromCms: [], answersFromCms: [],
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
}; };
}, },
props: { props: {
modelValue: String, modelValue: String,
cmsWidgetName: { cmsWidgetName: {
type: String, type: String,
required, required: true
}, },
}, },

View file

@ -15,7 +15,7 @@
ref="policyNumber" ref="policyNumber"
disableAutoFill disableAutoFill
:isDisabled="isPolicyHolderEnabled" :isDisabled="isPolicyHolderEnabled"
validationRules="policy-number-required" /> :validationRules="rules.policyNumber" />
</div> </div>
</div> </div>
<div class="row mt-4" v-if="this.isCoverageEnabled"> <div class="row mt-4" v-if="this.isCoverageEnabled">
@ -26,7 +26,7 @@
v-model="welcomePageModel.policyZipCode" v-model="welcomePageModel.policyZipCode"
isRequired isRequired
ref="policyZip" ref="policyZip"
validationRules="policy-zip-required|policy-zip-format" /> :validationRules="rules.policyZip" />
</div> </div>
</div> </div>
<div class="row mt-4"> <div class="row mt-4">
@ -41,7 +41,7 @@
disableAutoFill disableAutoFill
:max="new Date().toJSON().slice(0,10)" :max="new Date().toJSON().slice(0,10)"
:min="'1972-12-01'" :min="'1972-12-01'"
validationRules="loss-date-required" :validationRules="rules.lossDate"
/> />
</div> </div>
</div> </div>
@ -59,7 +59,7 @@
inputId="damageCauseQuestionField" inputId="damageCauseQuestionField"
:options="DamageCauseOptions" :options="DamageCauseOptions"
disableAutoFill disableAutoFill
validationRules="damage-option-required" :validationRules="rules.damageOption"
placeHolderText="Select an option" placeHolderText="Select an option"
id="welcomeDropdown" id="welcomeDropdown"
/> />
@ -71,7 +71,7 @@
inputId="phoneNumberField" inputId="phoneNumberField"
cmsWidgetName="PhoneNumberQuestion" cmsWidgetName="PhoneNumberQuestion"
v-model="welcomePageModel.phoneNumber" v-model="welcomePageModel.phoneNumber"
validationRules="phone-number-required|phone-number-format" :validationRules="rules.phoneNumber"
isRequired isRequired
ref="phoneNumber" ref="phoneNumber"
mask="###-###-####" mask="###-###-####"
@ -85,7 +85,7 @@
cmsWidgetName="EmailAddressQuestion" cmsWidgetName="EmailAddressQuestion"
v-model="welcomePageModel.email" v-model="welcomePageModel.email"
ref="email" ref="email"
validationRules="email-address-required|email-address-format" :validationRules="rules.email"
isRequired isRequired
disableAutoFill /> disableAutoFill />
</div> </div>
@ -101,7 +101,7 @@
ref="damageCity" ref="damageCity"
disableAutoFill disableAutoFill
v-if="this.displayDamageCityQuestion" v-if="this.displayDamageCityQuestion"
validationRules="loss-city-required" /> :validationRules="rules.lossCity" />
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -113,7 +113,7 @@
ref="state" ref="state"
inputId="8fdf9dc2e13e430eb57529499dceb3eb" inputId="8fdf9dc2e13e430eb57529499dceb3eb"
:options="getStates" :options="getStates"
validationRules="loss-state-required" :validationRules="rules.lossState"
isRequired isRequired
disableAutoFill disableAutoFill
v-if="this.displayDamageStateQuestion" v-if="this.displayDamageStateQuestion"
@ -127,11 +127,11 @@
class="px-0 mt-4" class="px-0 mt-4"
cmsWidgetName="GlassOnlyQuestion" cmsWidgetName="GlassOnlyQuestion"
v-model="welcomePageModel.isDamageGlassOnly" v-model="welcomePageModel.isDamageGlassOnly"
inputId = "isDamageGlassOnly" inputId="isDamageGlassOnly"
:answers="DamageGlassOnlyOptions" :answers="DamageGlassOnlyOptions"
:questionText="DamageGlassOnlyQuestion" :questionText="DamageGlassOnlyQuestion"
buttonTypeString="listButtonHorizontal" buttonTypeString="listButtonHorizontal"
validationRules="damage-option-required" :validationRules="rules.damageOption"
isRequired isRequired
isSmallQuestionLabelText isSmallQuestionLabelText
ref="glassOnlyDamage" ref="glassOnlyDamage"
@ -173,32 +173,17 @@
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { states } from "@/constants/states" import { states } from "@/constants/states"
import globalRules from '@/constants/global-rules';
//define validation rules //define validation rules
defineRule("loss-date-required", required(errorMessages.LOSS_DATE_REQUIRED)); defineRule("loss-date-required", required(errorMessages.LOSS_DATE_REQUIRED));
defineRule("loss-cause-required", required(errorMessages.LOSS_CAUSE_REQUIRED));
defineRule("policy-number-required", required(errorMessages.POLICY_NUMBER_REQUIRED)); defineRule("policy-number-required", required(errorMessages.POLICY_NUMBER_REQUIRED));
defineRule("loss-date-required", required(errorMessages.LOSS_DATE_REQUIRED));
defineRule("loss-state-required", required(errorMessages.LOSS_STATE_REQUIRED)); defineRule("loss-state-required", required(errorMessages.LOSS_STATE_REQUIRED));
defineRule("loss-city-required", required(errorMessages.LOSS_CITY_REQUIRED)); defineRule("loss-city-required", required(errorMessages.LOSS_CITY_REQUIRED));
defineRule("phone-number-required", required(errorMessages.PHONE_NUMBER_FORMAT));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule("damage-option-required", required(errorMessages.DAMAGE_OPTION_REQUIRED)); defineRule("damage-option-required", required(errorMessages.DAMAGE_OPTION_REQUIRED));
defineRule("policy-zip-required", required(errorMessages.POLICY_ZIP_REQUIRED)); defineRule("policy-zip-required", required(errorMessages.POLICY_ZIP_REQUIRED));
defineRule("policy-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.POLICY_ZIP_FORMAT)); defineRule("policy-zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.POLICY_ZIP_FORMAT));
defineRule("email-address-format",
regex(
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT
));
defineRule("phone-number-format",
regex(
/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/,
errorMessages.PHONE_NUMBER_FORMAT
));
export default { export default {
name: "welcome-page", name: "welcome-page",
mixins: [BaseFormMixin], mixins: [BaseFormMixin],
@ -206,6 +191,16 @@ export default {
return { return {
welcomePageModel: this.getWelcomePageModelFromStore(), welcomePageModel: this.getWelcomePageModelFromStore(),
vehiclesFound: [], vehiclesFound: [],
rules: {
policyNumber: 'policy-number-required',
policyZip: 'policy-zip-required|policy-zip-format',
lossDate: 'loss-date-required',
damageOption: 'damage-option-required',
phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`,
email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`,
lossCity: 'loss-city-required',
lossState: 'loss-state-required'
}
}; };
}, },
setup() { setup() {

View file

@ -12,6 +12,11 @@ import LoadScript from "vue-plugin-load-script";
import analyticsMixin from "@/mixins/analytics-mixin.js"; import analyticsMixin from "@/mixins/analytics-mixin.js";
import experimentMixin from "@/mixins/experiment-mixin.js"; import experimentMixin from "@/mixins/experiment-mixin.js";
import { defineRule } from 'vee-validate';
import { errorMessages } from '@/constants/error-messages';
import globalRules from '@/constants/global-rules';
import { required, regex } from '@/helpers/validation-rules';
// Vue App Setup // Vue App Setup
const vueApp = createApp(App); const vueApp = createApp(App);
@ -44,3 +49,22 @@ vueApp.mixin(analyticsMixin);
vueApp.mixin(experimentMixin); vueApp.mixin(experimentMixin);
vueApp.mount("#app"); vueApp.mount("#app");
// define global rules
defineRule(globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED,
required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED));
defineRule(globalRules.POLICYHOLDER_LAST_NAME_REQUIRED,
required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED));
defineRule(globalRules.FIRST_NAME_REQUIRED, required(errorMessages.FIRST_NAME_REQUIRED));
defineRule(globalRules.LAST_NAME_REQUIRED, required(errorMessages.LAST_NAME_REQUIRED));
defineRule(globalRules.PHONE_NUMBER_REQUIRED, required(errorMessages.PHONE_NUMBER_REQUIRED));
defineRule(globalRules.PHONE_NUMBER_FORMAT,
regex(/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/,
errorMessages.PHONE_NUMBER_FORMAT));
defineRule(globalRules.EMAIL_ADDRESS_REQUIRED, required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule(globalRules.EMAIL_ADDRESS_FORMAT,
regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT));
defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED));