Merge remote-tracking branch 'origin/feature/CSR-98' into feature/CSR-99

This commit is contained in:
FrankRua 2022-03-15 15:19:41 -04:00
commit e4773f08f7
22 changed files with 402 additions and 60 deletions

View file

@ -37,8 +37,8 @@
</div> </div>
</fieldset> </fieldset>
</div> </div>
<div class="row mt-2 form-test-error" v-if="!suppressError"> <div class="row mt-2 form-test-error">
<error-message :name="groupName"></error-message> <error-message :name="groupName" v-if="!suppressError"></error-message>
</div> </div>
</div> </div>
</template> </template>
@ -133,6 +133,7 @@ export default {
if(this.isMultiSelect && this.selectedValues) { if(this.isMultiSelect && this.selectedValues) {
// Add or remove item to array of data to emit // Add or remove item to array of data to emit
const newSelectedValues = this.selectedValues; const newSelectedValues = this.selectedValues;
if(Array.isArray(this.selectedValues)) { if(Array.isArray(this.selectedValues)) {
val.checkValue ? newSelectedValues.push(val.value) : newSelectedValues.splice(newSelectedValues.indexOf(val.value), 1); val.checkValue ? newSelectedValues.push(val.value) : newSelectedValues.splice(newSelectedValues.indexOf(val.value), 1);
this.selectedValues = newSelectedValues; this.selectedValues = newSelectedValues;

View file

@ -0,0 +1,6 @@
const cookieNames = {
ORDER_INFO: "OrderInfo"
};
export { cookieNames };

View file

@ -47,6 +47,10 @@ const endpoints = {
url: "/parts/api/v1/parts/parts-or-questions", url: "/parts/api/v1/parts/parts-or-questions",
method: "POST", method: "POST",
}, },
SaveOrder: {
url: "/order/api/v1/order/save",
method: "POST",
}
}; };
export { endpoints }; export { endpoints };

View file

@ -12,12 +12,14 @@ const storeActions = {
LOOKUP_VEHICLE_BY_YMMS: "lookupVehicleByYmms", LOOKUP_VEHICLE_BY_YMMS: "lookupVehicleByYmms",
LOOKUP_VEHICLE_BY_VIN: "lookupVehicleByVin", LOOKUP_VEHICLE_BY_VIN: "lookupVehicleByVin",
GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions", GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions",
SAVE_ORDER: "saveOrder",
// DEPENDENCY MUTATIONS // DEPENDENCY MUTATIONS
RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies", RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies",
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies", RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
RESET_REGISTRATION_STATE_AND_DEPENDENCIES: "resetRegistrationAndDependencies", RESET_REGISTRATION_STATE_AND_DEPENDENCIES: "resetRegistrationAndDependencies",
RESET_PARTS_STATE_AND_DEPENDENCIES: "resetPartsAndDependencies", RESET_PARTS_STATE_AND_DEPENDENCIES: "resetPartsAndDependencies",
RESET_STATE: "resetState",
}; };
export { storeActions }; export { storeActions };

View file

@ -15,6 +15,11 @@ const storeMutations = {
UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace", UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace",
UPDATE_PARTS: "updateParts", UPDATE_PARTS: "updateParts",
// ORDER MUTATIONS
UPDATE_REFERRAL_NUMBER: "updateReferralNumber",
UPDATE_REFERRAL_DATE: "updateReferralDate",
UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId",
// EVENT BUS MUTATIONS // EVENT BUS MUTATIONS
ADD_EVENT_TO_BUS: "addEventToBus", ADD_EVENT_TO_BUS: "addEventToBus",
REMOVE_EVENT_FROM_BUS: "removeEventFromBus", REMOVE_EVENT_FROM_BUS: "removeEventFromBus",
@ -24,6 +29,7 @@ const storeMutations = {
RESET_DAMAGE_STATE: "resetDamageState", RESET_DAMAGE_STATE: "resetDamageState",
RESET_REGISTRATION_STATE: "resetRegistrationState", RESET_REGISTRATION_STATE: "resetRegistrationState",
RESET_PARTS_STATE: "resetPartsState", RESET_PARTS_STATE: "resetPartsState",
RESET_STATE: "resetState",
// OTHER MUTATIONS // OTHER MUTATIONS
UPDATE_PAGE_DATA: "updatePageData", UPDATE_PAGE_DATA: "updatePageData",

View file

@ -5,7 +5,15 @@ import httpStatusCodes from "http-status-codes";
export default { export default {
callHttpClient({ method, endpoint, payload }) { callHttpClient({ method, endpoint, payload }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const apiGatewayUrl = applicationConfig.CONSUMER_APIGATEWAY_URL; // TODO CSR-98 TEMP FOR TESTING
var apiGatewayUrl = applicationConfig.CONSUMER_APIGATEWAY_URL;
if (endpoint.includes("order")) {
apiGatewayUrl = "https://localhost:44346";
}
// const apiGatewayUrl = applicationConfig.CONSUMER_APIGATEWAY_URL;
const payloadAndAnalyticsData = Object.assign({}, payload, { const payloadAndAnalyticsData = Object.assign({}, payload, {
AppName: "FixMyGlass", AppName: "FixMyGlass",
}); });

View file

@ -10,6 +10,7 @@
buttonType="listCard" buttonType="listCard"
v-model="selectedValues" v-model="selectedValues"
:validationRules="validationRules" :validationRules="validationRules"
:suppressError="suppressError"
/> />
</div> </div>
</transition> </transition>
@ -35,6 +36,7 @@ export default ({
modelValue: Array, modelValue: Array,
isMultiSelect: Boolean, isMultiSelect: Boolean,
validationRules: String, validationRules: String,
suppressError: Boolean,
}, },
methods: { methods: {
initializeComponent(cmsContent, replaceOptions){ initializeComponent(cmsContent, replaceOptions){

View file

@ -19,6 +19,7 @@
ref="windshieldOptions" ref="windshieldOptions"
v-model="selectedWindshieldOptions" v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict" :hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations" :selectedDamageLocations="selectedDamageLocations"
/> />
<alert <alert
@ -293,6 +294,12 @@ export default {
}, },
navigateForward(partsData){ navigateForward(partsData){
// CSR-98 TEMP
if (store.getters.vehicle.year == 2010) {
this.navigateToHeritageFunnel();
return;
}
//found problem questions //found problem questions
if (partsData.data.partsOrQuestions.some(pq => pq.partQuestions != null && pq.partQuestions.length > 0)){ if (partsData.data.partsOrQuestions.some(pq => pq.partQuestions != null && pq.partQuestions.length > 0)){
this.$router.navigateAfterSave(this.navigationScenarios.SELECTED_DAMAGE_WITH_PART_QUESTIONS, this.$route, {}, {}, partsData.data); this.$router.navigateAfterSave(this.navigationScenarios.SELECTED_DAMAGE_WITH_PART_QUESTIONS, this.$route, {}, {}, partsData.data);
@ -392,6 +399,23 @@ export default {
hasRepairReplaceConflict() { hasRepairReplaceConflict() {
return this.isWindshieldDamageLocation && this.selectedDamageLocations.length > 1 && this.isWindshieldRepair; return this.isWindshieldDamageLocation && this.selectedDamageLocations.length > 1 && this.isWindshieldRepair;
}, },
hasSplitSingleConflict() {
if (!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions) return false;
return this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.some(selectedSingleWindshield =>
{
return selectedSingleWindshield.toUpperCase() === damageLocationsSelected.SINGLE.toUpperCase();
}) &&
(this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.some(selectedDriverWindshield =>
{
return selectedDriverWindshield.toUpperCase() === damageLocationsSelected.DRIVER.toUpperCase();
}) ||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.some(selectedPassengerWindshield =>
{
return selectedPassengerWindshield.toUpperCase() === damageLocationsSelected.PASSENGER.toUpperCase();
})
);
},
}, },
components: { components: {
@ -408,11 +432,3 @@ export default {
}, },
}; };
</script> </script>
<style lang="scss">
.vehicle-damage-form {
display: flex;
flex-direction: column;
height: 100%;
}
</style>

View file

@ -2,14 +2,14 @@
<div class="windshield-options"> <div class="windshield-options">
<windshieldDamageTypeQuestion ref="windshieldDamageTypeQuestion" <windshieldDamageTypeQuestion ref="windshieldDamageTypeQuestion"
:isAvailable=isWindshieldDamageLocation :isAvailable=isWindshieldDamageLocation
:suppressError="hasRepairReplaceConflict || showNoReplaceAvailableError" :suppressError="hasRepairReplaceConflict || showNoReplacementAvailableError"
groupName="WindshieldDamageTypeQuestion" groupName="WindshieldDamageTypeQuestion"
v-model="selectedWindshieldDamageTypeValues" v-model="selectedWindshieldDamageTypeValues"
:validationRules="isWindshieldReplaceAvailable ? 'windshield-damage-type-required|checkForRepairAndReplace:@DamageLocationQuestion' : 'windshield-damage-type-required|checkForRepairAndReplace:@DamageLocationQuestion|repairOnly'" :validationRules="windshieldDamageTypeQuestionValidationRules"
/> />
<alert <alert
class="my-3" class="my-3"
v-show="showNoReplaceAvailableError" v-show="showNoReplacementAvailableError"
alertClass="alert-danger" alertClass="alert-danger"
alertHeadline="Service not available" alertHeadline="Service not available"
alertCopy="We're sorry, but we currently offer only repair service for your vehicle type. Need help with next steps? Call us at 800-394-0288." alertCopy="We're sorry, but we currently offer only repair service for your vehicle type. Need help with next steps? Call us at 800-394-0288."
@ -26,8 +26,17 @@
isMultiSelect isMultiSelect
groupName="WindshieldReplaceOptions" groupName="WindshieldReplaceOptions"
v-model="selectedWindshieldReplaceOptionsValues" v-model="selectedWindshieldReplaceOptionsValues"
validationRules="windshield-replace-options-required" validationRules="windshield-replace-options-required|preventSplitAndSingleTogether"
:suppressError="hasSplitSingleConflict"
/> />
<alert
class="my-3"
v-show="hasSplitSingleConflict"
alertClass="alert-danger"
alertHeadline="Single-piece or split?"
alertCopy="Please select just one windshield option: single-piece or split."
:isDismissible="false"
/>
</div> </div>
</template> </template>
@ -53,17 +62,25 @@ defineRule("checkForRepairAndReplace", (value, [otherFieldValue]) => {
Array.isArray(otherFieldValue) && Array.isArray(otherFieldValue) &&
otherFieldValue.length > 1) otherFieldValue.length > 1)
{ {
return "checkForRepairAndReplace error" return false;
} }
return true; return true;
}); });
defineRule("repairOnly", (value) => { defineRule("repairOnly", (value) => {
if (value.toString().toUpperCase() === damageLocationsSelected.REPAIR.toUpperCase()) { if (value.toString().toUpperCase() === damageLocationsSelected.REPAIR.toUpperCase()) {
return true; return true;
} }
return false; return false;
}); });
defineRule("preventSplitAndSingleTogether", (value) => {
if (value.toString().toUpperCase().includes(damageLocationsSelected.SINGLE.toUpperCase()) &&
(value.toString().toUpperCase().includes(damageLocationsSelected.DRIVER.toUpperCase()) ||
value.toString().toUpperCase().includes(damageLocationsSelected.PASSENGER.toUpperCase())))
{
return false;
}
return true;
});
export default ({ export default ({
name: "windshieldOptions", name: "windshieldOptions",
@ -77,7 +94,8 @@ export default ({
props: { props: {
modelValue: Array, modelValue: Array,
selectedDamageLocations: Array, selectedDamageLocations: Array,
hasRepairReplaceConflict: Boolean hasRepairReplaceConflict: Boolean,
hasSplitSingleConflict: Boolean,
}, },
methods: { methods: {
@ -91,10 +109,11 @@ export default ({
this.windshieldAvailableReplacementOptions = windshieldAvailableReplacementOptions; this.windshieldAvailableReplacementOptions = windshieldAvailableReplacementOptions;
}, },
getWindshieldOptions(selectedWindshieldDamageType, selectedWindshieldChipCount, selectedWindshieldReplaceOptions){ getWindshieldOptions(selectedWindshieldDamageType, selectedWindshieldChipCount, selectedWindshieldReplaceOptions){
// ONLY UPDATE THE NEW VALUE IF IT IS TRUTHY (NOT NULL)
return { return {
selectedWindshieldDamageType: selectedWindshieldDamageType, selectedWindshieldDamageType: selectedWindshieldDamageType ? selectedWindshieldDamageType : this.selectedValues.selectedWindshieldDamageType,
selectedWindshieldChipCount: selectedWindshieldChipCount, selectedWindshieldChipCount: selectedWindshieldChipCount ? selectedWindshieldChipCount : this.selectedValues.selectedWindshieldChipCount,
selectedWindshieldReplaceOptions: selectedWindshieldReplaceOptions selectedWindshieldReplaceOptions: selectedWindshieldReplaceOptions ? selectedWindshieldReplaceOptions : this.selectedValues.selectedWindshieldReplaceOptions,
} }
}, },
}, },
@ -150,12 +169,28 @@ export default ({
isWindshieldReplaceAvailable() { isWindshieldReplaceAvailable() {
return !(Array.isArray(this.windshieldAvailableReplacementOptions) && this.windshieldAvailableReplacementOptions.length < 1); return !(Array.isArray(this.windshieldAvailableReplacementOptions) && this.windshieldAvailableReplacementOptions.length < 1);
}, },
showNoReplaceAvailableError() { isSplitWindshieldOption() {
const options = this.windshieldAvailableReplacementOptions.toString().toUpperCase();
if (options.includes('DRIVER') && options.includes('PASSENGER')) {
return true;
}
return false;
},
showNoReplacementAvailableError() {
if (this.isReplaceOptionSelected && !this.isWindshieldReplaceAvailable) { if (this.isReplaceOptionSelected && !this.isWindshieldReplaceAvailable) {
return true; return true;
} }
return false; return false;
}, },
windshieldDamageTypeQuestionValidationRules() {
// Note: the validation rules string is not dynamic (it cannot be changed once component has been created)
let validationRules = "windshield-damage-type-required|checkForRepairAndReplace:@DamageLocationQuestion";
// if vehicle has no windshield replacement option
if (!this.isWindshieldReplaceAvailable) {
validationRules = validationRules.concat('|repairOnly');
}
return validationRules;
}
}, },
components: { components: {
windshieldDamageTypeQuestion, windshieldDamageTypeQuestion,

View file

@ -0,0 +1 @@
test.todo("some test to be written in the future");

View file

@ -0,0 +1,102 @@
<template>
<div class="container-fluid shadow rounded-3 p-2 position-relative make-tall">
<funnelHeader ref="funnelHeader" />
<vehicleBanner ref="vehicleBanner" />
<funnelSubHeader ref="funnelSubHeader" />
<h1>VIN Lookup Placeholder Page</h1>
<Form
@submit="onSubmit"
@invalid-submit="onInvalidSubmit"
ref="theForm"
v-slot="{ meta }"
class="d-flex flex-column h-100"
>
<funnel-footer
ref="funnelFooter"
:isDisabled="!meta.valid"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction"
/>
</Form>
</div>
</template>
<script>
// Components
import funnelHeader from "@/common-components/funnel-header/funnel-header";
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
import { Form, defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
// DEFINE VALIDATION RULES
defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED));
export default {
name: "vin-lookup",
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
const damageOptionsPromise =
baseMixin.methods.dispatchNonBlockingStoreAction(
storeActions.GET_DAMAGE_OPTIONS,
{ carId: store.getters.vehicle.carId }
);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "damageOptions",
promise: damageOptionsPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.$refs.funnelHeader.initializeComponent(
resultMap.cmsContent.FunnelHeaderWidget
);
vm.$refs.vehicleBanner.initializeComponent(
resultMap.cmsContent.VehicleBannerWidget
);
vm.$refs.funnelSubHeader.initializeComponent(
resultMap.cmsContent.FunnelSubHeaderWidget
);
vm.$refs.funnelFooter.initializeComponent(
resultMap.cmsContent.FunnelFooterWidget
);
});
},
methods: {
arePagePrerequisitesValid() {
return true;
},
},
components: {
funnelHeader,
vehicleBanner,
funnelSubHeader,
funnelFooter,
Form,
},
};
</script>
<style lang="scss">
</style>

View file

@ -1,4 +1,5 @@
import store from "@/store"; import store from "@/store";
import router from "@/router";
import { storeActions } from "@/constants/store-actions.js"; import { storeActions } from "@/constants/store-actions.js";
import { storeMutations } from "@/constants/store-mutations.js"; import { storeMutations } from "@/constants/store-mutations.js";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
@ -20,6 +21,39 @@ export default {
}, },
savePageDataToStore(page, data){ savePageDataToStore(page, data){
store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: data }); store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: data });
},
async saveOrder() {
var savedOrderInfo = (await this.dispatchNonBlockingStoreAction(storeActions.SAVE_ORDER)).data;
store.commit(storeMutations.UPDATE_REFERRAL_NUMBER, savedOrderInfo.referralNumber);
store.commit(storeMutations.UPDATE_REFERRAL_DATE, savedOrderInfo.referralDate);
store.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, savedOrderInfo.referralCorrelationId);
},
getCookieValue(cookieName) {
return document.cookie
?.split("; ")
?.find(row => row.startsWith(`${cookieName}=`))
?.split("=")[1];
},
setCookieValue(cookieName, cookieValue) {
document.cookie = `${cookieName}=${cookieValue}`;
},
deleteCookie(cookieName) {
document.cookie = `${cookieName}=; Max-Age=0; path=/; domain=${location.hostname}`;
},
navigateToHeritageFunnel() {
var referralCorrelationId = store.getters.referralCorrelationId;
router.navigate(
navigationScenarios.MOVE_TO_HERITAGE_FUNNEL,
router.currentRoute.value,
{
corid: referralCorrelationId,
src: "concept-funnel",
// TODO CSR-98 REMOVE THIS
cns: "all",
experiments: "ConceptFunnel=ConceptFunnel_V1=ConceptFunnel_TEST=true"
}
);
} }
}, },
computed: { computed: {

View file

@ -79,6 +79,8 @@ describe("baseMixin.js", () => {
}); });
}); });
function getMixInInstance({ isDispatchSuccess = true }) { function getMixInInstance({ isDispatchSuccess = true }) {
// Mock Store // Mock Store
const storeDispatch = jest.fn(); const storeDispatch = jest.fn();

View file

@ -8,6 +8,7 @@ import { routerParameterKeys } from '@/router/router-constants/router-parameter-
import baseMixin from "@/mixins/base-mixin"; import baseMixin from "@/mixins/base-mixin";
import eventBus from "@/helpers/event-bus/event-bus"; import eventBus from "@/helpers/event-bus/event-bus";
import store from "@/store"; import store from "@/store";
import { cookieNames } from "@/constants/cookie-names";
// Components // Components
import ComponentTest from "@/layouts/component-test/component-test.vue"; import ComponentTest from "@/layouts/component-test/component-test.vue";
@ -51,6 +52,12 @@ const routes = [
path: "/", path: "/",
name: "root", name: "root",
async beforeEnter(to, from, next) { async beforeEnter(to, from, next) {
// TODO CSR-98 Also triggers on refresh... should it though?
// Entering the concept funnel
if (from.redirectedFrom === undefined) {
handleInfoFromHeritageFunnel();
}
// If we have no query string, or we don't have the FmgPage query string. // If we have no query string, or we don't have the FmgPage query string.
if (to.query.fmgPage === undefined) { if (to.query.fmgPage === undefined) {
await GoToFunnelStartOn404(next); await GoToFunnelStartOn404(next);
@ -58,7 +65,6 @@ const routes = [
try { try {
// If we already have our route, go to it. // If we already have our route, go to it.
if (router.hasRoute(to.query.fmgPage)) { if (router.hasRoute(to.query.fmgPage)) {
// Since our route is already in scope, we can grab the component from it and call the arePagePrerequisitesValid function. // Since our route is already in scope, we can grab the component from it and call the arePagePrerequisitesValid function.
let component = router.getRoutes().filter((x) => x.name === to.query.fmgPage)[0].components; let component = router.getRoutes().filter((x) => x.name === to.query.fmgPage)[0].components;
@ -133,10 +139,14 @@ function navigate(scenario, currentRoute, invalidateOnSave, optionalQuery = {},
return; return;
} }
// // here?? CSR-98
// baseMixin.methods.saveOrder();
// Match our maps up and navigate if we have a destination. // Match our maps up and navigate if we have a destination.
const matchingScenarioMap = getNavigationMap(scenario, currentRoute); const matchingScenarioMap = getNavigationMap(scenario, currentRoute);
const destinationFmgPageValue = matchingScenarioMap.destinationFmgPageValue;
if (matchingScenarioMap.destinationFmgPageValue !== undefined) { if (destinationFmgPageValue !== undefined) {
// We're always pushing the same path, just changing query strings. Make sure our optional query strings get combined with our fmgPage one. // We're always pushing the same path, just changing query strings. Make sure our optional query strings get combined with our fmgPage one.
// If we need to do invalidation // If we need to do invalidation
@ -147,17 +157,23 @@ function navigate(scenario, currentRoute, invalidateOnSave, optionalQuery = {},
} }
// Append page data to the store for the NEXT page, if any. It will be an empty object if none is provided. // Append page data to the store for the NEXT page, if any. It will be an empty object if none is provided.
baseMixin.methods.savePageDataToStore(matchingScenarioMap.destinationFmgPageValue, optionalPageData); baseMixin.methods.savePageDataToStore(destinationFmgPageValue, optionalPageData);
baseMixin.methods.saveOrder();
router.push({ router.push({
name: "root", name: "root",
query: Object.assign(optionalQuery, { query: Object.assign(optionalQuery, {
fmgPage: matchingScenarioMap.destinationFmgPageValue, fmgPage: destinationFmgPageValue,
}), }),
params: Object.assign(optionalParams, {[routerParameterKeys.FROM_ROUTER_NAVIGATE]: true}) params: Object.assign(optionalParams, {[routerParameterKeys.FROM_ROUTER_NAVIGATE]: true})
}); });
} else if (matchingScenarioMap.destinationUrl !== undefined) { } else if (matchingScenarioMap.destinationUrl !== undefined) {
navigateToUrl(matchingScenarioMap.destinationUrl); if (matchingScenarioMap.shouldNavigateToHeritageFunnel) {
baseMixin.methods.saveOrder();
}
navigateToUrl(matchingScenarioMap.destinationUrl, optionalQuery);
} }
} }
@ -178,9 +194,15 @@ function getNavigationMap(scenario, currentRoute) {
//---------------------------------------------------------- Private Functions ---------------------------------------------------------- //---------------------------------------------------------- Private Functions ----------------------------------------------------------
// Navigate to an external url. // Navigate to an external url.
function navigateToUrl(url) { function navigateToUrl(url, optionalQuery) {
// possibly show some loading screen in the future here. // possibly show some loading screen in the future here.
window.location.assign(url); var externalUrl = new URL(url);
for (const queryKey in optionalQuery) {
externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
}
window.location.assign(externalUrl);
} }
// Get route information by page name. // Get route information by page name.
@ -237,4 +259,20 @@ function resetDependentState(component) {
return component.default.methods.resetDependentState(); return component.default.methods.resetDependentState();
} }
// Read info from heritage funnel and reset state or load referral
function handleInfoFromHeritageFunnel() {
var orderInfoJson = baseMixin.methods.getCookieValue(cookieNames.ORDER_INFO);
var orderInfo = orderInfoJson == null ? null : JSON.parse(orderInfoJson);
if (orderInfo?.ShouldResetState) {
store.dispatch(storeActions.RESET_STATE);
}
else if (orderInfo != null) {
// should load referral here
}
// Delete cookie once state is loaded or reset
baseMixin.methods.deleteCookie(cookieNames.ORDER_INFO);
}
export default router; export default router;

View file

@ -0,0 +1,5 @@
const externalUrls = {
HERITAGE_FUNNEL: process.env.VUE_APP_HERITAGE_FUNNEL,
};
export { externalUrls };

View file

@ -4,9 +4,10 @@ const fmgPageValues = {
VEHICLE_MODEL: "vehicle-model", VEHICLE_MODEL: "vehicle-model",
VEHICLE_STYLE: "vehicle-style", VEHICLE_STYLE: "vehicle-style",
VEHICLE_DAMAGE: "vehicle-damage", VEHICLE_DAMAGE: "vehicle-damage",
VIN_LOOKUP: "vin-lookup",
VEHICLE_PARTS: "vehicle-parts", VEHICLE_PARTS: "vehicle-parts",
PART_QUESTIONS: "part-questions", PART_QUESTIONS: "part-questions",
REVEAL : "reveal", REVEAL : "reveal",
}; };
export { fmgPageValues }; export { fmgPageValues };

View file

@ -4,10 +4,12 @@ const navigationScenarios = {
SELECTED_MAKE: "SELECTED_MAKE", SELECTED_MAKE: "SELECTED_MAKE",
SELECTED_STYLE: "SELECTED_STYLE", SELECTED_STYLE: "SELECTED_STYLE",
CLICKED_BACK: "CLICKED_BACK", CLICKED_BACK: "CLICKED_BACK",
CLICKED_FORWARD: "CLICKED_FORWARD",
SELECTED_PARTS: "SELECTED_PARTS", SELECTED_PARTS: "SELECTED_PARTS",
SELECTED_DAMAGE_WITH_SINGLE_PART: "SELECTED_DAMAGE_WITH_SINGLE_PART", SELECTED_DAMAGE_WITH_SINGLE_PART: "SELECTED_DAMAGE_WITH_SINGLE_PART",
SELECTED_DAMAGE_WITH_MULTIPLE_PARTS: "SELECTED_DAMAGE_WITH_MULTIPLE_PARTS", SELECTED_DAMAGE_WITH_MULTIPLE_PARTS: "SELECTED_DAMAGE_WITH_MULTIPLE_PARTS",
SELECTED_DAMAGE_WITH_PART_QUESTIONS: "SELECTED_DAMAGE_WITH_PART_QUESTIONS" SELECTED_DAMAGE_WITH_PART_QUESTIONS: "SELECTED_DAMAGE_WITH_PART_QUESTIONS",
MOVE_TO_HERITAGE_FUNNEL: "MOVE_TO_HERITAGE_FUNNEL",
}; };
export { navigationScenarios }; export { navigationScenarios };

View file

@ -1,4 +1,5 @@
import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
import { externalUrls } from "@/router/router-constants/externalUrl-values";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
const routingTable = [ const routingTable = [
@ -57,9 +58,14 @@ const routingTable = [
scenario: navigationScenarios.CLICKED_BACK, scenario: navigationScenarios.CLICKED_BACK,
destinationFmgPageValue: fmgPageValues.VEHICLE_STYLE, destinationFmgPageValue: fmgPageValues.VEHICLE_STYLE,
}, },
{
scenario: navigationScenarios.MOVE_TO_HERITAGE_FUNNEL,
destinationUrl: externalUrls.HERITAGE_FUNNEL,
shouldNavigateToHeritageFunnel: true
},
{ {
scenario: navigationScenarios.SELECTED_DAMAGE_WITH_SINGLE_PART, scenario: navigationScenarios.SELECTED_DAMAGE_WITH_SINGLE_PART,
destinationFmgPageValue: fmgPageValues.REVEAL, destinationFmgPageValue: fmgPageValues.REVEAL
}, },
{ {
scenario: navigationScenarios.SELECTED_DAMAGE_WITH_MULTIPLE_PARTS, scenario: navigationScenarios.SELECTED_DAMAGE_WITH_MULTIPLE_PARTS,
@ -80,10 +86,27 @@ const routingTable = [
}, },
{ {
scenario: navigationScenarios.SELECTED_PARTS, scenario: navigationScenarios.SELECTED_PARTS,
destinationFmgPageValue: fmgPageValues.QUOTE,
},
{
scenario: navigationScenarios.CLICKED_FORWARD,
destinationFmgPageValue: fmgPageValues.REVEAL, destinationFmgPageValue: fmgPageValues.REVEAL,
}, },
], ],
}, },
{
fmgPageValue: fmgPageValues.REVEAL,
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
},
{
scenario: navigationScenarios.SELECTED_PARTS,
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP,
},
],
},
]; ];
export { routingTable }; export { routingTable };

