Merge branch 'develop' into feature/SSR-669

This commit is contained in:
Katie Kroell 2023-10-20 14:42:52 -04:00
commit beeeed8778
20 changed files with 1944 additions and 790 deletions

View file

@ -162,6 +162,10 @@ const endpoints = Object.freeze({
url: '/order/api/v1/order/save-session/iss', url: '/order/api/v1/order/save-session/iss',
method: 'POST' method: 'POST'
}, },
LoadSession: {
url: '/order/api/v1/order/load-session',
method: 'POST'
},
DuplicateSearch: { DuplicateSearch: {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
url: (accountNumber, policyNumber, phoneNumber) => `/order/api/v1/order/duplicate-check/${accountNumber}/${policyNumber}/${phoneNumber}`, url: (accountNumber, policyNumber, phoneNumber) => `/order/api/v1/order/duplicate-check/${accountNumber}/${policyNumber}/${phoneNumber}`,

View file

@ -734,7 +734,11 @@ export default {
} }
.loader { .loader {
height: 2rem; height: 2rem;
width: calc(100% - 1.5rem); width: 100%;
display: flex;
justify-content: center;
transform: unset;
right: unset;
&::after { &::after {
width: 1.5rem; width: 1.5rem;

View file

@ -5,7 +5,21 @@
* @param {string} stringWithStyleTag * @param {string} stringWithStyleTag
* @returns {string} * @returns {string}
*/ */
export default function stripRteStyle(stringWithStyleTag) { export function stripRteStyle(stringWithStyleTag) {
const regexExp = /[\s*]style="(.*?)"/g; const regexExp = /[\s*]style="(.*?)"/g;
return stringWithStyleTag.replace(regexExp, ''); return stringWithStyleTag.replace(regexExp, '');
} }
/**
* @function toTitleCase
* @summary Returns title cased string version of 'text'
* @param {string} text
* @returns {string}
*/
export function toTitleCase(text) {
const temp = text.toLowerCase().split(' ');
for (let i = 0; i < temp.length; i++) {
temp[i] = temp[i].charAt(0).toUpperCase() + temp[i].slice(1);
}
return temp.join(' ');
}

View file

@ -36,7 +36,7 @@ import {
getRouterLinkHtmlStringFromCopy getRouterLinkHtmlStringFromCopy
} from '@/helpers/cms-content-helper'; } from '@/helpers/cms-content-helper';
import stripRteStyle from '@/helpers/text-helper'; import { stripRteStyle } from '@/helpers/text-helper';
export default { export default {
name: 'site-sub-header', name: 'site-sub-header',

View file

@ -1,11 +1,11 @@
// Components // Components
import { shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import contactDetails from '@/layouts/contact-details/contact-details.vue'; import contactDetails from '@/layouts/contact-details/contact-details.vue';
// Supporting Files // Supporting Files
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { getRandomString, getRandomInt, getRandomBoolean } from '@/helpers/data-generation.js'; import { getRandomString, getRandomInt, getRandomBoolean } from '@/helpers/data-generation.js';
import { createTestingPinia } from '@pinia/testing';
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js'; import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
import { useMainStore } from '@/store/index.js'; import { useMainStore } from '@/store/index.js';
@ -267,9 +267,6 @@ describe('contactDetails.vue', () => {
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
router: { router: {
navigate: jest.fn() navigate: jest.fn()
},
global: {
plugins: [createTestingPinia()]
} }
}); });
const wrapper = shallowMount(contactDetails, mountOptions); const wrapper = shallowMount(contactDetails, mountOptions);
@ -302,4 +299,89 @@ describe('contactDetails.vue', () => {
}); });
}); });
}); });
test('Mocked store with no contact info yields expected data', () => {
// Arrange
const mountOptions = getMountOptions();
const firstName = getRandomString(4, 15);
const lastName = getRandomString(4, 15);
const emailAddress = getRandomString(10, 20);
const phoneNumber = getRandomInt(1000000000, 9999999999);
const mainInitialState = {
order: {
customer: {
firstName,
lastName,
emailAddress,
phoneNumber
},
contactInfo: {
firstName: null,
lastName: null,
emailAddress: null,
phoneNumber: null,
requestTextUpdates: null,
notesForTechnician: null
}
}
};
mountOptions.global = {
plugins: [createTestingPinia({
initialState: {
main: mainInitialState
}
})]
};
const wrapper = shallowMount(contactDetails, mountOptions);
// Assert
expect(wrapper.vm.firstName).toBe(firstName);
expect(wrapper.vm.lastName).toBe(lastName);
expect(wrapper.vm.emailAddress).toBe(emailAddress);
expect(wrapper.vm.phoneNumber).toBe(phoneNumber);
});
test('Mock store with contact info yields expected data', () => {
// Arrange
const customer = {
firstName: getRandomString(4, 15),
lastName: getRandomString(4, 15),
emailAddress: getRandomString(10, 20),
phoneNumber: getRandomInt(1000000000, 9999999999)
};
const contactInfo = {
firstName: getRandomString(4, 15),
lastName: getRandomString(4, 15),
emailAddress: getRandomString(10, 20),
phoneNumber: getRandomInt(1000000000, 9999999999),
requestTextUpdates: getRandomBoolean(),
notesForTechnician: getRandomString(50, 100)
};
const mainInitialState = {
order: {
customer,
contactInfo
}
};
const mountOptions = getMountOptions();
mountOptions.global = {
plugins: [createTestingPinia({
initialState: {
main: mainInitialState
}
})]
};
const wrapper = shallowMount(contactDetails, mountOptions);
// Assert
expect(wrapper.vm.firstName).toBe(contactInfo.firstName);
expect(wrapper.vm.lastName).toBe(contactInfo.lastName);
expect(wrapper.vm.emailAddress).toBe(contactInfo.emailAddress);
expect(wrapper.vm.phoneNumber).toBe(contactInfo.phoneNumber);
expect(wrapper.vm.requestTextUpdates).toBe(contactInfo.requestTextUpdates);
expect(wrapper.vm.notesForTechnician).toBe(contactInfo.notesForTechnician);
});
}); });

View file

