Initial commit
This commit is contained in:
parent
2815d88858
commit
2d97232d40
6 changed files with 1801 additions and 64 deletions
1036
package-lock.json
generated
1036
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -40,6 +40,7 @@
|
|||
"eslint-plugin-vue": "9.8.0",
|
||||
"jest": "^27.0.5",
|
||||
"sass": "^1.32.7",
|
||||
"sass-loader": "^12.0.0"
|
||||
"sass-loader": "^12.0.0",
|
||||
"vitest": "^0.32.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
188
src/digital-components/textarea-question/textarea-question.vue
Normal file
188
src/digital-components/textarea-question/textarea-question.vue
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
<template>
|
||||
<div
|
||||
class="textarea-question"
|
||||
:class="(errors && errors.length) || hasError ? 'has-error' : ''">
|
||||
<label
|
||||
:for="inputId"
|
||||
class="form-label">
|
||||
{{ questionText }}
|
||||
<span
|
||||
v-if="!isRequired"
|
||||
class="optional">(Optional)</span>
|
||||
</label>
|
||||
<div class="input-wrapper">
|
||||
<textarea
|
||||
:id="inputId"
|
||||
:ref="inputId"
|
||||
v-model.trim="value"
|
||||
class="form-control"
|
||||
:name="inputId"
|
||||
:rows="[inputRows ?? 3]"
|
||||
:placeholder="placeholderText"
|
||||
:disabled="isDisabled"
|
||||
:required="isRequired"
|
||||
:maxlength="maxLength"
|
||||
:validationRules="validationRules"
|
||||
@paste="trimOnPaste"
|
||||
@drop="trimOnPaste">
|
||||
</textarea>
|
||||
</div>
|
||||
<p class="character-count margin-top-8">
|
||||
{{ characterCount }}/{{ maxLength }} characters remaining
|
||||
</p>
|
||||
<div
|
||||
v-show="errorMessage"
|
||||
class="row my-1 form-test-error">
|
||||
<span
|
||||
class="d-inline-flex mt-0"
|
||||
role="alert">{{ errorMessage }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useField } from 'vee-validate';
|
||||
|
||||
export default {
|
||||
name: 'textarea-question',
|
||||
props: {
|
||||
placeholderText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
inputId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
modelValue: String,
|
||||
isDisabled: Boolean,
|
||||
isRequired: Boolean,
|
||||
hasError: Boolean,
|
||||
validationRules: String,
|
||||
cmsWidgetName: String,
|
||||
maxLength: String,
|
||||
inputRows: Number
|
||||
},
|
||||
emits: ['update:modelValue', 'textareaQuestionEvent.inputIdAssigned'],
|
||||
setup(props) {
|
||||
const propsClone = { ...props };
|
||||
const { modelValue } = propsClone;
|
||||
const initialValue = modelValue ?? '';
|
||||
|
||||
const fieldOptions = {
|
||||
type: 'text',
|
||||
value: modelValue,
|
||||
initialValue
|
||||
};
|
||||
|
||||
const { errorMessage,
|
||||
handleChange,
|
||||
validate,
|
||||
errors }
|
||||
= useField(props.inputId,
|
||||
props.validationRules,
|
||||
fieldOptions);
|
||||
|
||||
return {
|
||||
errorMessage,
|
||||
handleChange,
|
||||
validate,
|
||||
errors
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
characterCount() {
|
||||
return this?.modelValue?.length ?? 0;
|
||||
},
|
||||
questionText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
||||
},
|
||||
value: {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit('update:modelValue', newValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async value(newValue) {
|
||||
const result = await this.validate(newValue, this.validationRules);
|
||||
if (result.valid) {
|
||||
this.handleChange(newValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// TODO do we need to do anything else for this event?
|
||||
this.$emit('textareaQuestionEvent.inputIdAssigned', this.inputId);
|
||||
},
|
||||
methods: {
|
||||
trimOnPaste(evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
const data = evt.type === 'paste' ? (evt.clipboardData || window.clipboardData) : evt.dataTransfer;
|
||||
const value = data.getData('Text')?.trim();
|
||||
|
||||
this.$emit('update:modelValue', value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.textarea-question {
|
||||
label {
|
||||
color: $black;
|
||||
font-weight: 500;
|
||||
}
|
||||
.form-test-error span{
|
||||
color: $red;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
max-height: 5rem;
|
||||
border: 1px solid $gray-500;
|
||||
border-radius: 0.5rem;
|
||||
padding: 12px 16px;
|
||||
&::placeholder {
|
||||
color: $gray-500;
|
||||
}
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
background-color: $gray-100;
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 4px transparent;
|
||||
border: 1px solid $gray-500;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
border: 1px solid $gray-500;
|
||||
box-shadow: 0 0 0 4px $blue-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.optional {
|
||||
color: $gray-550;
|
||||
}
|
||||
|
||||
.character-count {
|
||||
color: $gray-600;
|
||||
font-size: 12px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.margin-top-8 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
395
src/layouts/contact-details/contact-details.spec.js
Normal file
395
src/layouts/contact-details/contact-details.spec.js
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
// Components
|
||||
import contactDetails from '@/layouts/contact-details/contact-details.vue';
|
||||
|
||||
// TODO finish this file
|
||||
|
||||
// Supporting Files
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper';
|
||||
import { useMainStore } from '@/store';
|
||||
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
|
||||
import { nextTick } from 'vue';
|
||||
import { vi } from 'vitest';
|
||||
import baseMixin from '../../mixins/base-mixin';
|
||||
|
||||
// Mock our module for promises.
|
||||
vi.mock('@/helpers/layout-helper.js', () =>
|
||||
({
|
||||
settleAllPromises: vi.fn()
|
||||
}));
|
||||
|
||||
// Mock fetchCmsContentForPage
|
||||
vi.mock('@/helpers/cms-content-helper', () =>
|
||||
({
|
||||
fetchCmsContentForPage: vi.fn()
|
||||
}));
|
||||
|
||||
const baseStoreGettersPageData = () =>
|
||||
({
|
||||
partsOrQuestions: [
|
||||
{
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: []
|
||||
}
|
||||
],
|
||||
contactDetails: [
|
||||
{
|
||||
questionSequence: 1,
|
||||
questionText:
|
||||
'Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?',
|
||||
answers: [
|
||||
{
|
||||
answerResult1: 'DYNAMIC',
|
||||
answerResult2: '1',
|
||||
answerText: 'Yes',
|
||||
nextQuestionSequence: null,
|
||||
answerResult: 'DYNAMIC'
|
||||
},
|
||||
{
|
||||
answerResult1: 'Unknown',
|
||||
answerResult2: '0',
|
||||
answerText: 'No',
|
||||
nextQuestionSequence: null,
|
||||
answerResult: 'Unknown'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
partQuestions: [],
|
||||
questions: [],
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
answerKey: 'Windshield-Single',
|
||||
answerData: null
|
||||
}
|
||||
]
|
||||
});
|
||||
const baseStoreGettersDamage = () =>
|
||||
({
|
||||
partsQuestionAnswers: [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
result: 'FW04848',
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText:
|
||||
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
|
||||
selectedAnswer: '1|nextQuestion|3|Yes',
|
||||
selectedAnswerText: 'Yes',
|
||||
questionNum: 1
|
||||
},
|
||||
{
|
||||
questionText:
|
||||
'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?',
|
||||
selectedAnswer: '2|nextQuestion|3|Yes',
|
||||
selectedAnswerText: 'Yes',
|
||||
questionNum: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
useMainStore().pageData = baseStoreGettersPageData;
|
||||
useMainStore().damage = baseStoreGettersDamage;
|
||||
|
||||
describe('contactDetails.vue', () => {
|
||||
describe('method arePagePrerequisitesValid...', () => {
|
||||
test('Should return true for valid page requisites if pageData exists', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(true);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test('Should return false for valid page requisites if partsOrQuestions in pageData is missing', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
useMainStore().pageData = vi.fn(() =>
|
||||
undefined);
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
// Assert
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test('Should be at least one item in partsOrQuestions', () => {
|
||||
// Arrange
|
||||
useMainStore().pageData = vi.fn(() =>
|
||||
({
|
||||
partsOrQuestions: []
|
||||
}));
|
||||
useMainStore().damage = baseStoreGettersDamage;
|
||||
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
// Assert
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe('watch on selectedAnswers should be set up...', () => {
|
||||
test('Should trigger handleAnswerUpdates if watched data changes', async () => {
|
||||
// Arrange
|
||||
useMainStore().pageData = baseStoreGettersPageData;
|
||||
useMainStore().damage = baseStoreGettersDamage;
|
||||
const { wrapper } = setupMocks({});
|
||||
const spy = vi.spyOn(wrapper.vm, 'handleAnswerUpdates');
|
||||
|
||||
// Act
|
||||
wrapper.setData({
|
||||
selectedAnswers: {
|
||||
'Windshield-Single': {
|
||||
answerResult: 'FW04848',
|
||||
answeredQuestions: [
|
||||
{
|
||||
questionText:
|
||||
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
|
||||
selectedAnswer: '1|nextQuestion|3|Yes',
|
||||
selectedAnswerText: 'Yes',
|
||||
questionNum: 1
|
||||
},
|
||||
{
|
||||
questionText:
|
||||
'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?',
|
||||
selectedAnswer: '2|nextQuestion|3|Yes',
|
||||
selectedAnswerText: 'Yes',
|
||||
questionNum: 2
|
||||
}
|
||||
],
|
||||
index: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
// Assert
|
||||
expect(spy).toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe('forwardButtonAction', () => {
|
||||
test('Should clear out answerData', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
answerData: {
|
||||
answerResult: 'FW04848',
|
||||
answeredQuestions: []
|
||||
},
|
||||
questions: [],
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: [{}]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = vi.fn(() =>
|
||||
({
|
||||
data: []
|
||||
}));
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.questionsData[0].answerData).toEqual({});
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test('Should save to pinia store', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
answerData: {
|
||||
answerResult: 'FW04848',
|
||||
answeredQuestions: []
|
||||
},
|
||||
questions: [],
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: []
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
useMainStore().getPartsOrQuestions = vi.fn(() =>
|
||||
({
|
||||
data: {
|
||||
partsOrQuestions: []
|
||||
}
|
||||
}));
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
await nextTick();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.saveCapabilityQuestionAnswers).toHaveBeenCalled;
|
||||
wrapper.unmount();
|
||||
});
|
||||
test('Should call GET_PART_FROM_CAPABILITY_QUESTION_ANSWER API', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
answerData: {
|
||||
answerResult: 'FW04848',
|
||||
answeredQuestions: []
|
||||
},
|
||||
questions: [],
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: []
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
wrapper.vm.dispatchStoreAction = vi.fn(() =>
|
||||
({
|
||||
data: []
|
||||
}));
|
||||
|
||||
// Act
|
||||
wrapper.vm.forwardButtonAction();
|
||||
|
||||
await nextTick();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.getPartFromCapabilityQuestionAnswer).toHaveBeenCalled;
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
test('Should trigger navigateForward', async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
wrapper.vm.questionsData = [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
answerData: {
|
||||
answerResult: 'FW04848',
|
||||
answeredQuestions: []
|
||||
},
|
||||
questions: [],
|
||||
parts: [
|
||||
{
|
||||
childPartQuestions: []
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
useMainStore().getPartsOrQuestions = vi.fn(() =>
|
||||
({
|
||||
data: {
|
||||
partsOrQuestions: []
|
||||
}
|
||||
}));
|
||||
wrapper.vm.navigateForward = vi.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
mountOptionsMockData = {
|
||||
router: {
|
||||
navigate: vi.fn()
|
||||
},
|
||||
actionList: [
|
||||
{
|
||||
actionName: 'saveCapabilityQuestionAnswers',
|
||||
data: {}
|
||||
},
|
||||
{
|
||||
actionName: 'getPartsOrQuestions',
|
||||
data: {}
|
||||
}
|
||||
],
|
||||
route: {
|
||||
query: {
|
||||
issPage: 'capability-questions'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
computedSwitcher: [
|
||||
{
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
answerData: {
|
||||
answerResult: 'FW04848',
|
||||
answeredQuestions: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
questionsData: {
|
||||
get() {
|
||||
return this.computedSwitcher;
|
||||
},
|
||||
set(val) {
|
||||
this.computedSwitcher = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}) {
|
||||
useMainStore().getPartsOrQuestions = vi.fn(() =>
|
||||
({
|
||||
data: {
|
||||
partsOrQuestions: []
|
||||
}
|
||||
}));
|
||||
const mountOptions = getMountOptions({
|
||||
...mountOptionsMockData,
|
||||
mixins: [baseMixin, vehicleQuestionsMixin]
|
||||
});
|
||||
mountOptions.attachTo = document.body;
|
||||
|
||||
const wrapper = shallowMount(contactDetails, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -1,17 +1,91 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
|
||||
<Form
|
||||
ref="contact-details-form"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget"/>
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="container-fluid pb-2">
|
||||
<p>Placeholder for contact details page</p>
|
||||
<siteSubHeader
|
||||
id="sub-header"
|
||||
class="margin-top-16"
|
||||
cmsWidgetName="SiteSubHeaderWidget" />
|
||||
<textboxQuestion
|
||||
ref="firstName"
|
||||
v-model="firstName"
|
||||
class="margin-top-24"
|
||||
inputId="firstName"
|
||||
cmsWidgetName="FirstNameQuestionWidget"
|
||||
isRequired
|
||||
validationRules="first-name-required" />
|
||||
<textboxQuestion
|
||||
ref="lastName"
|
||||
v-model="lastName"
|
||||
class="margin-top-16"
|
||||
inputId="lastName"
|
||||
cmsWidgetName="LastNameQuestionWidget"
|
||||
isRequired
|
||||
validationRules="last-name-required" />
|
||||
<textboxQuestion
|
||||
ref="email"
|
||||
v-model="email"
|
||||
class="margin-top-16"
|
||||
inputId="email"
|
||||
cmsWidgetName="EmailQuestionWidget"
|
||||
isRequired
|
||||
validationRules="email-address-required|email-address-format" />
|
||||
<textboxQuestion
|
||||
ref="firstName"
|
||||
v-model="phoneNumber"
|
||||
class="margin-top-16"
|
||||
inputId="phoneNumber"
|
||||
cmsWidgetName="PhoneNumberQuestionWidget"
|
||||
isRequired
|
||||
validationRules="phone-number-required|phone-number-format" />
|
||||
<checkbox
|
||||
ref="requestTextUpdates"
|
||||
v-model="requestTextUpdates"
|
||||
class="margin-top-8"
|
||||
checkboxName="requestTextUpdates"
|
||||
buttonID="requestTextUpdates"
|
||||
:checkboxLabel="textContentText" />
|
||||
|
||||
<textareaQuestion
|
||||
v-model="notesForTechnician"
|
||||
class="margin-top-16"
|
||||
inputId="technicianNotes"
|
||||
:isDisabled="false"
|
||||
:isRequired="false"
|
||||
hasError="hasError"
|
||||
cmsWidgetName="NotesQuestionWidget"
|
||||
maxLength="500"
|
||||
inputRows="30" />
|
||||
|
||||
<p class="disclaimer margin-top-24">
|
||||
{{ textUpdateDisclaimerText }} I also agree to Safelite's
|
||||
<textLink
|
||||
class="disclaimer-link"
|
||||
linkType="text"
|
||||
text="Privacy Policy"
|
||||
href="//www.safelite.com/privacy-center"
|
||||
target="_blank" />
|
||||
and
|
||||
<textLink
|
||||
class="disclaimer-link"
|
||||
linkType="text"
|
||||
text="Terms of Use"
|
||||
href="//www.safelite.com/terms-of-use"
|
||||
target="_blank" />.
|
||||
</p>
|
||||
|
||||
<siteFooter
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
ref="siteFooter"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@ForwardClicked="navigateForward"
|
||||
@back-clicked="backButtonAction"
|
||||
/>
|
||||
ref="siteFooter"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@forwardClicked="navigateForward"
|
||||
@backClicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -19,67 +93,132 @@
|
|||
</template>
|
||||
<script>
|
||||
// Components
|
||||
import siteHeader from '@/iss-components/site-header/site-header';
|
||||
import siteFooter from "@/iss-components/site-footer/site-footer";
|
||||
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
|
||||
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
|
||||
import checkbox from '@/ux-components/checkbox/checkbox.vue';
|
||||
import textareaQuestion from '@/digital-components/textarea-question/textarea-question.vue';
|
||||
import textLink from '@/ux-components/text-link/text-link.vue';
|
||||
|
||||
// Supporting files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import { Form } from "vee-validate";
|
||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import { settleAllPromises } from '@/helpers/layout-helper';
|
||||
import { Form, defineRule } from 'vee-validate';
|
||||
import { errorMessages } from '@/constants/error-messages';
|
||||
import BaseFormMixin from '@/mixins/base-form-mixin';
|
||||
import { useMainStore } from '@/store';
|
||||
import { required, regex } from '@/helpers/validation-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 {
|
||||
name: "contact-details",
|
||||
name: 'contact-details',
|
||||
components: {
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
textboxQuestion,
|
||||
checkbox,
|
||||
textareaQuestion,
|
||||
siteFooter,
|
||||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form,
|
||||
textLink
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
data() {
|
||||
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
async beforeRouteEnter(to, from, next)
|
||||
{
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
},];
|
||||
resultKey: 'cmsContent',
|
||||
promise: cmsContentPromise
|
||||
}
|
||||
];
|
||||
|
||||
//use resultMap to populate layout content.
|
||||
let resultMap = await settleAllPromises(promiseResultMap);
|
||||
// use resultMap to populate layout content.
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
firstName: useMainStore().order.customer.firstName,
|
||||
lastName: useMainStore().order.customer.lastName,
|
||||
email: useMainStore().order.customer.emailAddress,
|
||||
phoneNumber: useMainStore().order.customer.phoneNumber,
|
||||
requestTextUpdates: false,
|
||||
notesForTechnician: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
textContentText() {
|
||||
return `${this.getCmsContent('TextContentWidget', 'Text')}*`;
|
||||
},
|
||||
methods:
|
||||
{
|
||||
backButtonAction() {
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
|
||||
forwardButtonAction() {
|
||||
},
|
||||
|
||||
navigateForward() {
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route
|
||||
);
|
||||
},
|
||||
textUpdateDisclaimerText() {
|
||||
return `*${this.getCmsContent('TextUpdateDisclaimerWidget', 'Text')}`;
|
||||
}
|
||||
},
|
||||
methods:
|
||||
{
|
||||
backButtonAction() {
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
components: {
|
||||
siteHeader,
|
||||
siteFooter,
|
||||
Form,
|
||||
|
||||
forwardButtonAction() {
|
||||
this.navigateForward();
|
||||
},
|
||||
|
||||
navigateForward() {
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#sub-header {
|
||||
span {
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
|
||||
.margin-top-24 {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.margin-top-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.margin-top-8 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
font-size: 12px;
|
||||
color: $darker-gray;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.disclaimer-link {
|
||||
text-decoration: none;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in a new issue