View file

@ -7,34 +7,41 @@ import globalMethods from "@/global-methods";
// Export State // Export State
export const state = { const getDefaultState = () => {
order: { return {
vehicle: { order: {
year: null, vehicle: {
make: null, year: null,
model: null, make: null,
style: null, model: null,
carId: null, style: null,
category: null, carId: null,
imageUrl: null, category: null,
imageVifNumber: null, imageUrl: null,
imageColor: null, imageVifNumber: null,
imageColor: null,
},
damage: {
isRepair: null,
numberOfChips: null,
glassToReplace: null,
},
lineItems:{
glassParts: null,
otherParts: null
},
referralNumber: null,
referralDate: null,
referralCorrelationId: null,
}, },
damage: { applicationUser: {
isRepair: null, eventBus: [],
numberOfChips: null, pageData: {}
glassToReplace: null,
}, },
lineItems:{ }
glassParts: {}, };
otherParts: {}
} export const state = getDefaultState();
},
applicationUser: {
eventBus: [],
pageData: {}
},
}
// Export Mutations // Export Mutations
export const mutations = { export const mutations = {
@ -81,6 +88,15 @@ export const mutations = {
updatePageData(state, pageData){ updatePageData(state, pageData){
state.applicationUser.pageData[pageData.page] = pageData.data; state.applicationUser.pageData[pageData.page] = pageData.data;
}, },
updateReferralCorrelationId(state, referralCorrelationId) {
state.order.referralCorrelationId = referralCorrelationId;
},
updateReferralNumber(state, referralNumber) {
state.order.referralNumber = referralNumber;
},
updateReferralDate(state, referralDate) {
state.order.referralDate = referralDate;
},
// EVENT BUS MUTATIONS // EVENT BUS MUTATIONS
addEventToBus(state, event) { addEventToBus(state, event) {
@ -120,6 +136,9 @@ export const mutations = {
resetPartsState(state) { resetPartsState(state) {
state.order.lineItems.glassParts = null; state.order.lineItems.glassParts = null;
state.order.lineItems.otherParts = null; state.order.lineItems.otherParts = null;
},
resetState(state) {
Object.assign(state, getDefaultState());
} }
} }
@ -137,6 +156,9 @@ export const getters = {
eventBus: (state) => state.applicationUser.eventBus, eventBus: (state) => state.applicationUser.eventBus,
damage: (state) => state.order.damage, damage: (state) => state.order.damage,
lineItems: (state) => state.order.lineItems, lineItems: (state) => state.order.lineItems,
referralNumber: (state) => state.order.referralNumber,
referralDate: (state) => state.order.referralDate,
referralCorrelationId: (state) => state.order.referralCorrelationId,
pageData: (state) => (page) => { pageData: (state) => (page) => {
return state.applicationUser.pageData[page]; return state.applicationUser.pageData[page];
} }
@ -230,6 +252,9 @@ export const actions = {
resetPartsAndDependencies(context) { resetPartsAndDependencies(context) {
context.commit(storeMutations.RESET_PARTS_STATE); context.commit(storeMutations.RESET_PARTS_STATE);
}, },
resetState(context) {
context.commit(storeMutations.RESET_STATE);
},
// Content API Actions // Content API Actions
getRouteInfo(context, { pageName }) { getRouteInfo(context, { pageName }) {
@ -274,7 +299,31 @@ export const actions = {
vin: vin vin: vin
}, },
}); });
} },
// Order API Actions
saveOrder(context) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
return globalMethods.callHttpClient({
method: endpoints.SaveOrder.method,
endpoint: endpoints.SaveOrder.url,
payload: {
vehicle: {
carId: vehicle.carId,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
style: vehicle.style,
},
numberOfChips: damage.numberOfChips,
glassToReplace: damage.glassToReplace,
referralNumber: context.getters.referralNumber,
referralDate: context.getters.referralDate
},
});
},
} }
export default createStore({ export default createStore({

View file

@ -35,4 +35,3 @@ body {
overflow: hidden; overflow: hidden;
} }
} }
// Hide horizontal scrollbar

View file

@ -1,5 +1,7 @@
process.env.VUE_APP_CONSUMER_API_GATEWAY = process.env.VUE_APP_CONSUMER_API_GATEWAY =
"https://consumerapidev.safelite.com"; "https://consumerapidev.safelite.com";
process.env.VUE_APP_HERITAGE_FUNNEL =
"http://localhost:38000/default.aspx";
module.exports = { module.exports = {
outputDir: "dist/fmg", outputDir: "dist/fmg",
@ -19,4 +21,7 @@ module.exports = {
}, },
}, },
}, },
configureWebpack: {
devtool: 'source-map'
},
}; };

View file

@ -1,4 +1,5 @@
process.env.VUE_APP_CONSUMER_API_GATEWAY = "__VUE_APP_CONSUMER_API_GATEWAY__"; process.env.VUE_APP_CONSUMER_API_GATEWAY = "__VUE_APP_CONSUMER_API_GATEWAY__";
process.env.VUE_APP_HERITAGE_FUNNEL = "__VUE_APP_HERITAGE_FUNNEL__";
module.exports = { module.exports = {
outputDir: "dist/fmg", outputDir: "dist/fmg",