@ -1,12 +1,13 @@
// Components // Components
import { shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import duplicateCheck from '@/layouts/duplicate-check/duplicate-check.vue'; import duplicateCheck from '@/layouts/duplicate-check/duplicate-check.vue';
// Supporting Files // Supporting Files
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { createTestingPinia } from '@pinia/testing';
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js'; import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
import { getRandomString } from '@/helpers/data-generation.js'; import { getRandomString } from '@/helpers/data-generation.js';
import { useMainStore } from '@/store';
const duplicateOrderText = 'Finish Existing Claim'; const duplicateOrderText = 'Finish Existing Claim';
@ -52,279 +53,277 @@ describe('duplicateCheck.vue', () => {
// Assert // Assert
expect(footer.exists()).toBeTruthy(); expect(footer.exists()).toBeTruthy();
}); });
// TODO update or remove
// test('Mocked store with no contact info yields expected data', () => {
// // Arrange
// const mountOptions = getMountOptions();
// const firstName = getRandomString(4, 15);
// const lastName = getRandomString(4, 15);
// const emailAddress = getRandomString(10, 20);
// const phoneNumber = getRandomInt(1000000000, 9999999999);
// const mainInitialState = {
// order: {
// customer: {
// firstName,
// lastName,
// emailAddress,
// phoneNumber
// }
// }
// };
// mountOptions.global = {
// plugins: [createTestingPinia({
// initialState: {
// main: mainInitialState
// }
// })]
// };
// const wrapper = shallowMount(contactDetails, mountOptions);
// // Assert
// expect(wrapper.vm.firstName).toBe(firstName);
// expect(wrapper.vm.lastName).toBe(lastName);
// expect(wrapper.vm.emailAddress).toBe(emailAddress);
// expect(wrapper.vm.phoneNumber).toBe(phoneNumber);
// });
// test('Mock store with contact info yields expected data', () => {
// // Arrange
// const customer = {
// firstName: getRandomString(4, 15),
// lastName: getRandomString(4, 15),
// emailAddress: getRandomString(10, 20),
// phoneNumber: getRandomInt(1000000000, 9999999999)
// };
// const contactInfo = {
// firstName: getRandomString(4, 15),
// lastName: getRandomString(4, 15),
// emailAddress: getRandomString(10, 20),
// phoneNumber: getRandomInt(1000000000, 9999999999),
// requestTextUpdates: getRandomBoolean(),
// notesForTechnician: getRandomString(50, 100)
// };
// const mainInitialState = {
// order: {
// customer,
// contactInfo
// }
// };
// const mountOptions = getMountOptions();
// mountOptions.global = {
// plugins: [createTestingPinia({
// initialState: {
// main: mainInitialState
// }
// })]
// };
// const wrapper = shallowMount(contactDetails, mountOptions);
// // Assert
// expect(wrapper.vm.firstName).toBe(contactInfo.firstName);
// expect(wrapper.vm.lastName).toBe(contactInfo.lastName);
// expect(wrapper.vm.emailAddress).toBe(contactInfo.emailAddress);
// expect(wrapper.vm.phoneNumber).toBe(contactInfo.phoneNumber);
// expect(wrapper.vm.requestTextUpdates).toBe(contactInfo.requestTextUpdates);
// expect(wrapper.vm.notesForTechnician).toBe(contactInfo.notesForTechnician);
// });
}); });
describe('duplicateOrders computed', () => { describe('computed properties', () => {
test('duplicateOrders in store undefined => returns empty list', () => { describe('duplicateOrders computed', () => {
// Arrange test('duplicateOrders in store undefined => returns empty list', () => {
const mountOptions = getMountOptions({ // Arrange
router: { navigate: jest.fn() } const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const mainInitialState = {
applicationUser: {
duplicateOrders: undefined
}
};
mountOptions.global.plugins = [createTestingPinia({
initialState: {
main: mainInitialState
}
})];
const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert
expect(wrapper.vm.duplicateOrders.length).toBe(0);
}); });
test('duplicateOrders in store empty => returns empty list', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const mainInitialState = { const mainInitialState = {
applicationUser: { applicationUser: {
duplicateOrders: undefined duplicateOrders: []
} }
}; };
mountOptions.global.plugins = [createTestingPinia({ mountOptions.global.plugins = [createTestingPinia({
initialState: { initialState: {
main: mainInitialState main: mainInitialState
} }
})]; })];
const wrapper = shallowMount(duplicateCheck, mountOptions); const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert // Assert
expect(wrapper.vm.duplicateOrders.length).toBe(0); expect(wrapper.vm.duplicateOrders.length).toBe(0);
});
test('duplicateOrders in store empty => returns empty list', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
}); });
test('duplicateOrder in store with null vehicle year => returns order with only date in subtext', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const mainInitialState = { const referralNumber = getRandomString(6, 6);
applicationUser: { const mainInitialState = {
duplicateOrders: [] applicationUser: {
} duplicateOrders: [
}; {
mountOptions.global.plugins = [createTestingPinia({ vehicleYear: null,
initialState: { vehicleMake: getRandomString(5, 5),
main: mainInitialState vehicleModel: getRandomString(5, 5),
} responseDate: '1990-09-23T01:12:34',
})]; referralNumber
}
]
}
};
mountOptions.global.plugins = [createTestingPinia({
initialState: {
main: mainInitialState
}
})];
const expectedSubtext = '9/23/1990';
const wrapper = shallowMount(duplicateCheck, mountOptions); const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert // Assert
expect(wrapper.vm.duplicateOrders.length).toBe(0); expect(wrapper.vm.duplicateOrders.length).toBe(1);
}); expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
test('duplicateOrder in store with null vehicle year => returns order with only date in subtext', () => { Text: duplicateOrderText,
// Arrange Name: referralNumber,
const mountOptions = getMountOptions({ SubText: expectedSubtext
router: { navigate: jest.fn() } });
}); });
test('duplicateOrder in store with null vehicle make => returns order with only date subtext', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const date = getRandomString(9, 9); const referralNumber = getRandomString(6, 6);
const referralNumber = getRandomString(6, 6); const mainInitialState = {
const mainInitialState = { applicationUser: {
applicationUser: { duplicateOrders: [
duplicateOrders: [ {
{ vehicleYear: getRandomString(6, 6),
vehicleYear: null, vehicleMake: null,
vehicleMake: getRandomString(5, 5), vehicleModel: getRandomString(5, 5),
vehicleModel: getRandomString(5, 5), responseDate: '2004-11-01T01:12:34',
dateOfLoss: date, referralNumber
referralNumber }
} ]
] }
} };
}; mountOptions.global.plugins = [createTestingPinia({
mountOptions.global.plugins = [createTestingPinia({ initialState: {
initialState: { main: mainInitialState
main: mainInitialState }
} })];
})]; const expectedSubtext = '11/1/2004';
const wrapper = shallowMount(duplicateCheck, mountOptions); const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert // Assert
expect(wrapper.vm.duplicateOrders.length).toBe(1); expect(wrapper.vm.duplicateOrders.length).toBe(1);
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({ expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText, Text: duplicateOrderText,
Name: referralNumber, Name: referralNumber,
SubText: date SubText: expectedSubtext
});
});
test('duplicateOrder in store with null vehicle model => returns order with only date subtext', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const referralNumber = getRandomString(6, 6);
const mainInitialState = {
applicationUser: {
duplicateOrders: [
{
vehicleYear: getRandomString(6, 6),
vehicleMake: getRandomString(6, 6),
vehicleModel: null,
responseDate: '1999-01-15T01:12:34',
referralNumber
}
]
}
};
mountOptions.global.plugins = [createTestingPinia({
initialState: {
main: mainInitialState
}
})];
const expectedSubtext = '1/15/1999';
const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert
expect(wrapper.vm.duplicateOrders.length).toBe(1);
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText,
Name: referralNumber,
SubText: expectedSubtext
});
});
test('duplicateOrder in store with all vehicle info => returns order with year, make, model and date in subtext', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const referralNumber = getRandomString(6, 6);
const mainInitialState = {
applicationUser: {
duplicateOrders: [
{
vehicleYear: 'YEAR',
vehicleMake: 'make',
vehicleModel: 'MoDel',
responseDate: '2018-03-01T01:12:34',
referralNumber
}
]
}
};
mountOptions.global.plugins = [createTestingPinia({
initialState: {
main: mainInitialState
}
})];
const expectedVehicle = 'Year Make Model';
const expectedDate = '3/1/2018';
const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert
expect(wrapper.vm.duplicateOrders.length).toBe(1);
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText,
Name: referralNumber,
SubText: `${expectedVehicle}, ${expectedDate}`
});
}); });
}); });
test('duplicateOrder in store with null vehicle make => returns order with only date subtext', () => { describe('getNewOrderSelectionName', () => {
// Arrange test('answersFromCms null => returns empty string', () => {
const mountOptions = getMountOptions({ // Arrange
router: { navigate: jest.fn() } const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const answersFromCmsValue = null;
mountOptions.mixins = [{
methods: {
getCmsContent: jest.fn().mockImplementation((_, label) => (label === 'Answers' ? answersFromCmsValue : ''))
}
}];
const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert
expect(wrapper.vm.getNewOrderSelectionName).toBe('');
}); });
test('answersFromCms empty list => returns empty string', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const answersFromCmsValue = [];
mountOptions.mixins = [{
methods: {
getCmsContent: jest.fn().mockImplementation((_, label) => (label === 'Answers' ? answersFromCmsValue : ''))
}
}];
const date = getRandomString(9, 9); const wrapper = shallowMount(duplicateCheck, mountOptions);
const referralNumber = getRandomString(6, 6);
const mainInitialState = {
applicationUser: {
duplicateOrders: [
{
vehicleYear: getRandomString(6, 6),
vehicleMake: null,
vehicleModel: getRandomString(5, 5),
dateOfLoss: date,
referralNumber: referralNumber
}
]
}
};
mountOptions.global.plugins = [createTestingPinia({
initialState: {
main: mainInitialState
}
})];
const wrapper = shallowMount(duplicateCheck, mountOptions); // Assert
expect(wrapper.vm.getNewOrderSelectionName).toBe('');
// Assert
expect(wrapper.vm.duplicateOrders.length).toBe(1);
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText,
Name: referralNumber,
SubText: date
}); });
}); test('answersFromCms non-empty list whose first item has no Name property => returns empty string', () => {
test('duplicateOrder in store with null vehicle model => returns order with only date subtext', () => { // Arrange
// Arrange const mountOptions = getMountOptions({
const mountOptions = getMountOptions({ router: { navigate: jest.fn() }
router: { navigate: jest.fn() } });
const answersFromCmsValue = [{ test: getRandomString(6, 6) }];
mountOptions.mixins = [{
methods: {
getCmsContent: jest.fn().mockImplementation((_, label) => (label === 'Answers'
? answersFromCmsValue
: ''))
}
}];
const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert
expect(wrapper.vm.getNewOrderSelectionName).toBe('');
}); });
test('answersFromCms first item has Name property => returns expected', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const expectedName = getRandomString(6, 6);
const answersFromCmsValue = [{ Name: expectedName }];
mountOptions.mixins = [{
methods: {
getCmsContent: jest.fn().mockImplementation((_, label) => (label === 'Answers'
? answersFromCmsValue
: ''))
}
}];
const date = getRandomString(9, 9); const wrapper = shallowMount(duplicateCheck, mountOptions);
const referralNumber = getRandomString(6, 6);
const mainInitialState = {
applicationUser: {
duplicateOrders: [
{
vehicleYear: getRandomString(6, 6),
vehicleMake: getRandomString(6, 6),
vehicleModel: null,
dateOfLoss: date,
referralNumber: referralNumber
}
]
}
};
mountOptions.global.plugins = [createTestingPinia({
initialState: {
main: mainInitialState
}
})];
const wrapper = shallowMount(duplicateCheck, mountOptions); // Assert
expect(wrapper.vm.getNewOrderSelectionName).toBe(expectedName);
// Assert
expect(wrapper.vm.duplicateOrders.length).toBe(1);
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText,
Name: referralNumber,
SubText: date
});
});
test('duplicateOrder in store with all vehicle info => returns order with year, make, model and date in subtext', () => {
// Arrange
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
const year = getRandomString(6, 6,);
const make = getRandomString(6, 6);
const model = getRandomString(6, 6);
const date = getRandomString(9, 9);
const referralNumber = getRandomString(6, 6);
const mainInitialState = {
applicationUser: {
duplicateOrders: [
{
vehicleYear: year,
vehicleMake: make,
vehicleModel: model,
dateOfLoss: date,
referralNumber: referralNumber
}
]
}
};
mountOptions.global.plugins = [createTestingPinia({
initialState: {
main: mainInitialState
}
})];
const wrapper = shallowMount(duplicateCheck, mountOptions);
// Assert
expect(wrapper.vm.duplicateOrders.length).toBe(1);
expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
Text: duplicateOrderText,
Name: referralNumber,
SubText: `${year} ${make} ${model}, ${date}`
}); });
}); });
}); });
@ -348,7 +347,88 @@ describe('duplicateCheck.vue', () => {
}); });
describe('forwardButtonAction', () => { describe('forwardButtonAction', () => {
test('policyLookupSuccessful true and policy vehicles returned => CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES', () => { test('Selected duplicate => load session called', async () => {
// Arrange
const newOrderSelectionName = getRandomString(6, 6);
const selectedAnswer = getRandomString(6, 6);
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
mountOptions.mixins = [{
methods: {
getCmsContent: jest.fn().mockImplementation((_, label) => (label === 'Answers'
? [{ Name: newOrderSelectionName }]
: ''))
}
}];
const wrapper = shallowMount(duplicateCheck, mountOptions);
wrapper.setData({ selectedAnswer });
useMainStore().loadSession = jest.fn().mockImplementation(() => Promise.resolve({}));
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.mainStore.loadSession).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
});
test('Selected new order => load session not called', async () => {
// Arrange
const newOrderSelectionName = getRandomString(6, 6);
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
mountOptions.mixins = [{
methods: {
getCmsContent: jest.fn().mockImplementation((_, label) => (label === 'Answers'
? [{ Name: newOrderSelectionName }]
: ''))
}
}];
const wrapper = shallowMount(duplicateCheck, mountOptions);
wrapper.setData({ selectedAnswer: newOrderSelectionName });
useMainStore().loadSession = jest.fn().mockImplementation(() => Promise.resolve({}));
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.mainStore.loadSession).toHaveBeenCalledTimes(0);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
});
test('Load session throws error => still navigate forward', async () => {
// Arrange
const newOrderSelectionName = getRandomString(6, 6);
const selectedAnswer = getRandomString(6, 6);
const mountOptions = getMountOptions({
router: { navigate: jest.fn() }
});
mountOptions.mixins = [{
methods: {
getCmsContent: jest.fn().mockImplementation((_, label) => (label === 'Answers'
? [{ Name: newOrderSelectionName }]
: ''))
}
}];
const wrapper = shallowMount(duplicateCheck, mountOptions);
wrapper.setData({ selectedAnswer });
const error = 'load session error';
useMainStore().loadSession = jest.fn().mockImplementation(() => Promise.reject(error));
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.mainStore.loadSession).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
});
test('policyLookupSuccessful true and policy vehicles returned => CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES', async () => {
// Arrange // Arrange
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
router: { navigate: jest.fn() } router: { navigate: jest.fn() }
@ -358,7 +438,7 @@ describe('duplicateCheck.vue', () => {
order: { order: {
policy: { policy: {
policyLookupSuccessful: true, policyLookupSuccessful: true,
vehicles: [{test: 'a'}] vehicles: [{ test: 'a' }]
} }
} }
}; };
@ -371,19 +451,19 @@ describe('duplicateCheck.vue', () => {
const wrapper = shallowMount(duplicateCheck, mountOptions); const wrapper = shallowMount(duplicateCheck, mountOptions);
// Act // Act
wrapper.vm.forwardButtonAction(); await wrapper.vm.forwardButtonAction();
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate) expect(wrapper.vm.$router.navigate)
.toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, undefined); .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, undefined);
}); });
test('policyLookupSuccessful true and no policy vehicles returned => CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES', () => { test('policyLookupSuccessful true and no policy vehicles returned => CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES', async () => {
// Arrange // Arrange
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
router: { navigate: jest.fn() } router: { navigate: jest.fn() }
}); });
const mainInitialState = { const mainInitialState = {
order: { order: {
policy: { policy: {
@ -401,19 +481,19 @@ describe('duplicateCheck.vue', () => {
const wrapper = shallowMount(duplicateCheck, mountOptions); const wrapper = shallowMount(duplicateCheck, mountOptions);
// Act // Act
wrapper.vm.forwardButtonAction(); await wrapper.vm.forwardButtonAction();
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
expect(wrapper.vm.$router.navigate) expect(wrapper.vm.$router.navigate)
.toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, undefined); .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, undefined);
}); });
test('policyLookupSuccessful false => CLICKED_FORWARD_POLICY_UNVERIFIED', () => { test('policyLookupSuccessful false => CLICKED_FORWARD_POLICY_UNVERIFIED', async () => {
// Arrange // Arrange
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
router: { navigate: jest.fn() } router: { navigate: jest.fn() }
}); });
const mainInitialState = { const mainInitialState = {
order: { order: {
policy: { policy: {
@ -430,7 +510,7 @@ describe('duplicateCheck.vue', () => {
const wrapper = shallowMount(duplicateCheck, mountOptions); const wrapper = shallowMount(duplicateCheck, mountOptions);
// Act // Act
wrapper.vm.forwardButtonAction(); await wrapper.vm.forwardButtonAction();
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1); expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
@ -439,4 +519,4 @@ describe('duplicateCheck.vue', () => {
}); });
}); });
}); });
}); });

View file

@ -42,6 +42,7 @@
<script> <script>
// Components // Components
import { Form } from 'vee-validate';
import siteHeader from '@/iss-components/site-header/site-header.vue'; import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue'; import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
@ -49,10 +50,10 @@ import buttonQuestion from '@/digital-components/button-question/button-question
// Supporting files // Supporting files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper.js'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper.js';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store/index.js'; import { useMainStore } from '@/store/index.js';
import globalRules from '@/constants/global-rules.js'; import globalRules from '@/constants/global-rules.js';
import { toTitleCase } from '@/helpers/text-helper.js';
export default { export default {
name: 'duplicate-check', name: 'duplicate-check',
@ -74,6 +75,7 @@ export default {
}, },
data() { data() {
return { return {
selectedAnswer: '',
widget: { widget: {
siteHeader: 'SiteHeaderWidget', siteHeader: 'SiteHeaderWidget',
siteSubHeader: 'SiteSubHeaderWidget', siteSubHeader: 'SiteSubHeaderWidget',
@ -92,6 +94,9 @@ export default {
answersFromCms() { answersFromCms() {
return this.getCmsContent(this.widget.existingOrNewQuestion, 'Answers') ?? []; return this.getCmsContent(this.widget.existingOrNewQuestion, 'Answers') ?? [];
}, },
getNewOrderSelectionName() {
return this.answersFromCms?.[0]?.Name ?? '';
},
duplicateOrders() { duplicateOrders() {
const duplicateOrderText = 'Finish Existing Claim'; const duplicateOrderText = 'Finish Existing Claim';
const orders = useMainStore().applicationUser.duplicateOrders; const orders = useMainStore().applicationUser.duplicateOrders;
@ -100,14 +105,15 @@ export default {
? `${o.vehicleYear} ${o.vehicleMake} ${o.vehicleModel}` ? `${o.vehicleYear} ${o.vehicleMake} ${o.vehicleModel}`
: null; : null;
const subtext = vehicle && o.dateOfLoss const dateOfLoss = o.responseDate == null ? '' : new Date(o.responseDate).toLocaleDateString();
? `${vehicle}, ${o.dateOfLoss}` const subtext = vehicle && o.responseDate
: (vehicle ?? '').concat(o.dateOfLoss ?? ''); ? `${vehicle}, ${dateOfLoss}`
: (vehicle ?? '').concat(dateOfLoss);
return { return {
Text: duplicateOrderText, Text: duplicateOrderText,
Name: o.referralNumber, Name: o.referralNumber,
SubText: subtext SubText: toTitleCase(subtext)
}; };
}) ?? []; }) ?? [];
}, },
@ -125,7 +131,16 @@ export default {
/** /**
* @summary Steps to perform when forward button clicked. * @summary Steps to perform when forward button clicked.
*/ */
forwardButtonAction() { async forwardButtonAction() {
if (this.selectedAnswer !== this.getNewOrderSelectionName) {
await useMainStore().loadSession()
.then(() => {}, () => {})
.finally(() => { this.navigateForward(); });
} else {
this.navigateForward();
}
},
navigateForward() {
if (useMainStore().order.policy.policyLookupSuccessful) { if (useMainStore().order.policy.policyLookupSuccessful) {
const policyVehicles = useMainStore().order.policy.vehicles ?? []; const policyVehicles = useMainStore().order.policy.vehicles ?? [];
if (policyVehicles.length > 0) { if (policyVehicles.length > 0) {
@ -168,6 +183,9 @@ export default {
margin-top: map-get($spacers, 4); margin-top: map-get($spacers, 4);
margin-bottom: map-get($spacers, 2); margin-bottom: map-get($spacers, 2);
} }
.form-test-error{
margin-top: 0 !important;
}
} }
</style> </style>

View file

@ -1,30 +1,10 @@
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
const getAlertReasons = async (ctu) => { export async function getAlertReasons(ctu) {
const store = useMainStore(); const store = useMainStore();
const alertReasons = await store.getAlertReasonsByCtu(ctu); const alertReasons = await store.getAlertReasonsByCtu(ctu);
return Promise.resolve(alertReasons); return Promise.resolve(alertReasons);
};
// This function will go away after testing.
// The Service already went through testing and had these removed from it.
export async function mockGetAlertReasons(ctu) {
let retList = [];
if (ctu === '01853') { // Ocala, FL 34470
retList = [
'Hurricane', 'ExtremeTemperature'
];
} else if (ctu === '01814') { // Phoenix, AZ 85026
retList = [
'ExtremeTemperature'
];
} else if (ctu === '01845') { // Raleigh, NC 27601
retList = [
'Hurricane'
];
}
return Promise.resolve(retList);
} }
export function calcDaysBetweenDates(dateString1, dateString2) { export function calcDaysBetweenDates(dateString1, dateString2) {
@ -90,5 +70,3 @@ export function getDisplayTextForDurationLength(durationMinimum, durationMaximum
return `${durationText} ${unitText}`; return `${durationText} ${unitText}`;
} }
export default getAlertReasons;

View file

@ -9,7 +9,7 @@
</template> </template>
<script> <script>
import alert from '@/ux-components/alert/alert.vue'; import alert from '@/ux-components/alert/alert.vue';
import { mockGetAlertReasons } from '@/layouts/schedule-page/helpers/schedule-helper'; import { getAlertReasons } from '@/layouts/schedule-page/helpers/schedule-helper';
export default { export default {
name: 'location-alerts', name: 'location-alerts',
@ -44,7 +44,7 @@ export default {
if (providerCtu) { if (providerCtu) {
ctuToUse = providerCtu; ctuToUse = providerCtu;
} }
return mockGetAlertReasons(ctuToUse); // Change to getAlertReasons after testing. return getAlertReasons(ctuToUse);
}, },
initializeComponent(initialData) { initializeComponent(initialData) {
this.alertReasons = initialData; this.alertReasons = initialData;

View file

@ -6,11 +6,50 @@ import { createTestingPinia } from '@pinia/testing';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { useMainStore } from '@/store/index.js'; import { useMainStore } from '@/store/index.js';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
// Mock fetchCmsContentForPage
jest.mock('@/helpers/cms-content-helper', () => ({
fetchCmsContentForPage: jest.fn()
}));
const mockMixin = { const mockMixin = {
methods: { methods: {
getCmsContent: jest.fn().mockImplementation(() => ''), getCmsContent: jest.fn().mockImplementation(() => ''),
setCmsContent: jest.fn() setCmsContent: jest.fn(),
dispatchStoreAction: jest.fn().mockImplementation((storeAction) => {
if (storeAction === 'priceOrderItemsAndSaveServerData') {
return Promise.resolve([
{
partNumber: 'EARLY BIRD',
description: null,
partType: 'EARLY BIRD',
laborAmount: 0,
sellingPrice: 14.99,
kitPrice: 0
}
]);
}
if (storeAction === 'saveSupportingItemsSuppressingStateResetting') {
return Promise.resolve([
{
partNumber: 'EARLY BIRD',
description: null,
partType: 'EARLY BIRD',
laborAmount: 0,
sellingPrice: 14.99,
kitPrice: 0
}
]);
}
return {
data: {
estimatedServiceMinutesMinimum: 90,
estimatedServiceMinutesMaximum: 120,
days: []
}
};
})
} }
}; };
@ -40,10 +79,6 @@ function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
mountOptions.global.stubs = { mountOptions.global.stubs = {
siteFooter: footerStub, siteFooter: footerStub,
siteHeader: true,
recalModal: true,
contentGroupModal: true,
alert: true,
loadingModal: loadingModalStub loadingModal: loadingModalStub
}; };
@ -102,6 +137,9 @@ beforeEach(() => {
}); });
useMainStore(testingPinia); useMainStore(testingPinia);
}); });
afterEach(() => {
jest.clearAllMocks();
});
describe('schedule-page.vue', () => { describe('schedule-page.vue', () => {
describe('Initial Load', () => { describe('Initial Load', () => {
@ -138,17 +176,6 @@ describe('schedule-page.vue', () => {
// Assert // Assert
expect(arePagePrerequisitesValid).toBeFalsy(); expect(arePagePrerequisitesValid).toBeFalsy();
}); });
test('Should fail arePagePrerequisitesValid without isInsurance', () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.mainStore.payment.isInsurance = null;
// Act
const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
// Assert
expect(arePagePrerequisitesValid).toBe(false);
});
test('Should fail arePagePrerequisitesValid if supportingItems is null', async () => { test('Should fail arePagePrerequisitesValid if supportingItems is null', async () => {
// Arrange // Arrange
const { wrapper } = getShallowMountedComponent(); const { wrapper } = getShallowMountedComponent();
@ -171,6 +198,88 @@ describe('schedule-page.vue', () => {
// Assert // Assert
expect(arePagePrerequisitesValid).toBe(false); expect(arePagePrerequisitesValid).toBe(false);
}); });
test('should return newShopTimeSlots when getAvailableDatesMethod is called', async () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.selectableDatesData = {
days: []
};
const store = useMainStore();
store.getShopTimeSlots.mockImplementation(() => ({
data: {
estimatedServiceMinutesMinimum: 90,
estimatedServiceMinutesMaximum: 120,
days: [
{
date: '2023-12-01',
timeSlots: [
{
id: '06747-01820-S-B*20424*7 AM',
startTime: '07:00',
endTime: '08:00',
offerPremium: false
}
]
}
]
}
}));
// Act
const newShopTimeSlots = await wrapper.vm.getAvailableDatesMethod(
'2023-01-01',
'2023-01-31'
);
// Assert
expect(newShopTimeSlots).toStrictEqual({
days: [
{
date: '2023-12-01',
timeSlots: [
{
endTime: '08:00',
id: '06747-01820-S-B*20424*7 AM',
offerPremium: false,
startTime: '07:00'
}
]
}
],
estimatedServiceMinutesMinimum: 90,
estimatedServiceMinutesMaximum: 120
});
});
test('Should call API service in days of 34 or less when getAvailableDatesMethod is called with large date ranges', async () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.selectableDatesData = {
days: []
};
const store = useMainStore();
store.getShopTimeSlots.mockImplementation(() => ({
data: {
estimatedServiceMinutesMinimum: 90,
estimatedServiceMinutesMaximum: 120,
days: []
}
}));
// Act
await wrapper.vm.getAvailableDates.call(
wrapper.vm,
'2023-01-01',
'2023-03-31',
'Inshop',
'123'
);
// Assert
// 2023-01-01 --> 2023-02-05
// 2023-02-06 --> 2023-03-12
// 2023-03-13 --> 2023-03-31
expect(store.getShopTimeSlots).toHaveBeenCalledTimes(3);
});
}); });
describe('Rendering', () => { describe('Rendering', () => {
test('Schedule page loads', () => { test('Schedule page loads', () => {
@ -181,4 +290,128 @@ describe('schedule-page.vue', () => {
expect(wrapper).toBeTruthy(); expect(wrapper).toBeTruthy();
}); });
}); });
describe('schedule page methods...', () => {
test('getServiceZipCtuCodeFromStore should return zipCodeCtu', () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.selectableDatesData = {
days: []
};
// Act
const testValue = wrapper.vm.getServiceZipCtuCodeFromStore();
// Assert
expect(testValue).toStrictEqual('01234');
});
test('getDisplayTextForMilitaryTime should return the correctly formatted string', () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.selectableDatesData = {
days: []
};
const timeInput1 = '15:00';
const timeInput2 = '15:30';
// Act
const testOutput1 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput1);
const testOutput2 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput2);
const testOutput3 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput1, true);
const testOutput4 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput2, true);
// Assert
expect(testOutput1).toBe('3:00 PM');
expect(testOutput2).toBe('3:30 PM');
expect(testOutput3).toBe('3 PM');
expect(testOutput4).toBe('3:30 PM');
});
});
test('forwardButtonAction should call route method navigateWithoutSaving', async () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.$router.navigate = jest.fn(() => ({}));
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
test('for mobile appts, updateSupportingItems should call store action to save supporting items', async () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE;
wrapper.vm.mobilePremiumAppointmentFee = 14.99;
wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = true;
wrapper.vm.mainStore.lineItems.supportingItems = [
{
partNumber: 'EARLY BIRD',
description: null,
partType: 'EARLY BIRD',
laborAmount: 0,
sellingPrice: 0,
kitPrice: 0
}
];
const store = useMainStore();
// Act
await wrapper.vm.updateSupportingItems();
// Assert
expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(1);
expect(wrapper.vm.mainStore.lineItems.supportingItems)
.toEqual(expect.arrayContaining([
expect.objectContaining({
partType: 'EARLY BIRD'
})
]));
});
test(
'for Inshop appts, updateSupportingItems should call store action to save supporting items WITHOUT the EARLY BIRD supporting item',
async () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP;
wrapper.vm.mobilePremiumAppointmentFee = 14.99;
wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = true;
wrapper.vm.mainStore.lineItems.supportingItems = [
{
partNumber: 'EARLY BIRD',
description: null,
partType: 'EARLY BIRD',
laborAmount: 0,
sellingPrice: 0,
kitPrice: 0
}
];
const store = useMainStore();
// Act
await wrapper.vm.updateSupportingItems();
// Assert
expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(1);
expect(wrapper.vm.mainStore.lineItems.supportingItems)
.not.toEqual(expect.arrayContaining([
expect.objectContaining({
partType: 'EARLY BIRD'
})
]));
}
);
test('if no EARLY BIRD supporting item, then updateSupportingItems should NOT call store action', async () => {
// Arrange
const { wrapper } = getShallowMountedComponent();
wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE;
wrapper.vm.mobilePremiumAppointmentFee = 14.99;
wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = false;
wrapper.vm.mainStore.lineItems.supportingItems = [];
const store = useMainStore();
// Act
await wrapper.vm.updateSupportingItems();
// Assert
expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(0);
});
}); });

View file

@ -328,14 +328,13 @@ export default {
&& ((serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE && ((serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|| serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) || serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP)
|| serviceLocation.provider.providerNumber); || serviceLocation.provider.providerNumber);
const paymentInfo = useMainStore().payment.isInsurance !== null;
const supportingItems = useMainStore().lineItems.supportingItems !== null; const supportingItems = useMainStore().lineItems.supportingItems !== null;
const damageInfo = const damageInfo =
useMainStore().order.damage.isRepair useMainStore().order.damage.isRepair
|| (useMainStore().order.lineItems?.glassParts != null || (useMainStore().order.lineItems?.glassParts != null
&& useMainStore().order.lineItems.glassParts.length > 0); && useMainStore().order.lineItems.glassParts.length > 0);
return serviceLocationPreReqs && paymentInfo && supportingItems && damageInfo; return serviceLocationPreReqs && supportingItems && damageInfo;
}, },
setData(initialShopTimeSlotsResponse, premiumFeeWithPriceResponse) { setData(initialShopTimeSlotsResponse, premiumFeeWithPriceResponse) {
this.selectableDatesData = initialShopTimeSlotsResponse; this.selectableDatesData = initialShopTimeSlotsResponse;
@ -437,14 +436,14 @@ export default {
this.appointmentType === AppointmentTypeStrings.MOBILE this.appointmentType === AppointmentTypeStrings.MOBILE
&& this.selectedTimeSlotInfo?.isPremiumAppointment && this.selectedTimeSlotInfo?.isPremiumAppointment
) { ) {
const earlyBirdIndex = supportingItems.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE); const premiumFeeIndex = supportingItems.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE);
if (earlyBirdIndex >= 0) { if (premiumFeeIndex >= 0) {
supportingItems[earlyBirdIndex].laborAmount = supportingItems[premiumFeeIndex].laborAmount =
this.mobilePremiumAppointmentFee.laborAmount; this.mobilePremiumAppointmentFee.laborAmount;
supportingItems[earlyBirdIndex].selingPrice = supportingItems[premiumFeeIndex].sellingPrice =
this.mobilePremiumAppointmentFee.selingPrice; this.mobilePremiumAppointmentFee.sellingPrice;
supportingItems[earlyBirdIndex].kitPrice = supportingItems[premiumFeeIndex].kitPrice =
this.mobilePremiumAppointmentFee.kitPrice; this.mobilePremiumAppointmentFee.kitPrice;
} else { } else {
supportingItems.push(this.mobilePremiumAppointmentFee); supportingItems.push(this.mobilePremiumAppointmentFee);
@ -453,10 +452,10 @@ export default {
this.mainStore.saveSupportingItemsSuppressingStateResetting(supportingItems); this.mainStore.saveSupportingItemsSuppressingStateResetting(supportingItems);
} else { } else {
// if it's not a mobile and/or premium early bird, then make sure we remove any that may have been added // if it's not a mobile and/or premium early bird, then make sure we remove any that may have been added
const removeEarlyBirdIndex = supportingItems.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE); const removePremiumFeeIndex = supportingItems.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE);
if (removeEarlyBirdIndex >= 0) { if (removePremiumFeeIndex >= 0) {
supportingItems.splice(removeEarlyBirdIndex, 1); supportingItems.splice(removePremiumFeeIndex, 1);
this.mainStore.saveSupportingItemsSuppressingStateResetting(supportingItems); this.mainStore.saveSupportingItemsSuppressingStateResetting(supportingItems);
} }
} }

View file

@ -445,3 +445,12 @@ export default {
} }
}; };
</script> </script>
<style lang="scss">
.replace-options-question {
.two-list-card-width {
width: 100%;
flex: 0 auto;
}
}
</style>

View file

@ -1,7 +1,8 @@
import { shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import welcomePage from '@/layouts/welcome-page/welcome-page.vue'; import welcomePage from '@/layouts/welcome-page/welcome-page.vue';
// Supporting files // Supporting files
import { shallowMount } from '@vue/test-utils';
import settleAllPromises from '@/helpers/layout-helper.js'; import settleAllPromises from '@/helpers/layout-helper.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import baseMixin from '@/mixins/base-mixin.js'; import baseMixin from '@/mixins/base-mixin.js';
@ -10,8 +11,6 @@ import applicationConfig from '@/constants/application-config';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import navigationScenarios from '@/router/router-constants/navigation-scenarios'; import navigationScenarios from '@/router/router-constants/navigation-scenarios';
import routerParams from '@/router/router-constants/router-params'; import routerParams from '@/router/router-constants/router-params';
import { getRandomString } from '@/helpers/data-generation.js';
import { createTestingPinia } from '@pinia/testing';
// Mock our module for promises. // Mock our module for promises.
jest.mock('@/helpers/layout-helper.js', () => jest.fn()); jest.mock('@/helpers/layout-helper.js', () => jest.fn());
@ -179,13 +178,8 @@ describe('navigation', () => {
test('if duplicates found, navigate to duplicate check page', async () => { test('if duplicates found, navigate to duplicate check page', async () => {
// Arrange // Arrange
const { wrapper } = getMountedComponent({}); const { wrapper } = getMountedComponent({});
useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({}));
const duplicatesExist = { useMainStore().applicationUser.duplicateOrders = [{ test: 'a' }];
policyLookupResponse: {},
duplicateCheckResponse: [{ test: 'a'}]
};
settleAllPromises.mockImplementation(() => Promise.resolve(duplicatesExist));
// Act // Act
await wrapper.vm.forwardButtonAction(); await wrapper.vm.forwardButtonAction();
@ -199,38 +193,43 @@ describe('navigation', () => {
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
); );
}); });
test('if policy and vehicles are found, navigate to policy-vehicle page', async () => { test('if isCoverageEnabled is false, then getCoveragePolicyInfo not called', async () => {
// Arrange // Arrange
const mockvehicles = [ const { wrapper } = getMountedComponent({});
{ useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({}));
vin: 'TEST_VIN' useMainStore().issConfig.isCoverageEnabled = false;
},
{
vin: 'TEST_VIN2'
}
];
const { wrapper } = setupMocks({ // Act
policies: [{ await wrapper.vm.forwardButtonAction();
vehicles: [
{
vin: 'TEST_VIN'
},
{
vin: 'TEST_VIN2'
}
]
}]
});
await wrapper.setData({
vehiclesFound: mockvehicles
});
// Assert
expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled();
expect(wrapper.vm.mainStore.getCoveragePolicyInfo).not.toHaveBeenCalled();
});
test('if isCoverageEnabled is true, then getCoveragePolicyInfo called', async () => {
// Arrange
const { wrapper } = getMountedComponent({});
useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({}));
useMainStore().issConfig.isCoverageEnabled = true; useMainStore().issConfig.isCoverageEnabled = true;
useMainStore().order.policy.policyNumber = 'p_0001';
useMainStore().order.policy.dateOfLoss = '2022-01-28'; // Act
useMainStore().order.accountNumber = '00000'; await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.mainStore.updatePolicyData).toHaveBeenCalled();
expect(wrapper.vm.mainStore.getCoveragePolicyInfo).toHaveBeenCalled();
});
test('if policy and vehicles are found but no duplicates, navigate to policy-vehicle page', async () => {
// Arrange
const { wrapper } = setupMocks({});
useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({}));
useMainStore().applicationUser.duplicateOrders = [];
useMainStore().order.policy.policyLookupSuccessful = true;
useMainStore().order.policy.vehicles = [
{ vin: 'TEST_VIN' },
{ vin: 'TEST_VIN2' }
];
// Act // Act
await wrapper.vm.forwardButtonAction(); await wrapper.vm.forwardButtonAction();
@ -243,20 +242,14 @@ describe('navigation', () => {
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
); );
}); });
test('if policy is found, but no vehicles, navigate to vehicle-selection page', async () => { test('if policy is found, but no vehicles and no duplicates, navigate to vehicle-selection page', async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({});
policies: [{}] useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({}));
});
await wrapper.setData({ useMainStore().applicationUser.duplicateOrders = [];
vehiclesFound: null useMainStore().order.policy.policyLookupSuccessful = true;
}); useMainStore().order.policy.vehicles = [];
useMainStore().issConfig.isCoverageEnabled = true;
useMainStore().order.policy.policyNumber = 'p_0001';
useMainStore().order.policy.dateOfLoss = '2022-01-28';
useMainStore().order.accountNumber = '00000';
// Act // Act
@ -270,19 +263,37 @@ describe('navigation', () => {
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
); );
}); });
test('if policy is not found, navigate to policy-holder-details page', async () => { test('if policy is found, but null vehicles and no duplicates, navigate to vehicle-selection page', async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({});
policies: null useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({}));
});
useMainStore().issConfig.isCoverageEnabled = true; useMainStore().applicationUser.duplicateOrders = [];
useMainStore().order.policy.policyNumber = 'p_0001'; useMainStore().order.policy.policyLookupSuccessful = true;
useMainStore().order.policy.dateOfLoss = '2022-01-28'; useMainStore().order.policy.vehicles = null;
useMainStore().order.accountNumber = '00000';
// Act // Act
await wrapper.vm.navigateForward();
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES,
undefined,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
});
test('if policy is not found and no duplicates, navigate to policy-holder-details page', async () => {
// Arrange
const { wrapper } = setupMocks({});
useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.resolve({}));
useMainStore().order.policy.policyLookupSuccessful = false;
useMainStore().applicationUser.duplicateOrders = [];
// Act
await wrapper.vm.forwardButtonAction();
// Assert // Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
@ -292,4 +303,16 @@ describe('navigation', () => {
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
); );
}); });
test('getDuplicateReferrals throws rejected promise => navigate called', async () => {
// Arrange
const { wrapper } = setupMocks({});
const error = 'duplicate referrals error';
useMainStore().getDuplicateReferrals = jest.fn().mockImplementation(() => Promise.reject(error));
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
}); });

View file

@ -167,6 +167,7 @@
<script> <script>
// Components // Components
import { Form, defineRule } from 'vee-validate';
import siteHeader from '@/iss-components/site-header/site-header.vue'; import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue'; import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue';
@ -178,7 +179,6 @@ import textBlock from '@/digital-components/text-block/text-block.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 { required, regex } from '@/helpers/validation-rules'; import { required, regex } from '@/helpers/validation-rules';
import errorMessages from '@/constants/error-messages'; import errorMessages from '@/constants/error-messages';
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
@ -253,7 +253,6 @@ export default {
data() { data() {
return { return {
welcomePageModel: this.getWelcomePageModelFromStore(), welcomePageModel: this.getWelcomePageModelFromStore(),
vehiclesFound: [],
duplicates: [], duplicates: [],
rules: { rules: {
policyNumber: 'policy-number-required', policyNumber: 'policy-number-required',
@ -309,75 +308,27 @@ export default {
methods: { methods: {
async forwardButtonAction() { async forwardButtonAction() {
this.mainStore.updatePolicyData(this.welcomePageModel); this.mainStore.updatePolicyData(this.welcomePageModel);
const duplicateCheckResponse = await useMainStore().getDuplicateReferrals(); await this.mainStore.getDuplicateReferrals()
const duplicatePromiseResultMap = [ .then(() => {}, () => {})
{ .finally(async () => {
resultKey: 'duplicateCheckResponse', if (this.isCoverageEnabled) {
promise: duplicateCheckResponse await this.mainStore.getCoveragePolicyInfo();
}
];
const duplicateResultMap = await settleAllPromises(duplicatePromiseResultMap);
this.mainStore.applicationUser.duplicateOrders = duplicateResultMap.duplicateCheckResponse ?? [];
this.duplicates = duplicateResultMap.duplicateCheckResponse;
// call coverage policy lookup if isCoverageEnabled flag enabled
if (this.isCoverageEnabled) {
const policyLookupResponse = useMainStore().getCoveragePolicyInfo({
accountNumber: this.mainStore.order.accountNumber.toString(),
policyNumber: this.mainStore.order.policy.policyNumber,
dateOfLoss: this.mainStore.order.policy.dateOfLoss,
zipCode: this.mainStore.order.policy.policyZipCode
});
const policyPromiseResultMap = [
{
resultKey: 'policyLookupResponse',
promise: policyLookupResponse
} }
];
const policyResultMap = await settleAllPromises(policyPromiseResultMap);
const policyInfo = policyResultMap.policyLookupResponse;
// if policy lookup fails, navigate directly to policy-holder-details page
if (!policyInfo) {
this.navigateForward(); this.navigateForward();
} });
const policy = policyInfo.policies?.[0];
if (policy) {
// populate policy holder details from policy lookup
this.mainStore.order.customer.address.streetAddress = policy.insureds?.[0]?.address;
this.mainStore.order.customer.address.city = policy.insureds?.[0]?.city;
this.mainStore.order.customer.address.state = policy.insureds?.[0]?.state;
this.mainStore.order.customer.address.zipCode = policy.insureds?.[0]?.zipCode;
this.mainStore.order.customer.firstName = policy.insureds?.[0]?.firstName;
this.mainStore.order.customer.lastName = policy.insureds?.[0]?.lastName;
// populate additional fields
this.mainStore.order.serviceLocation.zipCode = policy.insureds?.[0]?.zipCode;
// populate vehicles
this.mainStore.order.policy.vehicles = policy.vehicles;
this.vehiclesFound = policy.vehicles;
}
return this.navigateForward(policy);
}
return this.navigateForward();
}, },
navigateForward(policy) { navigateForward() {
if (this.duplicates?.length > 0 ?? false) { if (this.mainStore.applicationUser.duplicateOrders?.length > 0 ?? false) {
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_DUPLICATES, this.navigationScenarios.CLICKED_FORWARD_WITH_DUPLICATES,
this.$route, this.$route,
{}, {},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
); );
} else if (policy) { } else if (this.mainStore.policy.policyLookupSuccessful) {
if (this.vehiclesFound) { if (this.mainStore.order.policy.vehicles?.length > 0 ?? false) {
// if policy lookup is successful and vehicles are found, navigate to policy-vehicles page // navigate to policy-vehicles page
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES,
this.$route, this.$route,
@ -385,7 +336,6 @@ export default {
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
); );
} else { } else {
// if policy lookup is successful, but no vehicles are associated with the policy
// navigate to vehicle-selection page (manual entry) // navigate to vehicle-selection page (manual entry)
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES,

View file

@ -11,6 +11,7 @@ import applicationConfig from '@/constants/application-config';
import issPageValues from '@/router/router-constants/issPage-values'; import issPageValues from '@/router/router-constants/issPage-values';
import damageLocationsSelected from '@/constants/damage-locations-selected'; import damageLocationsSelected from '@/constants/damage-locations-selected';
import coverageStatuses from '@/constants/coverage-statuses'; import coverageStatuses from '@/constants/coverage-statuses';
import { deepEqual } from '@/helpers/object-helper';
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants'; import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants';
import getDateDifferenceInDays from '@/helpers/date-helper'; import getDateDifferenceInDays from '@/helpers/date-helper';
@ -42,7 +43,7 @@ const getDefaultState = () => ({
imageUrl: null, imageUrl: null,
imageVifNumber: null, imageVifNumber: null,
imageColor: null, imageColor: null,
registration: { registration: { // TODO only licensePlate saved in save session
licensePlate: null, licensePlate: null,
address: null, address: null,
city: null, city: null,
@ -120,7 +121,6 @@ const getDefaultState = () => ({
vaps: null vaps: null
}, },
payment: { payment: {
isInsurance: true, // TODO delete; irrelevant to ISS
insuranceCoverage: { insuranceCoverage: {
isVerified: false, isVerified: false,
coverageStatus: coverageStatuses.PENDING, coverageStatus: coverageStatuses.PENDING,
@ -155,15 +155,16 @@ const getDefaultState = () => ({
}, },
applicationUser: { applicationUser: {
experiments: [], experiments: [],
eventBus: [], eventBus: [], // TODO not in save session
pageData: {}, pageData: {},
savedSessionTimeout: getDateForSavedSessionTimeout(), savedSessionTimeout: getDateForSavedSessionTimeout(),
saveSessionPromise: null, saveSessionPromise: null,
savedSessionId: null, savedSessionId: '00000000-0000-0000-0000-000000000000',
crmCustomerId: null, crmCustomerId: null,
lastPageVisited: null, lastPageVisited: null,
triggeredSiteEntry: false, triggeredSiteEntry: false, // TODO not in save session
duplicateOrders: [] duplicateOrders: [],
hasSentSaveQuoteEmail: null
}, },
issConfig: { issConfig: {
clientName: 'Generic Insurance', // this is the default and will be overriden by the client's name clientName: 'Generic Insurance', // this is the default and will be overriden by the client's name
@ -206,7 +207,9 @@ export const useMainStore = defineStore({
}, },
eventBus: (state) => state.applicationUser.eventBus, eventBus: (state) => state.applicationUser.eventBus,
applicationUserObj: (state) => state.applicationUser, applicationUserObj: (state) => state.applicationUser,
pageData: (state) => (page) => state.applicationUser.pageData[page], pageData: (state) => (page) => (page in state.applicationUser.pageData
? state.applicationUser.pageData[page]
: undefined),
customerData: (state) => { customerData: (state) => {
if (state.order.vehicle.registration.address) { if (state.order.vehicle.registration.address) {
const { registration } = state.order.vehicle; const { registration } = state.order.vehicle;
@ -387,38 +390,46 @@ export const useMainStore = defineStore({
}; };
} }
}, },
getCoveragePolicyInfo() {
// Coverage API Actions const { order } = this;
getCoveragePolicyInfo({ accountNumber, policyNumber, dateOfLoss, zipCode }) { const { policy } = order;
const { policy } = this.order; return new Promise((resolve, reject) => {
try { globalMethods.callHttpClient({
const response = globalMethods.callHttpClient({
method: endpoints.CoveragePolicyInfo.method, method: endpoints.CoveragePolicyInfo.method,
endpoint: endpoints.CoveragePolicyInfo.url, endpoint: endpoints.CoveragePolicyInfo.url,
payload: { payload: {
accountNumber, accountNumber: order.accountNumber?.toString(),
policyNumber, policyNumber: policy.policyNumber,
dateOfLoss, dateOfLoss: policy.dateOfLoss,
zipCode, zipCode: policy.policyZipCode,
correlationId: this.order.referralCorrelationId correlationId: order.referralCorrelationId
} }
}).then((r) => { }).then((r) => {
const responsePolicy = r.data.policies?.[0]; const responsePolicy = r?.data?.policies?.[0];
policy.policyLookupSuccessful = !!responsePolicy; policy.policyLookupSuccessful = !!responsePolicy;
return r; if (policy.policyLookupSuccessful) {
const insured = responsePolicy.insureds?.[0];
// populate policy holder details from policy lookup
order.customer.address.streetAddress = insured?.address;
order.customer.address.city = insured?.city;
order.customer.address.state = insured?.state;
order.customer.address.zipCode = insured?.zipCode;
order.customer.firstName = insured?.firstName;
order.customer.lastName = insured?.lastName;
// populate additional fields
order.serviceLocation.zipCode = insured?.zipCode;
// populate vehicles
order.policy.vehicles = responsePolicy.vehicles ?? [];
}
return resolve(r);
}).catch((error) => { }).catch((error) => {
policy.policyLookupSuccessful = false; policy.policyLookupSuccessful = false;
return error; return reject(error);
}); });
return response; });
} catch (responseError) {
policy.policyLookupSuccessful = false;
return {
error: {
status: responseError.status
}
};
}
}, },
registerClaim() { registerClaim() {
const nonNumberCharRegex = /[^0-9]/g; const nonNumberCharRegex = /[^0-9]/g;
@ -655,7 +666,7 @@ export const useMainStore = defineStore({
}, },
getMobilePremiumFee() { getMobilePremiumFee() {
const damageType = this.damage.isRepair ? 'Repair' : 'Replace'; const damageType = this.damage.isRepair ? 'Repair' : 'Replace';
const paymentType = this.order.payment.isInsurance ? 'Insurance' : 'Cash'; const paymentType = 'Insurance';
return globalMethods.callHttpClient({ return globalMethods.callHttpClient({
method: endpoints.GetMobilePremiumFee.method, method: endpoints.GetMobilePremiumFee.method,
@ -943,124 +954,251 @@ export const useMainStore = defineStore({
const { vehicle, damage, policy, customer, contactInfo, payment, const { vehicle, damage, policy, customer, contactInfo, payment,
lineItems, serviceLocation, schedule } = this.order; lineItems, serviceLocation, schedule } = this.order;
const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace);
return new Promise((resolve, reject) => {
return globalMethods.callHttpClient({ globalMethods.callHttpClient({
method: endpoints.SaveSession.method, method: endpoints.SaveSession.method,
endpoint: endpoints.SaveSession.url, endpoint: endpoints.SaveSession.url,
payload: { payload: {
applicationUser: { applicationUser: {
crmCustomerId: this.applicationUser.crmCustomerId, crmCustomerId: this.applicationUser.crmCustomerId,
experiments: this.applicationUser.experiments, experiments: this.applicationUser.experiments,
lastPage: this.applicationUser.lastPageVisited, lastPage: this.applicationUser.lastPageVisited,
pageData: this.applicationUser.pageData, pageData: this.applicationUser.pageData,
savedSessionId: this.applicationUser.savedSessionId savedSessionId: this.applicationUser.savedSessionId
},
vehicle: {
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
style: vehicle.style,
vin: vehicle.vin,
carId: vehicle.carId,
licensePlateNumber: vehicle.registration?.licensePlate
},
damage: {
numberOfChips: damage.numberOfChips,
glassToReplace: newGlassToReplace,
isRepair: damage.isRepair,
partQuestionAnswers: damage.partQuestionAnswers,
moldingQuestionAnswers: damage.moldingQuestionAnswers,
capabilityQuestionAnswers: damage.capabilityQuestionAnswers,
dateOfLoss: policy.dateOfLoss,
damageCause: policy.damageCause,
damageState: policy.damageState,
damageCity: policy.damageCity,
isDamageGlassOnly: policy.isDamageGlassOnly
},
policy: {
policyHolder: {
policyFirstName: customer.firstName,
policyLastName: customer.lastName,
policyPhoneNumber: customer.phoneNumber,
policyEmail: customer.emailAddress,
policyState: customer.address.state
}, },
policyNumber: policy.policyNumber, vehicle: {
policyZipCode: policy.policyZipCode, year: vehicle.year,
noCoverage: policy.noCoverage, make: vehicle.make,
policyLookupSuccessful: policy.policyLookupSuccessful, model: vehicle.model,
originalDeductible: this.order.originalDeductible, style: vehicle.style,
currentDeductible: this.order.currentDeductible, vin: vehicle.vin,
status: policy.status carId: vehicle.carId,
}, licensePlateNumber: vehicle.registration?.licensePlate
customer: {
address: {
streetAddress: customer.address?.streetAddress,
streetAddress2: customer.address?.streetAddress2,
city: customer.address?.city,
state: customer.address?.state,
zipCode: customer.address?.zipCode
}, },
emailAddress: contactInfo.emailAddress, damage: {
firstName: contactInfo.firstName || customer.firstName, numberOfChips: damage.numberOfChips,
lastName: contactInfo.lastName || customer.lastName, glassToReplace: newGlassToReplace,
phoneNumber: contactInfo.phoneNumber, isRepair: damage.isRepair,
optInSms: contactInfo.requestTextUpdates ?? false partQuestionAnswers: damage.partQuestionAnswers,
}, moldingQuestionAnswers: damage.moldingQuestionAnswers,
lineItems: { capabilityQuestionAnswers: damage.capabilityQuestionAnswers,
glassParts: lineItems.glassParts, dateOfLoss: policy.dateOfLoss,
supportingItems: lineItems.supportingItems, damageCause: policy.damageCause,
vaps: lineItems.vaps damageState: policy.damageState,
}, damageCity: policy.damageCity,
payment: { isDamageGlassOnly: policy.isDamageGlassOnly
InsuranceCoverage: {
isVerified: payment.insuranceCoverage?.isVerified ?? false,
coverageStatus: payment.insuranceCoverage?.coverageStatus,
claimNumber: payment.insuranceCoverage?.claimNumber
}, },
isInsurance: payment.isInsurance ?? true, policy: {
parentAccountNumber: this.issConfig.parentAccountNumber policyHolder: {
}, policyFirstName: customer.firstName,
serviceLocation: { policyLastName: customer.lastName,
address: { policyPhoneNumber: customer.phoneNumber,
streetAddress: serviceLocation.address, policyEmail: customer.emailAddress,
city: serviceLocation.city, policyState: customer.address.state
state: serviceLocation.state, },
zipCode: serviceLocation.zipCode, policyNumber: policy.policyNumber,
zipCodeCtu: serviceLocation.zipCodeCtu policyZipCode: policy.policyZipCode,
noCoverage: policy.noCoverage,
policyLookupSuccessful: policy.policyLookupSuccessful,
originalDeductible: this.order.originalDeductible,
currentDeductible: this.order.currentDeductible
}, },
appointmentType: (serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE customer: {
|| serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP)
? AppointmentTypeStrings.MOBILE : serviceLocation.appointmentType,
isVehicleProtected: serviceLocation.isVehicleProtected,
provider: {
providerNumber: serviceLocation.provider?.providerNumber,
address: { address: {
streetAddress: serviceLocation.provider?.address?.streetAddress, streetAddress: customer.address?.streetAddress,
city: serviceLocation.provider?.address?.city, streetAddress2: customer.address?.streetAddress2,
state: serviceLocation.provider?.address?.state, city: customer.address?.city,
zipCode: serviceLocation.provider?.address?.zipCode, state: customer.address?.state,
zipCodeCtu: serviceLocation.provider?.address?.zipCodeCtu zipCode: customer.address?.zipCode
} },
emailAddress: contactInfo.emailAddress,
firstName: contactInfo.firstName || customer.firstName,
lastName: contactInfo.lastName || customer.lastName,
phoneNumber: contactInfo.phoneNumber,
optInSms: contactInfo.requestTextUpdates ?? false
}, },
techNotes: contactInfo.notesForTechnician lineItems: {
glassParts: lineItems.glassParts,
supportingItems: lineItems.supportingItems,
vaps: lineItems.vaps
},
payment: {
InsuranceCoverage: {
isVerified: payment.insuranceCoverage?.isVerified ?? false,
coverageStatus: payment.insuranceCoverage?.coverageStatus,
claimNumber: payment.insuranceCoverage?.claimNumber
},
parentAccountNumber: this.issConfig.parentAccountNumber
},
serviceLocation: {
address: {
streetAddress: serviceLocation.address,
city: serviceLocation.city,
state: serviceLocation.state,
zipCode: serviceLocation.zipCode,
zipCodeCtu: serviceLocation.zipCodeCtu
},
appointmentType: (serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|| serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP)
? AppointmentTypeStrings.MOBILE : serviceLocation.appointmentType,
isVehicleProtected: serviceLocation.isVehicleProtected,
provider: {
providerNumber: serviceLocation.provider?.providerNumber,
address: {
streetAddress: serviceLocation.provider?.address?.streetAddress,
city: serviceLocation.provider?.address?.city,
state: serviceLocation.provider?.address?.state,
zipCode: serviceLocation.provider?.address?.zipCode,
zipCodeCtu: serviceLocation.provider?.address?.zipCodeCtu
}
},
techNotes: contactInfo.notesForTechnician
},
schedule: {
date: schedule.date,
startTime: schedule.startTime,
endTime: schedule.endTime,
routeCode: schedule.routeCode,
jobMaxMinutes: schedule.jobMaxMinutes,
jobMinMinutes: schedule.jobMinMinutes
},
referralDate: this.order.referralDate,
referralNumber: this.order.referralNumber?.toString(),
referralCorrelationId: this.order.referralCorrelationId,
referralSequenceNumber: this.order.referralSequenceNumber,
eon: this.order.eon
}, },
schedule: { additionalSuccessEventDataHandler: (response) =>
date: schedule.date, `Email provided: ${customer.emailAddress ? 'true' : 'false'}`
startTime: schedule.startTime, }).then((response) => resolve(response), (error) => reject(error));
endTime: schedule.endTime, });
routeCode: schedule.routeCode, },
jobMaxMinutes: schedule.jobMaxMinutes,
jobMinMinutes: schedule.jobMinMinutes loadSession() {
}, const { applicationUser, order, issConfig } = this;
referralDate: this.order.referralDate, // TODO how to get savedSessionId for a duplicate referral?
referralNumber: this.order.referralNumber?.toString(), return new Promise((resolve, reject) => {
referralCorrelationId: this.order.referralCorrelationId, globalMethods.callHttpClient({
referralSequenceNumber: this.order.referralSequenceNumber, method: endpoints.LoadSession.method,
eon: this.order.eon endpoint: endpoints.LoadSession.url,
}, payload: {
additionalSuccessEventDataHandler: (response) => savedSessionId: applicationUser.savedSessionId?.toString(),
`Email provided: ${customer.emailAddress ? 'true' : 'false'}` referralNumber: order.referralNumber?.toString(),
referralDate: order.referralDate?.toString(),
parentAccountNumber: issConfig.parentAccountNumber,
referralCorrelationId: order.referralCorrelationId
}
}).then((response) => {
const { data } = response;
if (!data) {
// TODO how should we handle this case?
return resolve(data);
}
applicationUser.crmCustomerId = data.applicationUser?.crmCustomerId;
applicationUser.experiments = data.applicationUser?.experiments ?? [];
applicationUser.lastPageVisited = data.applicationUser?.lastPage;
applicationUser.pageData = data.applicationUser?.pageData ?? {};
applicationUser.savedSessionId = data.applicationUser?.savedSessionId; // TODO this might just be what is passed
applicationUser.hasSentSaveQuoteEmail = data.applicationUser?.hasSentSaveQuoteEmail;
order.vehicle.registration.licensePlate = data.order?.vehicle?.registration?.licensePlateNumber;
order.vehicle.imageUrl = data.order?.vehicle?.imageUrl;
order.vehicle.imageColor = data.order?.vehicle?.imageVifColor;
order.vehicle.imageVifNumber = data.order?.vehicle?.imageVifNumber;
order.vehicle.year = data.order?.vehicle?.year;
order.vehicle.make = data.order?.vehicle?.make;
order.vehicle.model = data.order?.vehicle?.model;
order.vehicle.style = data.order?.vehicle?.style;
order.vehicle.carId = data.order?.vehicle?.carId;
order.vehicle.category = data.order?.vehicle?.category;
order.vehicle.vin = data.order?.vehicle?.vin;
order.customer.emailAddress = data.order?.customer?.emailAddress;
order.customer.firstName = data.order?.policy?.policyHolder?.policyFirstName;
order.customer.lastName = data.order?.policy?.policyHolder?.policyLastName;
order.customer.phoneNumber = data.order?.policy?.policyHolder?.policyPhoneNumber;
order.customer.address.streetAddress = data.order?.customer?.address?.streetAddress;
order.customer.address.streetAddress2 = data.order?.customer?.address?.streetAddress2;
order.customer.address.city = data.order?.customer?.address?.city;
order.customer.address.state = data.order?.customer?.address?.state;
order.customer.address.zipCode = data.order?.customer?.address?.zipCode;
order.damage.isRepair = data.order?.damage?.isRepair;
order.damage.numberOfChips = data.order?.damage?.numberOfChips;
order.damage.glassToReplace = data.order?.damage?.glassToReplace;
order.damage.capabilityQuestionAnswers = data.order?.damage?.capabilityQuestionAnswers;
order.damage.moldingQuestionAnswers = data.order?.damage?.moldingQuestionAnswers;
order.damage.partQuestionAnswers = data.order?.damage?.partQuestionAnswers;
order.policy.policyNumber = data.order?.policy?.policyNumber;
order.policy.policyZipCode = data.order?.policy?.policyZipCode;
order.policy.noCoverage = data.order?.policy?.noCoverage;
order.policy.policyLookupSuccessful = data.order?.policy?.policyLookupSuccessful; // TODO probably don't need to load this
order.policy.dateOfLoss = data.order?.damage?.dateOfLoss;
order.policy.damageCause = data.order?.damage?.damageCause;
order.policy.damageState = data.order?.damage?.damageState;
order.policy.damageCity = data.order?.damage?.damageCity;
order.policy.isDamageGlassOnly = data.order?.damage?.isDamageGlassOnly;
order.originalDeductible = data.order?.policy?.originalDeductible;
order.currentDeductible = data.order?.policy?.currentDeductible;
order.lineItems.glassParts = data.order?.lineItems?.glassParts;
// TODO otherParts
order.lineItems.supportingItems = data.order?.lineItems?.supportingItems;
order.lineItems.vaps = data.order?.lineItems?.vaps;
order.payment.insuranceCoverage.isVerified = data.order?.payment?.insuranceCoverage?.isVerified;
order.payment.insuranceCoverage.coverageStatus = data.order?.payment?.insuranceCoverage?.coverageStatus;
const parentAccountNumber = Number.isNaN(data.order?.payment?.parentAccountNumber)
? 0
: data.order?.payment?.parentAccountNumber;
order.payment.parentAccountNumber = parentAccountNumber;
issConfig.parentAccountNumber = parentAccountNumber;
order.payment.insuranceCoverage.claimNumber = data.order?.payment?.insuranceCoverage?.claimNumber;
order.serviceLocation.address = data.order?.serviceLocation?.streetAddress;
order.serviceLocation.address2 = data.order?.serviceLocation?.streetAddress2;
order.serviceLocation.city = data.order?.serviceLocation?.city;
order.serviceLocation.state = data.order?.serviceLocation?.state;
order.serviceLocation.zipCode = data.order?.serviceLocation?.zipCode;
order.serviceLocation.zipCodeCtu = data.order?.serviceLocation?.zipCodeCtu;
order.serviceLocation.appointmentType = data.order?.serviceLocation?.appointmentType;
order.serviceLocation.isVehicleProtected = data.order?.serviceLocation?.isVehicleProtected;
order.serviceLocation.provider.providerNumber = data.order?.serviceLocation?.provider?.providerNumber;
order.serviceLocation.provider.address.streetAddress = data.order?.serviceLocation?.provider?.address?.streetAddress;
order.serviceLocation.provider.address.city = data.order?.serviceLocation?.provider?.address?.city;
order.serviceLocation.provider.address.state = data.order?.serviceLocation?.provider?.address?.state;
order.serviceLocation.provider.address.zipCode = data.order?.serviceLocation?.provider?.address?.zipCode;
order.serviceLocation.provider.address.zipCodeCtu = data.order?.serviceLocation?.provider?.address?.zipCodeCtu;
order.contactInfo.firstName = data.order?.customer?.firstName;
order.contactInfo.lastName = data.order?.customer?.lastName;
order.contactInfo.emailAddress = data.order?.customer?.emailAddress;
order.contactInfo.phoneNumber = data.order?.customer?.phoneNumber;
order.contactInfo.requestTextUpdates = data.order?.customer?.isSmsOptIn; // TODO confirm
order.contactInfo.notesForTechnician = data.order?.serviceLocation?.techNotes;
// TODO service phone number ??
// TODO isSmsOptIn service ??
order.schedule.date = data.order?.schedule?.date;
order.schedule.startTime = data.order?.schedule?.startTime;
order.schedule.endTime = data.order?.schedule?.endTime;
order.schedule.routeCode = data.order?.schedule?.routeCode;
order.schedule.jobMaxMinutes = data.order?.schedule?.jobMaxMinutes;
order.schedule.jobMinMinutes = data.order?.schedule?.jobMinMinutes;
order.referralNumber = data.order?.referralNumber;
order.referralDate = data.order?.referralDate;
order.referralCorrelationId = data.order?.referralCorrelationId;
order.referralSequenceNumber = data.order?.referralSequenceNumber;
order.eon = data.order?.eon;
// TODO order.workOrderNumber not set, but this likely is not an issue since WON => will not return
return resolve(data);
}, (error) => {
reject(error);
});
}); });
}, },
@ -1151,6 +1289,11 @@ export const useMainStore = defineStore({
this.order.vehicle.registration.firstName = null; this.order.vehicle.registration.firstName = null;
this.order.vehicle.registration.lastName = null; this.order.vehicle.registration.lastName = null;
}, },
resetServiceLocationAndDependencies(context) {
this.resetServiceLocationAppointmentType();
this.resetServiceLocationProvider();
this.resetSchedule();
},
resetServiceLocationAppointmentType() { resetServiceLocationAppointmentType() {
this.order.serviceLocation.appointmentType = null; this.order.serviceLocation.appointmentType = null;
}, },
@ -1407,6 +1550,8 @@ export const useMainStore = defineStore({
|| !sortedPreviousResultsArray?.every((x, i) => x.result === sortedPartQuestionAnswersArray[i].result); || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedPartQuestionAnswersArray[i].result);
if (havePartQuestionAnswersChanged) { if (havePartQuestionAnswersChanged) {
this.resetServiceLocationAndDependencies();
this.updateGlassParts(null); this.updateGlassParts(null);
this.updateMoldingQuestionAnswers(null); this.updateMoldingQuestionAnswers(null);
this.updateCapabilityQuestionAnswers(null); this.updateCapabilityQuestionAnswers(null);
@ -1428,6 +1573,8 @@ export const useMainStore = defineStore({
|| !sortedPreviousResultsArray?.every((x, i) => x.result === sortedMoldingQuestionAnswersArray[i].result); || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedMoldingQuestionAnswersArray[i].result);
if (haveMoldingQuestionAnswersChanged) { if (haveMoldingQuestionAnswersChanged) {
this.resetServiceLocationAndDependencies();
this.updateGlassParts(null); this.updateGlassParts(null);
this.updateSupportingItems(null); this.updateSupportingItems(null);
this.updateCapabilityQuestionAnswers(null); this.updateCapabilityQuestionAnswers(null);
@ -1445,6 +1592,8 @@ export const useMainStore = defineStore({
|| !sortedPreviousResultsArray?.every((x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result); || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result);
if (haveCapabilityQuestionAnswersChanged) { if (haveCapabilityQuestionAnswersChanged) {
this.resetServiceLocationAndDependencies();
this.updateGlassParts(null); this.updateGlassParts(null);
this.updateSupportingItems(null); this.updateSupportingItems(null);
} }
@ -1453,10 +1602,16 @@ export const useMainStore = defineStore({
this.updateCapabilityQuestionAnswers(capabilityQuestionAnswersArray); this.updateCapabilityQuestionAnswers(capabilityQuestionAnswersArray);
}, },
saveGlassParts(glassParts) { saveGlassParts(glassParts) {
if (!deepEqual(glassParts, this.order.lineItems.glassParts)) {
this.resetServiceLocationAndDependencies();
}
this.order.lineItems.glassParts = glassParts; this.order.lineItems.glassParts = glassParts;
}, },
saveSupportingItems(supportingItems) { saveSupportingItems(supportingItems) {
// TODO: RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES if (!deepEqual(supportingItems, this.order.lineItems.supportingItems)) {
this.resetServiceLocationAndDependencies();
}
this.order.lineItems.supportingItems = supportingItems; this.order.lineItems.supportingItems = supportingItems;
}, },
saveSupportingItemsSuppressingStateResetting(supportingItems) { saveSupportingItemsSuppressingStateResetting(supportingItems) {
@ -1827,6 +1982,8 @@ export const useMainStore = defineStore({
this.resetGlassPartsState(); this.resetGlassPartsState();
this.resetSupportingItemsState(); this.resetSupportingItemsState();
this.resetVapsState(); this.resetVapsState();
this.resetServiceLocationAndDependencies();
}, },
resetPageFields() { resetPageFields() {

File diff suppressed because it is too large Load diff

View file

@ -157,13 +157,20 @@ $spacer: 1rem;
$spacers: ( $spacers: (
0: 0, 0: 0,
1: $spacer * 0.25, 1: $spacer * 0.25,
/* 8px */ 2: $spacer * 0.5, /* 8px */
/* 12px */ 3: $spacer * 0.75, 2: $spacer * 0.5,
/* 16px */ 4: $spacer * 1, /* 12px */
/* 24px */ 5: $spacer * 1.5, 3: $spacer * 0.75,
/* 32px */ 6: $spacer * 2, /* 16px */
/* 40px */ 7: $spacer * 2.5, 4: $spacer * 1,
/* 48px */ 8: $spacer * 3, /* 24px */
5: $spacer * 1.5,
/* 32px */
6: $spacer * 2,
/* 40px */
7: $spacer * 2.5,
/* 48px */
8: $spacer * 3,
); );
//Grid breakpoints //Grid breakpoints
@ -190,3 +197,6 @@ $alert-color-scale: 40%;
// This affects all [Bootstrap] modals // This affects all [Bootstrap] modals
$modal-fade-transform: translate(0, 100%); $modal-fade-transform: translate(0, 100%);
$modal-backdrop-opacity: 0; $modal-backdrop-opacity: 0;
//Disable default !important behavior
$enable-important-utilities: false;

View file

@ -76,6 +76,7 @@ import textBlock from '@/digital-components/text-block/text-block.vue';
import textLink from '@/ux-components/text-link/text-link.vue'; import textLink from '@/ux-components/text-link/text-link.vue';
export default { export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'alert', name: 'alert',
components: { components: {
textBlock, textBlock,
@ -158,6 +159,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.alert { .alert {
border-color: transparent;
button { button {
display: none; display: none;
} }

View file

@ -93,8 +93,8 @@ export default {
img { img {
// svg's should be constructed on the same canvas size/viewbox to ensure // svg's should be constructed on the same canvas size/viewbox to ensure
// they occupy the same space in the DOM. This will allow easy/proper alignment of elements. See exisitng svg's for examples. // they occupy the same space in the DOM. This will allow easy/proper alignment of elements. See exisitng svg's for examples.
height: auto; height: 2rem;
width: 6.5rem; width: auto;
margin-bottom: 2.2rem; margin-bottom: 2.2rem;
max-width: 100%; max-width: 100%;
} }
@ -105,8 +105,9 @@ export default {
+ .list-card-content { + .list-card-content {
outline: none; outline: none;
display: block; display: flex;
position: relative; position: relative;
justify-content: flex-start;
p { p {
color: $gray-600; color: $gray-600;

View file

@ -28,7 +28,7 @@ export default {
display: flex; display: flex;
//Open an overlay to prevent page interaction //Open an overlay to prevent page interaction
&:before { &:before:not(.date-picker-hidden) {
content: ""; content: "";
position: fixed; position: fixed;
top: 0; top: 0;