diff --git a/src/constants/package-names.js b/src/constants/package-names.js new file mode 100644 index 000000000..221a75a49 --- /dev/null +++ b/src/constants/package-names.js @@ -0,0 +1,5 @@ +export const packageNames = { + TIER_ONE: "TierOne", + TIER_TWO: "TierTwo", + TIER_THREE: "TierThree", +}; diff --git a/src/helpers/service-package-helper.js b/src/helpers/service-package-helper.js new file mode 100644 index 000000000..babdbfe7e --- /dev/null +++ b/src/helpers/service-package-helper.js @@ -0,0 +1,239 @@ +import { partTypeStrings } from "@/constants/part-type-strings"; +import { damageLocationsSelected as glassLocations } from "@/constants/damage-locations-selected"; +import { packageNames } from "@/constants/package-names"; + +export function containsLineItemWithPartType(typeToFind, itemsToSearch) { + const partTypeMatches = findLineItemsWithPartType(typeToFind, itemsToSearch); + return !!partTypeMatches?.length; +} + +export function findLineItemsWithPartType(typeToFind, itemsToSearch) { + const partTypeMatches = itemsToSearch?.filter( + (lineItem) => lineItem.partType.toUpperCase() === typeToFind.toUpperCase() + ); + + return partTypeMatches; +} + +export function getVapsLineItems(availableLineItems, vapTypes) { + let lineItems = []; + + for (let i = 0; i < vapTypes.length; i++) { + lineItems.push(...findLineItemsWithPartType(vapTypes[i], availableLineItems)); + } + + return lineItems; +} + +export function containsGlassPieceWithLocation(locationToFind, glassPiecesToSearch) { + const glassLocationMatches = glassPiecesToSearch?.filter( + (glassPiece) => glassPiece.glassLocation.toUpperCase() === locationToFind.toUpperCase() + ); + + return !!glassLocationMatches?.length; +} + +export function getAvailablePackages(glassToReplace, availableLineItems, isRepair) { + let tierOneVaps = getPackageContents( + glassToReplace, + availableLineItems, + isRepair, + packageNames.TIER_ONE + ); + let tierTwoVaps = getPackageContents( + glassToReplace, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + let tierThreeVaps = getPackageContents( + glassToReplace, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + if (tierTwoVaps.length === 0) { + return [ + { + packageName: packageNames.TIER_ONE, + vapTypes: tierOneVaps, + }, + { + packageName: packageNames.TIER_THREE, + vapTypes: tierThreeVaps, + }, + ]; + } else { + return [ + { + packageName: packageNames.TIER_ONE, + vapTypes: tierOneVaps, + }, + { + packageName: packageNames.TIER_TWO, + vapTypes: tierTwoVaps, + }, + { + packageName: packageNames.TIER_THREE, + vapTypes: tierThreeVaps, + }, + ]; + } +} + +export function getPackageContents(glassToReplace, availableLineItems, isRepair, targetTier) { + let vaps = []; + + if (shouldFrontWipersBeAvailable(glassToReplace, availableLineItems, isRepair, targetTier)) { + vaps.push(partTypeStrings.FRONT_WIPER); + } + if (shouldRearWipersBeAvailable(glassToReplace, availableLineItems, isRepair, targetTier)) { + vaps.push(partTypeStrings.REAR_WIPER); + } + if (shouldRainDefenseBeAvailable(glassToReplace, availableLineItems, isRepair, targetTier)) { + vaps.push(partTypeStrings.RAIN_DEFENSE); + } + + return vaps; +} + +export function shouldFrontWipersBeAvailable( + glassToReplace, + availableLineItems, + isRepair, + targetTier +) { + const frontWiperIsAvailable = containsLineItemWithPartType( + partTypeStrings.FRONT_WIPER, + availableLineItems + ); + const isFrontWindshieldTask = + isRepair || containsGlassPieceWithLocation(glassLocations.WINDSHIELD, glassToReplace); + + switch (targetTier) { + case packageNames.TIER_TWO: + return frontWiperIsAvailable && isFrontWindshieldTask; + case packageNames.TIER_THREE: + return frontWiperIsAvailable; + default: + return false; + } +} + +export function shouldRearWipersBeAvailable( + glassToReplace, + availableLineItems, + isRepair, + targetTier +) { + const rearWiperIsAvailable = containsLineItemWithPartType( + partTypeStrings.REAR_WIPER, + availableLineItems + ); + const frontWiperIsAvailable = containsLineItemWithPartType( + partTypeStrings.FRONT_WIPER, + availableLineItems + ); + const isRearWindshieldTask = containsGlassPieceWithLocation( + glassLocations.REAR, + glassToReplace + ); + + switch (targetTier) { + case packageNames.TIER_TWO: + return rearWiperIsAvailable && isRearWindshieldTask; + case packageNames.TIER_THREE: + return rearWiperIsAvailable && (isRearWindshieldTask || !frontWiperIsAvailable); + default: + return false; + } +} + +export function shouldRainDefenseBeAvailable( + glassToReplace, + availableLineItems, + isRepair, + targetTier +) { + const isTierThree = targetTier === packageNames.TIER_THREE; + const frontWipersInTierTwo = shouldFrontWipersBeAvailable( + glassToReplace, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + const frontWipersInTierThree = shouldFrontWipersBeAvailable( + glassToReplace, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + const rearWipersInTierTwo = shouldRearWipersBeAvailable( + glassToReplace, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + + return isTierThree && !(rearWipersInTierTwo && !frontWipersInTierTwo && frontWipersInTierThree); +} + +export function getLowestTierForType(glassToReplace, availableLineItems, isRepair, partType) { + const packages = getAvailablePackages(glassToReplace, availableLineItems, isRepair); + for (let i = 0; i < packages.length; i++) { + for (let j = 0; j < packages[i].vapTypes.length; j++) { + if (packages[i].vapTypes[j].toUpperCase() === partType.toUpperCase()) { + return packages[i].packageName; + } + } + } + + return packageNames.TIER_ONE; +} + +export function getHighestRequiredTier(glassToReplace, availableLineItems, isRepair, vaps) { + let currentHighestTier = packageNames.TIER_ONE; + for (let i = 0; i < vaps.length; i++) { + const lowestTierForItem = getLowestTierForType( + glassToReplace, + availableLineItems, + isRepair, + vaps[i].partType + ); + + currentHighestTier = maxTier(currentHighestTier, lowestTierForItem); + } + + return currentHighestTier; +} + +export function getHighestFullySatisfiedTier(glassToReplace, availableLineItems, isRepair, vaps) { + const packages = getAvailablePackages(glassToReplace, availableLineItems, isRepair); + let highestSatisfiedPackage = packageNames.TIER_ONE; + + for (let i = 0; i < packages.length; i++) { + let isPackageSatisfied = true; + for (let j = 0; j < packages[i].vapTypes.length; j++) { + isPackageSatisfied = + isPackageSatisfied && containsLineItemWithPartType(packages[i].vapTypes[j], vaps); + } + if (isPackageSatisfied) { + highestSatisfiedPackage = packages[i].packageName; + } + } + + return highestSatisfiedPackage; +} + +function maxTier(tierA, tierB) { + if (tierA === packageNames.TIER_THREE || tierB === packageNames.TIER_THREE) { + return packageNames.TIER_THREE; + } + + if (tierA === packageNames.TIER_TWO || tierB === packageNames.TIER_TWO) { + return packageNames.TIER_TWO; + } + + return packageNames.TIER_ONE; +} diff --git a/src/helpers/service-package-helper.spec.js b/src/helpers/service-package-helper.spec.js new file mode 100644 index 000000000..abcafd82c --- /dev/null +++ b/src/helpers/service-package-helper.spec.js @@ -0,0 +1,1023 @@ +import * as servicePackageHelper from "@/helpers/service-package-helper"; +import { partTypeStrings } from "@/constants/part-type-strings"; +import { damageLocationsSelected as glassLocations } from "@/constants/damage-locations-selected"; +import { packageNames } from "@/constants/package-names"; + +describe("service-package-helper.js", () => { + describe("containsLineItemWithPartType", () => { + it("Returns true when type is present", () => { + // Arrange + const lineItems = [ + recalLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + ]; + const partType = partTypeStrings.RAIN_DEFENSE; + + // Act + const result = servicePackageHelper.containsLineItemWithPartType(partType, lineItems); + + // Assert + expect(result).toBe(true); + }); + + it("Returns true when type is present multiple times", () => { + // Arrange + const lineItems = [ + recalLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + ]; + const partType = partTypeStrings.FRONT_WIPER; + + // Act + const result = servicePackageHelper.containsLineItemWithPartType(partType, lineItems); + + // Assert + expect(result).toBe(true); + }); + + it("Returns false when type is not present", () => { + // Arrange + const lineItems = [ + recalLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + ]; + const partType = partTypeStrings.RAIN_DEFENSE; + + // Act + const result = servicePackageHelper.containsLineItemWithPartType(partType, lineItems); + + // Assert + expect(result).toBe(false); + }); + + it("Returns false with empty array", () => { + // Arrange + const lineItems = []; + const partType = partTypeStrings.RAIN_DEFENSE; + + // Act + const result = servicePackageHelper.containsLineItemWithPartType(partType, lineItems); + + // Assert + expect(result).toBe(false); + }); + }); + + describe("findLineItemsWithPartType", () => { + it("Returns an item of the same type when present", () => { + // Arrange + const lineItems = [ + recalLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + ]; + const partType = partTypeStrings.RAIN_DEFENSE; + + // Act + const result = servicePackageHelper.findLineItemsWithPartType(partType, lineItems); + + // Assert + expect(result.length).toBe(1); + expect(result[0].partType).toEqual(partType); + }); + + it("Returns an empty array when no matching items are present", () => { + // Arrange + const lineItems = [ + recalLineItem, + passengerFrontWiperLineItem, + driverFrontWiperLineItem, + ]; + const partType = partTypeStrings.RAIN_DEFENSE; + + // Act + const result = servicePackageHelper.findLineItemsWithPartType(partType, lineItems); + + // Assert + expect(result.length).toBe(0); + }); + + it("Returns all matching items when multiple are present", () => { + // Arrange + const lineItems = [ + recalLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + ]; + const partType = partTypeStrings.FRONT_WIPER; + + // Act + const result = servicePackageHelper.findLineItemsWithPartType(partType, lineItems); + + // Assert + expect(result.length).toBe(2); + expect(result[0].partType).toEqual(partType); + expect(result[1].partType).toEqual(partType); + expect(result[0].partNumber).not.toEqual(result[1].partNumber); + }); + + it("Is not case sensitive", () => { + // Arrange + const lineItems = [ + recalLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + ]; + const partType = "rAin DEfenSe"; + + // Act + const result = servicePackageHelper.findLineItemsWithPartType(partType, lineItems); + + // Assert + expect(result.length).toBe(1); + expect(result[0].partType).toEqual(partTypeStrings.RAIN_DEFENSE); + }); + }); + + describe("getVapsLineItems", () => { + it("Returns line items matching given types", () => { + // Arrange + const lineItems = [ + recalLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + ]; + + const vapTypes = [partTypeStrings.RAIN_DEFENSE]; + + // Act + const result = servicePackageHelper.getVapsLineItems(lineItems, vapTypes); + + // Assert + expect(result.length).toBe(1); + expect(result[0].partType).toEqual(partTypeStrings.RAIN_DEFENSE); + }); + + it("Returns all matching line items, when multiple match a single type", () => { + // Arrange + const lineItems = [ + recalLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + ]; + + const vapTypes = [partTypeStrings.FRONT_WIPER]; + + // Act + const result = servicePackageHelper.getVapsLineItems(lineItems, vapTypes); + + // Assert + expect(result.length).toBe(2); + expect(result[0].partType).toEqual(partTypeStrings.FRONT_WIPER); + expect(result[1].partType).toEqual(partTypeStrings.FRONT_WIPER); + expect(result[0].partNumber).not.toEqual(result[1].partNumber); + }); + + it("Returns only line items in the given set", () => { + // Arrange + const lineItems = [recalLineItem, passengerFrontWiperLineItem, rainDefenseLineItem]; + + const vapTypes = [partTypeStrings.FRONT_WIPER]; + + // Act + const result = servicePackageHelper.getVapsLineItems(lineItems, vapTypes); + + // Assert + expect(result.length).toBe(1); + expect(result[0].partType).toEqual(partTypeStrings.FRONT_WIPER); + expect(result[0].partNumber).toEqual(passengerFrontWiperLineItem.partNumber); + }); + + it("Returns all matching items when multiple vap types are requested", () => { + // Arrange + const lineItems = [recalLineItem, passengerFrontWiperLineItem, rainDefenseLineItem]; + + const vapTypes = [partTypeStrings.FRONT_WIPER, partTypeStrings.RAIN_DEFENSE]; + + // Act + const result = servicePackageHelper.getVapsLineItems(lineItems, vapTypes); + + // Assert + expect(result.length).toBe(2); + expect(result[0].partType).not.toEqual(result[1].partType); + }); + }); + + describe("containsGlassPieceWithLocation", () => { + it("Returns true when location is present", () => { + // Arrange + const locations = [frontWindshieldGlass, sideGlass]; + + const locationName = glassLocations.WINDSHIELD; + + // Act + const result = servicePackageHelper.containsGlassPieceWithLocation( + locationName, + locations + ); + + // Assert + expect(result).toBe(true); + }); + + it("Returns true when location is present multiple times", () => { + // Arrange + const locations = [frontWindshieldGlass, frontWindshieldGlass, sideGlass]; + + const locationName = glassLocations.WINDSHIELD; + + // Act + const result = servicePackageHelper.containsGlassPieceWithLocation( + locationName, + locations + ); + + // Assert + expect(result).toBe(true); + }); + + it("Returns false when location is not present", () => { + // Arrange + const locations = [frontWindshieldGlass, sideGlass]; + + const locationName = glassLocations.REAR; + + // Act + const result = servicePackageHelper.containsGlassPieceWithLocation( + locationName, + locations + ); + + // Assert + expect(result).toBe(false); + }); + + it("Returns false with empty array", () => { + // Arrange + const locations = []; + + const locationName = glassLocations.WINDSHIELD; + + // Act + const result = servicePackageHelper.containsGlassPieceWithLocation( + locationName, + locations + ); + + // Assert + expect(result).toBe(false); + }); + + it("Is not case sensitive", () => { + // Arrange + const locations = [frontWindshieldGlass, sideGlass]; + + const locationName = "windShieLd"; + + // Act + const result = servicePackageHelper.containsGlassPieceWithLocation( + locationName, + locations + ); + + // Assert + expect(result).toBe(true); + }); + }); + + describe("getAvailablePackages", () => { + it("Returns two packages when there is not a viable tier-two option.", () => { + // Arrange + const damageLocations = [sideGlass]; + + const availableLineItems = [rainDefenseLineItem]; + + // Act + const results = servicePackageHelper.getAvailablePackages( + damageLocations, + availableLineItems, + false + ); + + // Assert + expect(results.length).toBe(2); + expect(results[0].packageName).toEqual(packageNames.TIER_ONE); + expect(results[1].packageName).toEqual(packageNames.TIER_THREE); + }); + + it("Returns three packages when wipers are available in tier two", () => { + // Arrange + const damageLocations = [rearWindshieldGlass]; + + const availableLineItems = [ + driverFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + + // Act + const results = servicePackageHelper.getAvailablePackages( + damageLocations, + availableLineItems, + true + ); + + // Assert + expect(results.length).toBe(3); + expect(results[0].packageName).toEqual(packageNames.TIER_ONE); + expect(results[1].packageName).toEqual(packageNames.TIER_TWO); + expect(results[2].packageName).toEqual(packageNames.TIER_THREE); + }); + }); + + describe("getPackageContents", () => { + describe("Match figma cases", () => { + test.todo("Implement specific cases."); + }); + }); + + describe("shouldFrontWipersBeAvailable", () => { + it("Should be available in tier 2 and 3 if windshield damage and available", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [driverFrontWiperLineItem, passengerFrontWiperLineItem]; + const isRepair = false; + + // Act + const resultTwo = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + const resultThree = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(resultTwo).toBe(true); + expect(resultThree).toBe(true); + }); + + it("Should be available in tier 2 and 3 if repair and available", () => { + // Arrange + const damageLocations = []; + const availableLineItems = [driverFrontWiperLineItem, passengerFrontWiperLineItem]; + const isRepair = true; + + // Act + const resultTwo = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + const resultThree = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(resultTwo).toBe(true); + expect(resultThree).toBe(true); + }); + + it("Should not be available in tier 2 if not windshield damage or repair", () => { + // Arrange + const damageLocations = []; + const availableLineItems = [driverFrontWiperLineItem, passengerFrontWiperLineItem]; + const isRepair = false; + + // Act + const result = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + + // Assert + expect(result).toBe(false); + }); + + it("Should be available in tier 3 even if not windshield repair or replace", () => { + // Arrange + const damageLocations = []; + const availableLineItems = [driverFrontWiperLineItem, passengerFrontWiperLineItem]; + const isRepair = false; + + // Act + const result = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(result).toBe(true); + }); + + it("Should not be available in any tier if not available.", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = []; + const isRepair = true; + + // Act + const resultOne = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_ONE + ); + const resultTwo = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + const resultThree = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(resultOne).toBe(false); + expect(resultTwo).toBe(false); + expect(resultThree).toBe(false); + }); + + it("Should not be available in tier 1", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [driverFrontWiperLineItem, passengerFrontWiperLineItem]; + const isRepair = true; + + // Act + const result = servicePackageHelper.shouldFrontWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_ONE + ); + + // Assert + expect(result).toBe(false); + }); + }); + + describe("shouldRearWipersBeAvailable", () => { + it("Should be available in tier 2 and 3 if rear damage and available", () => { + // Arrange + const damageLocations = [rearWindshieldGlass]; + const availableLineItems = [rearWiperLineItem]; + const isRepair = false; + + // Act + const resultTwo = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + const resultThree = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(resultTwo).toBe(true); + expect(resultThree).toBe(true); + }); + + it("Should not be available in tier 2 if not rear damage", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [rearWiperLineItem]; + const isRepair = false; + + // Act + const result = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + + // Assert + expect(result).toBe(false); + }); + + it("Should be available in tier 3 without rear damage, if available and no front wipers available", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [rearWiperLineItem]; + const isRepair = false; + + // Act + const result = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(result).toBe(true); + }); + + it("Should not be available in tier 3 without rear damage if front wipers are available", () => { + // Arrange + const damageLocations = []; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + ]; + const isRepair = false; + + // Act + const result = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(result).toBe(false); + }); + + it("Should not be available in any tier if not available", () => { + // Arrange + const damageLocations = [rearWindshieldGlass]; + const availableLineItems = []; + const isRepair = false; + + // Act + const resultOne = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_ONE + ); + const resultTwo = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + const resultThree = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(resultOne).toBe(false); + expect(resultTwo).toBe(false); + expect(resultThree).toBe(false); + }); + + it("Should not be available in tier 1", () => { + // Arrange + const damageLocations = [rearWindshieldGlass]; + const availableLineItems = [rearWiperLineItem]; + const isRepair = false; + + // Act + const result = servicePackageHelper.shouldRearWipersBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_ONE + ); + + // Assert + expect(result).toBe(false); + }); + }); + + describe("shouldRainDefenseBeAvailable", () => { + it("Should generally be available only in tier 3", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [ + rainDefenseLineItem, + driverFrontWiperLineItem, + rearWiperLineItem, + recalLineItem, + ]; + const isRepair = false; + + // Act + const resultOne = servicePackageHelper.shouldRainDefenseBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_ONE + ); + const resultTwo = servicePackageHelper.shouldRainDefenseBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_TWO + ); + const resultThree = servicePackageHelper.shouldRainDefenseBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(resultOne).toBe(false); + expect(resultTwo).toBe(false); + expect(resultThree).toBe(true); + }); + + it("Should not be available in a specific scenario", () => { + // Arrange + // SPECIFICALLY: no front windshield + const damageLocations = [rearWindshieldGlass]; + const availableLineItems = [ + rainDefenseLineItem, + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + ]; + // SPECIFICALLY: not repair + const isRepair = false; + + // Act + const result = servicePackageHelper.shouldRainDefenseBeAvailable( + damageLocations, + availableLineItems, + isRepair, + packageNames.TIER_THREE + ); + + // Assert + expect(result).toBe(false); + }); + }); + + describe("getLowestTierForType", () => { + it("Should return the tier for items available in one tier only", () => { + // Arrange + const damageLocations = [frontWindshieldGlass, rearWindshieldGlass]; + + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + + const isRepair = false; + + // Act + const result = servicePackageHelper.getLowestTierForType( + damageLocations, + availableLineItems, + isRepair, + partTypeStrings.RAIN_DEFENSE + ); + + // Assert + expect(result).toEqual(packageNames.TIER_THREE); + }); + + it("Should return tier 2 for items in tier 2 and 3", () => { + // Arrange + const damageLocations = [frontWindshieldGlass, rearWindshieldGlass]; + + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + + const isRepair = false; + + // Act + const resultFront = servicePackageHelper.getLowestTierForType( + damageLocations, + availableLineItems, + isRepair, + partTypeStrings.FRONT_WIPER + ); + const resultRear = servicePackageHelper.getLowestTierForType( + damageLocations, + availableLineItems, + isRepair, + partTypeStrings.REAR_WIPER + ); + + // Assert + expect(resultFront).toEqual(packageNames.TIER_TWO); + expect(resultRear).toEqual(packageNames.TIER_TWO); + }); + + it("Should return tier 1 for any item not in any tier", () => { + // Arrange + const damageLocations = [rearWindshieldGlass]; + + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + ]; + + const isRepair = false; + + // Act + const resultFront = servicePackageHelper.getLowestTierForType( + damageLocations, + availableLineItems, + isRepair, + partTypeStrings.RAIN_DEFENSE + ); + + // Assert + expect(resultFront).toEqual(packageNames.TIER_ONE); + }); + }); + + describe("getHighestRequiredTier", () => { + it("Should return the highest tier among items", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + const isRepair = false; + const vaps = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + ]; + + // Act + const result = servicePackageHelper.getHighestRequiredTier( + damageLocations, + availableLineItems, + isRepair, + vaps + ); + + // Assert + expect(result).toEqual(packageNames.TIER_THREE); + }); + + it("Should not return a higher tier than items require", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + const isRepair = false; + const vaps = [driverFrontWiperLineItem, passengerFrontWiperLineItem]; + + // Act + const result = servicePackageHelper.getHighestRequiredTier( + damageLocations, + availableLineItems, + isRepair, + vaps + ); + + // Assert + expect(result).toEqual(packageNames.TIER_TWO); + }); + + it("Should return tier 1 for empty set", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + const isRepair = false; + const vaps = []; + + // Act + const result = servicePackageHelper.getHighestRequiredTier( + damageLocations, + availableLineItems, + isRepair, + vaps + ); + + // Assert + expect(result).toEqual(packageNames.TIER_ONE); + }); + + it("Should return tier 1 if no vaps are part of tiers", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + const isRepair = false; + const vaps = [recalLineItem]; + + // Act + const result = servicePackageHelper.getHighestRequiredTier( + damageLocations, + availableLineItems, + isRepair, + vaps + ); + + // Assert + expect(result).toEqual(packageNames.TIER_ONE); + }); + }); + + describe("getHighestSatisfiedTier", () => { + it("Should return the highest tier if multiple are satisfied", () => { + // Arrange + const damageLocations = [frontWindshieldGlass, rearWindshieldGlass]; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + const isRepair = false; + const vaps = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rainDefenseLineItem, + rearWiperLineItem, + ]; + + // Act + const result = servicePackageHelper.getHighestFullySatisfiedTier( + damageLocations, + availableLineItems, + isRepair, + vaps + ); + + // Assert + expect(result).toEqual(packageNames.TIER_THREE); + }); + + it("Should only return *satisfied* tier", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + const isRepair = false; + const vaps = [driverFrontWiperLineItem, passengerFrontWiperLineItem]; + + // Act + const result = servicePackageHelper.getHighestFullySatisfiedTier( + damageLocations, + availableLineItems, + isRepair, + vaps + ); + + // Assert + expect(result).toEqual(packageNames.TIER_TWO); + }); + + it("Should not return a tier if it is only partially satisfied", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + const isRepair = false; + const vaps = [rainDefenseLineItem]; + + // Act + const result = servicePackageHelper.getHighestFullySatisfiedTier( + damageLocations, + availableLineItems, + isRepair, + vaps + ); + + // Assert + expect(result).toEqual(packageNames.TIER_ONE); + }); + + it("Should return tier 1 if no vaps are selected.", () => { + // Arrange + const damageLocations = [frontWindshieldGlass]; + const availableLineItems = [ + driverFrontWiperLineItem, + passengerFrontWiperLineItem, + rearWiperLineItem, + rainDefenseLineItem, + ]; + const isRepair = false; + const vaps = []; + + // Act + const result = servicePackageHelper.getHighestFullySatisfiedTier( + damageLocations, + availableLineItems, + isRepair, + vaps + ); + + // Assert + expect(result).toEqual(packageNames.TIER_ONE); + }); + }); +}); + +// Constants + +const recalLineItem = { + partNumber: "RECAL STATIC", + Description: "Recalibration", + partType: "recalibration", + Quantity: "1", + price: 150.0, +}; + +const driverFrontWiperLineItem = { + partNumber: "SBB16", + description: "SAFELITE BEAM BLADE 16", + partType: "FRONT WIPER", + price: 32.64, +}; + +const passengerFrontWiperLineItem = { + partNumber: "SBB26", + description: "SAFELITE BEAM BLADE 26", + partType: "FRONT WIPER", + price: 53.04, +}; + +const rearWiperLineItem = { + partNumber: "SBBR12A", + description: "SAFELITE REAR BLADE 12A", + partType: "REAR WIPER", + price: 24.48, +}; + +const rainDefenseLineItem = { + partNumber: "RAIN DEFENSE", + description: null, + partType: "RAIN DEFENSE", + price: 35.5, +}; + +const frontWindshieldGlass = { + glassLocation: "Windshield", +}; + +const rearWindshieldGlass = { + glassLocation: "Rear", +}; + +const sideGlass = { + glassLocation: "Driver", +}; diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index 29e6a9a9e..51598631b 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -18,12 +18,17 @@ import { processIfStatements } from "@/helpers/cms-content-helper"; import { damageLocationsSelected as glassLocations } from "@/constants/damage-locations-selected"; import servicePackageRadio from "./service-package-radio/service-package-radio"; import { partTypeStrings } from "@/constants/part-type-strings"; - -const packageNames = { - TIER_ONE: "TierOne", - TIER_TWO: "TierTwo", - TIER_THREE: "TierThree", -}; +import { packageNames } from "@/constants/package-names"; +import { + shouldFrontWipersBeAvailable, + shouldRearWipersBeAvailable, + shouldRainDefenseBeAvailable, + getAvailablePackages, + getHighestRequiredTier, + getPackageContents, + containsLineItemWithPartType, + findLineItemsWithPartType, +} from "@/helpers/service-package-helper"; export default { name: "servicePackageQuestion", @@ -65,11 +70,17 @@ export default { if (!cmsAnswersContent) { return null; } - if (!this.shouldDisplayTierTwoPackage) { - cmsAnswersContent = cmsAnswersContent.filter( - (answer) => answer.Name != packageNames.TIER_TWO - ); - } + + const availablePackages = getAvailablePackages( + this.glassToReplace, + this.nullSafeAvailableLineItems, + this.isRepair + ); + + cmsAnswersContent = cmsAnswersContent.filter((answer) => + availablePackages.some((tier) => answer.Name === tier.packageName) + ); + const modifiedAnswers = cmsAnswersContent.map((answer) => ({ value: answer.Name, buttonLabel: this.getHeaderTextFromCms(answer.SubWidgetName), @@ -81,67 +92,56 @@ export default { return modifiedAnswers; }, isRecalibrationOnOrder() { - return this.lineItemsContainsPartType(partTypeStrings.RECALIBRATION); + return containsLineItemWithPartType( + partTypeStrings.RECALIBRATION, + this.nullSafeAvailableLineItems + ); }, frontWipersApplicableForTierTwo() { - const frontWipersAreAvailable = this.lineItemsContainsPartType( - partTypeStrings.FRONT_WIPER + return shouldFrontWipersBeAvailable( + this.glassToReplace, + this.nullSafeAvailableLineItems, + this.isRepair, + packageNames.TIER_TWO ); - const isRepair = this.$store.getters.order.damage.isRepair; - const glassToReplaceContainsWindshield = this.glassToReplaceContainsGlassLocation( - glassLocations.WINDSHIELD - ); - if (frontWipersAreAvailable) { - if (isRepair) { - return true; - } else { - if (glassToReplaceContainsWindshield) { - return true; - } else { - return false; - } - } - } else { - return false; - } }, rearWiperApplicableForTierTwo() { - const rearWiperIsAvailable = this.lineItemsContainsPartType(partTypeStrings.REAR_WIPER); - return ( - this.glassToReplaceContainsGlassLocation(glassLocations.REAR) && - rearWiperIsAvailable + return shouldRearWipersBeAvailable( + this.glassToReplace, + this.nullSafeAvailableLineItems, + this.isRepair, + packageNames.TIER_TWO ); }, frontWipersApplicableForTierThree() { - const frontWipersAreAvailable = this.lineItemsContainsPartType( - partTypeStrings.FRONT_WIPER + return shouldFrontWipersBeAvailable( + this.glassToReplace, + this.nullSafeAvailableLineItems, + this.isRepair, + packageNames.TIER_THREE ); - return frontWipersAreAvailable; }, rearWiperApplicableForTierThree() { - const rearWiperIsAvailable = this.lineItemsContainsPartType(partTypeStrings.REAR_WIPER); - const frontWipersAreAvailable = this.lineItemsContainsPartType( - partTypeStrings.FRONT_WIPER - ); - return ( - rearWiperIsAvailable && - (this.glassToReplaceContainsGlassLocation(glassLocations.REAR) || - !frontWipersAreAvailable) + return shouldRearWipersBeAvailable( + this.glassToReplace, + this.nullSafeAvailableLineItems, + this.isRepair, + packageNames.TIER_THREE ); }, rainDefenseApplicableForTierThree() { - if ( - this.rearWiperApplicableForTierTwo && - !this.frontWipersApplicableForTierTwo && - this.frontWipersApplicableForTierThree - ) { - return false; - } else { - return true; - } + return shouldRainDefenseBeAvailable( + this.glassToReplace, + this.nullSafeAvailableLineItems, + this.isRepair, + packageNames.TIER_THREE + ); }, - shouldDisplayTierTwoPackage() { - return this.frontWipersApplicableForTierTwo || this.rearWiperApplicableForTierTwo; + glassToReplace() { + return this.$store.getters.order.damage.glassToReplace; + }, + isRepair() { + return this.$store.getters.order.damage.isRepair; }, }, methods: { @@ -170,65 +170,31 @@ export default { : baseMixin.methods.getTierOnePackagePrice( baseMixin.methods.filterOutFees(this.nullSafeAvailableLineItems) ); - if (packageName === packageNames.TIER_TWO) { - priceFloat += this.getTierTwoPackageVapsPrice(); - } else if (packageName === packageNames.TIER_THREE) { - priceFloat += this.getTierThreePackageVapsPrice(); - } + + priceFloat += this.getVapsPrice(packageName); + return priceFloat; }, - getTierTwoPackageVapsPrice() { - let vapsPrice = 0; - const priceFrontWipers = this.frontWipersApplicableForTierTwo; - const priceRearWipers = this.rearWiperApplicableForTierTwo; - this.nullSafeAvailableLineItems.forEach((item) => { - if ( - (priceFrontWipers && - item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER) || - (priceRearWipers && item.partType.toUpperCase() === partTypeStrings.REAR_WIPER) - ) { - vapsPrice += baseMixin.methods.getTotalLineItemPrice(item); - } + getVapsPrice(packageName) { + const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName); + + let price = 0; + + vapsItems.forEach((item) => { + price += baseMixin.methods.getTotalLineItemPrice(item); }); - return vapsPrice; - }, - getTierThreePackageVapsPrice() { - let vapsPrice = 0; - const priceFrontWipers = this.frontWipersApplicableForTierThree; - const priceRearWipers = this.rearWiperApplicableForTierThree; - const priceRainDefense = this.rainDefenseApplicableForTierThree; - this.nullSafeAvailableLineItems.forEach((item) => { - if ( - (priceFrontWipers && - item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER) || - (priceRearWipers && - item.partType.toUpperCase() === partTypeStrings.REAR_WIPER) || - (priceRainDefense && - item.partType.toUpperCase() === partTypeStrings.RAIN_DEFENSE) - ) { - vapsPrice += baseMixin.methods.getTotalLineItemPrice(item); - } - }); - return vapsPrice; + + return price; }, selectDefaultPackage() { - const vapsFromStore = this.$store.getters.lineItems.vaps; - let lowestTierForPackage = packageNames.TIER_ONE; - if (vapsFromStore?.length > 0) { - vapsFromStore.every((vapsItem) => { - let lowestTierForThisItem = this.getLowestTierForThisItem(vapsItem); - if (lowestTierForThisItem === packageNames.TIER_THREE) { - lowestTierForPackage = packageNames.TIER_THREE; - return false; - } else if (lowestTierForThisItem === packageNames.TIER_TWO) { - lowestTierForPackage = packageNames.TIER_TWO; - return true; - } else { - return true; - } - }); - } - this.selectedPackageName = lowestTierForPackage; + const vapsFromStore = this.$store.getters.lineItems.vaps ?? []; + + this.selectedPackageName = getHighestRequiredTier( + this.glassToReplace, + this.nullSafeAvailableLineItems, + this.isRepair, + vapsFromStore + ); }, allGlassPartsAndSupportingItemsHavePrices(lineItems) { if (lineItems?.glassParts) { @@ -254,63 +220,22 @@ export default { (lineItem.sellingPrice == null || lineItem.sellingPrice == 0) ); }, - getLowestTierForThisItem(vapsItem) { - let lowestTierForThisItem = null; - switch (vapsItem.partType) { - case partTypeStrings.FRONT_WIPER: - if (this.frontWipersApplicableForTierThree) { - lowestTierForThisItem = packageNames.TIER_THREE; - } - if (this.frontWipersApplicableForTierTwo) { - lowestTierForThisItem = packageNames.TIER_TWO; - } - break; - case partTypeStrings.REAR_WIPER: - if (this.rearWiperApplicableForTierThree) { - lowestTierForThisItem = packageNames.TIER_THREE; - } - if (this.rearWiperApplicableForTierTwo) { - lowestTierForThisItem = packageNames.TIER_TWO; - } - break; - case partTypeStrings.RAIN_DEFENSE: - if (this.rainDefenseApplicableForTierThree) { - lowestTierForThisItem = packageNames.TIER_THREE; - } - break; - } - return lowestTierForThisItem; - }, getVapsLineItemsForSelectedPackage(packageName) { - const vapsLineItemsForSelectedPackage = []; - if (packageName === packageNames.TIER_TWO) { - if (this.frontWipersApplicableForTierTwo) { - vapsLineItemsForSelectedPackage.push( - ...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER) - ); - } - if (this.rearWiperApplicableForTierTwo) { - vapsLineItemsForSelectedPackage.push( - ...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER) - ); - } - } else if (packageName === packageNames.TIER_THREE) { - if (this.frontWipersApplicableForTierThree) { - vapsLineItemsForSelectedPackage.push( - ...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER) - ); - } - if (this.rearWiperApplicableForTierThree) { - vapsLineItemsForSelectedPackage.push( - ...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER) - ); - } - if (this.rainDefenseApplicableForTierThree) { - vapsLineItemsForSelectedPackage.push( - ...this.getLineItemsContainingPartType(partTypeStrings.RAIN_DEFENSE) - ); - } - } + const packageContentTypes = getPackageContents( + this.glassToReplace, + this.nullSafeAvailableLineItems, + this.isRepair, + packageName + ); + + let vapsLineItemsForSelectedPackage = []; + + packageContentTypes.forEach((vapType) => { + vapsLineItemsForSelectedPackage.push( + ...findLineItemsWithPartType(vapType, this.nullSafeAvailableLineItems) + ); + }); + return vapsLineItemsForSelectedPackage; }, getCustomValueFromString(str) { @@ -331,23 +256,6 @@ export default { return null; } }, - getLineItemsContainingPartType(partType) { - const partTypeMatches = this.nullSafeAvailableLineItems.filter( - (lineItem) => lineItem.partType.toUpperCase() === partType - ); - return partTypeMatches; - }, - lineItemsContainsPartType(partType) { - const partTypeMatches = this.getLineItemsContainingPartType(partType); - return !!partTypeMatches.length; - }, - glassToReplaceContainsGlassLocation(glassLocation) { - const glassLocationMatches = - this.$store.getters.order.damage.glassToReplace?.filter( - (glassToReplace) => glassToReplace.glassLocation === glassLocation - ) ?? []; - return !!glassLocationMatches.length; - }, }, components: { buttonQuestion, diff --git a/src/layouts/review/review-block/review-block.vue b/src/layouts/review/review-block/review-block.vue index 0b1f913c3..e1a8e0128 100644 --- a/src/layouts/review/review-block/review-block.vue +++ b/src/layouts/review/review-block/review-block.vue @@ -5,7 +5,12 @@ :cmsWidgetName="headerCmsWidgetName" typeStyle="body small bold dark" margin="mt-0" /> - +
{{ item }} diff --git a/src/layouts/review/review-sections/service-package-review/service-package-review.spec.js b/src/layouts/review/review-sections/service-package-review/service-package-review.spec.js new file mode 100644 index 000000000..fc8b1ce5c --- /dev/null +++ b/src/layouts/review/review-sections/service-package-review/service-package-review.spec.js @@ -0,0 +1,969 @@ +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import servicePackageReview from "@/layouts/review/review-sections/service-package-review/service-package-review"; + +import { packageNames } from "@/constants/package-names"; +import { partTypeStrings } from "@/constants/part-type-strings"; +import { damageLocationsSelected as glassConstants } from "@/constants/damage-locations-selected"; + +const testConstants = { + cmsPropValues: { + servicePackageOptionsCmsName: "ServicePackageTitle", + defaultPackageItemsCmsName: "DefaultPackageItemDescriptions", + vapsItemsCmsName: "VapsItemDescriptions", + }, + widgetNames: { + tierOneTitle: "EconomyServiceTitle", + tierTwoTitle: "StandardServiceTitle", + tierThreeTitle: "PremiumServiceTitle", + }, + defaultItemCopy: { + itemOne: "Item Description 1", + itemTwo: "Item Description 2", + itemThree: "Item Description 3", + itemFour: "Item Description 4", + defaultItemCopyArray: ["Item Description 1", "Item Description 2", "Item Description 3"], + }, + vapsCopy: { + frontWiperCopy: "Front Wiper copy", + rearWiperCopy: "Rear Wiper copy", + rainDefenseCopy: "Rain defense copy", + }, + parts: { + frontWiperPart: { + partNumber: "SBB16", + description: "SAFELITE BEAM BLADE 16", + partType: "FRONT WIPER", + price: 32.64, + }, + rearWiperPart: { + partNumber: "SBBR12A", + description: "SAFELITE REAR BLADE 12A", + partType: "REAR WIPER", + price: 24.48, + }, + rainDefensePart: { + partNumber: "RAIN DEFENSE", + description: null, + partType: "RAIN DEFENSE", + price: 35.5, + }, + recalPart: { + partNumber: "RECAL STATIC", + Description: "Recalibration", + partType: "recalibration", + Quantity: "1", + price: 150.0, + }, + }, + damages: { + frontWindshield: { + glassLocation: glassConstants.WINDSHIELD, + glassName: glassConstants.SINGLE, + }, + rearWindshield: { + glassLocation: glassConstants.REAR, + glassName: glassConstants.STATIONARY, + }, + sideGlass: { + glassLocation: glassConstants.PASSENGER, + glassName: glassConstants.QUARTER, + }, + }, + imageId: "00000000-0000-0000-0000-000000000000", +}; + +const figmaScenarios = [ + { + name: "05_01_CSR_Quote_Cash", + params: { + availableVaps: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart, + testConstants.parts.rainDefensePart, + ], + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.frontWindshield], + }, + glassParts: [], + supportingItems: [], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Standard", + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + ], + }, + }, + { + name: "Premium", + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart, + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Standard+RearWiper", + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + ], + }, + // 05_01_CSR_Quote_Standard_Repair & 05_01_CSR_Quote_Recal have identical outcomes to above, but included in case that changes in the future. + { + name: "05_01_CSR_Quote_Standard_Repair", + params: { + availableVaps: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart, + testConstants.parts.rainDefensePart, + ], + damage: { + isRepair: true, + glassToReplace: [], + }, + glassParts: [], + supportingItems: [], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Standard", + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + ], + }, + }, + { + name: "Premium", + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart, + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Standard+RearWiper", + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + ], + }, + { + name: "05_01_CSR_Quote_Recal", + params: { + availableVaps: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart, + testConstants.parts.rainDefensePart, + ], + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.frontWindshield], + }, + glassParts: [], + supportingItems: [testConstants.parts.recalPart], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Standard", + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + ], + }, + }, + { + name: "Premium", + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart, + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Standard+RearWiper", + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + ], + }, + // 05_01_CSR_Quote_RearGlass omitted as a duplicate of below. + { + name: "05_01_CSR_Quote_RearGlass+NonWindshield", + params: { + availableVaps: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart, + testConstants.parts.rainDefensePart, + ], + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.rearWindshield], + }, + glassParts: [], + supportingItems: [], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Economy+Frontwiper", + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + ], + }, + }, + { + name: "Standard", + vapsCombo: [testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + { + name: "Standard+RainDefense", + vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Premium", + vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + ], + }, + { + name: "05_01_CSR_Quote_RearGlass+Windshield", + params: { + availableVaps: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart, + testConstants.parts.rainDefensePart, + ], + damage: { + isRepair: false, + glassToReplace: [ + testConstants.damages.frontWindshield, + testConstants.damages.rearWindshield, + ], + }, + glassParts: [], + supportingItems: [], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Economy+Frontwiper", + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + ], + }, + }, + { + name: "Economy+Rearwiper", + vapsCombo: [testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + { + name: "Economy+RainDefense", + vapsCombo: [testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Economy+Frontwiper+RainDefense", + vapsCombo: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rainDefensePart, + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Economy+Rearwiper+RainDefense", + vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Standard", + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + { + name: "Premium", + vapsCombo: [ + testConstants.parts.rearWiperPart, + testConstants.parts.frontWiperPart, + testConstants.parts.rainDefensePart, + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + ], + }, + { + name: "05_01_CSR_Quote_RearGlassNoFrontFit", + params: { + availableVaps: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.rearWindshield], + }, + glassParts: [], + supportingItems: [], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Economy+Raindefense", + vapsCombo: [testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Standard", + vapsCombo: [testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + { + name: "Premium", + vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + ], + }, + // 05_01_CSR_Quote_Windshield+SideGlass has identical outcomes to 05_01_CSR_Quote_Cash, but included in case that changes in the future. + { + name: "05_01_CSR_Quote_Windshield+SideGlass", + params: { + availableVaps: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart, + testConstants.parts.rainDefensePart, + ], + damage: { + isRepair: false, + glassToReplace: [ + testConstants.damages.frontWindshield, + testConstants.damages.sideGlass, + ], + }, + glassParts: [], + supportingItems: [], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Standard", + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + ], + }, + }, + { + name: "Premium", + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart, + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Standard+RearWiper", + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + ], + }, + // Has no standard package + { + name: "05_01_CSR_Quote_SideGlass", + params: { + availableVaps: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart, + testConstants.parts.rainDefensePart, + ], + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.sideGlass], + }, + glassParts: [], + supportingItems: [], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Economy+Frontwiper", + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + ], + }, + }, + { + name: "Economy+RainDefense", + vapsCombo: [testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Economy+Rearwiper", + vapsCombo: [testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + ], + }, + }, + { + name: "Premium", + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart, + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + { + name: "Premium+Rearwiper", + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart, + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + ], + }, + // Has no standard package + { + name: "05_01_CSR_Quote_NoWiperFit", + params: { + availableVaps: [testConstants.parts.rainDefensePart], + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.frontWindshield], + }, + glassParts: [], + supportingItems: [], + }, + iterations: [ + { + name: "Economy", + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray, + }, + }, + { + name: "Premium", + vapsCombo: [testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rainDefenseCopy, + ], + }, + }, + ], + }, +]; + +let cmsContent; + +describe("Service Package Review Block", () => { + beforeEach(() => { + cmsContent = { + ServicePackageTitle: { + Answers: [ + { + Name: packageNames.TIER_ONE, + Text: "", + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: testConstants.widgetNames.tierOneTitle, + }, + { + Name: packageNames.TIER_TWO, + Text: "", + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: testConstants.widgetNames.tierTwoTitle, + }, + { + Name: packageNames.TIER_THREE, + Text: "", + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: testConstants.widgetNames.tierThreeTitle, + }, + ], + }, + DefaultPackageItemDescriptions: { + Answers: [ + { + Name: "Item1", + Text: testConstants.defaultItemCopy.itemOne, + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: "", + }, + { + Name: "Item2", + Text: testConstants.defaultItemCopy.itemTwo, + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: "", + }, + { + Name: "Item3", + Text: testConstants.defaultItemCopy.itemThree, + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: "", + }, + ], + }, + VapsItemDescriptions: { + Answers: [ + { + Name: partTypeStrings.FRONT_WIPER, + Text: testConstants.vapsCopy.frontWiperCopy, + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: "", + }, + { + Name: partTypeStrings.REAR_WIPER, + Text: testConstants.vapsCopy.rearWiperCopy, + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: "", + }, + { + Name: partTypeStrings.RAIN_DEFENSE, + Text: testConstants.vapsCopy.rainDefenseCopy, + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: "", + }, + ], + }, + }; + }); + describe("General functionality", () => { + it('Should properly "Round Down" package tier', async () => { + // Slightly longer explanation: + // Should only return the highest tier where *every* offered VAP is part of the order. + // However, there may be vaps not offered in the qualifying tier. Hence rounding *down*. + // + // I.e. Economy=[], Standard=[front wipers], Premium=[front wipers, rain defense]. + // Current vaps=[rain defense]. Though rain defense is in Premium, we don't satisfy it or standard. + // So our tier should still be Economy. + // Should still display extra vaps. + + // Arrange + let props = generateDefaultProps(); + + props.lineItems.vaps = [testConstants.parts.rainDefensePart]; + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.packageNameWidget).toEqual(testConstants.widgetNames.tierOneTitle); + + let containsRainDefenseCopy = wrapper.vm.displayContent.includes( + testConstants.vapsCopy.rainDefenseCopy + ); + expect(containsRainDefenseCopy).toBe(true); + }); + + it("Should display all default items from cms", async () => { + // Arrange + cmsContent.DefaultPackageItemDescriptions.Answers.push({ + Name: "Item4", + Text: testConstants.defaultItemCopy.itemFour, + SubText: "", + ImageId: testConstants.imageId, + Image: "", + SubWidgetName: "", + }); + + let props = generateDefaultProps(); + props.lineItems.vaps = []; + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + let expectedResult = [ + testConstants.defaultItemCopy.itemOne, + testConstants.defaultItemCopy.itemTwo, + testConstants.defaultItemCopy.itemThree, + testConstants.defaultItemCopy.itemFour, + ]; + + expect(wrapper.vm.displayContent).toEqual(expectedResult); + }); + + it("Should display vaps if and only if they are added", async () => { + // Arrange + const { wrapper } = setupMocks({ + propsData: generateDefaultProps(), + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + const includesFrontWiperCopy = wrapper.vm.displayContent.includes( + testConstants.vapsCopy.frontWiperCopy + ); + const includesRainDefenseCopy = wrapper.vm.displayContent.includes( + testConstants.vapsCopy.rainDefenseCopy + ); + expect(includesFrontWiperCopy).toBe(true); + expect(includesRainDefenseCopy).toBe(false); + }); + + it("Should not error if cms content is missing (though may display poorly).", async () => { + // Arrange + cmsContent = {}; + + const { wrapper } = setupMocks({ + propsData: generateDefaultProps(), + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.packageNameWidget).toEqual(""); + expect(wrapper.vm.displayContent).toEqual([]); + }); + }); + + describe("Match Figma Scenarios", () => { + figmaScenarios.forEach((scenario) => { + scenario.iterations.forEach((iteration) => { + it(`Should match figma scenario "${scenario.name}", iteration "${iteration.name}"`, async () => { + // Arrange + let props = generateDefaultProps(); + props.availableVaps = scenario.params.availableVaps; + props.damage = scenario.params.damage; + props.glassParts = scenario.params.glassParts; + props.lineItems.supportingItems = scenario.params.supportingItems; + props.lineItems.vaps = iteration.vapsCombo; + + const { wrapper } = setupMocks({ + propsData: props, + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.packageNameWidget).toEqual( + iteration.expected.packageNameWidget + ); + expect(wrapper.vm.displayContent).toEqual(iteration.expected.displayContent); + }); + }); + }); + }); +}); + +function generateDefaultProps() { + return { + servicePackageOptionsCmsName: testConstants.cmsPropValues.servicePackageOptionsCmsName, + defaultPackageItemsCmsName: testConstants.cmsPropValues.defaultPackageItemsCmsName, + vapsItemsCmsName: testConstants.cmsPropValues.vapsItemsCmsName, + availableVaps: [testConstants.parts.frontWiperPart, testConstants.parts.rainDefensePart], + lineItems: { + glassParts: [], + supportingItems: [], + vaps: [testConstants.parts.frontWiperPart], + }, + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.frontWindshield], + }, + }; +} + +function setupMocks(customMountOptions) { + const mountOptions = getMountOptions(customMountOptions); + + const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => { + return cmsContent?.[widgetName]?.[cmsFieldName] ?? ""; + }), + }, + }; + + mountOptions.global.mixins = [mockMixin]; + + const wrapper = shallowMount(servicePackageReview, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} diff --git a/src/layouts/review/review-sections/service-package-review/service-package-review.vue b/src/layouts/review/review-sections/service-package-review/service-package-review.vue new file mode 100644 index 000000000..c842c18c9 --- /dev/null +++ b/src/layouts/review/review-sections/service-package-review/service-package-review.vue @@ -0,0 +1,104 @@ + + + diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue index e3c173a02..a974afa48 100644 --- a/src/layouts/review/review.vue +++ b/src/layouts/review/review.vue @@ -27,7 +27,9 @@ class="mb-2" @click-event="forwardButtonAction" /> -
+
+
+
+ +
+ +
-
+
+
+
{ vm.setCmsContent(resultMap.cmsContent); + + vm.availableWipers = resultMap.wipers; + vm.availableRainDefense = [resultMap.rainDefense]; }); }, data() { - return {}; + return { + availableWipers: null, + availableRainDefense: null, + }; }, methods: { arePagePrerequisitesValid() { @@ -113,6 +151,12 @@ export default { this.$route ); }, + editServicePackage() { + this.$router.navigateWithoutSaving( + this.navigationScenarios.CLICKED_SERVICE_PACKAGE_EDIT, + this.$route + ); + }, }, computed: { subHeaderTitle() { @@ -130,6 +174,12 @@ export default { damageInfo() { return this.$store.getters.damage; }, + availableVaps() { + return [...(this.availableWipers ?? []), ...(this.availableRainDefense ?? [])]; + }, + lineItems() { + return this.$store.getters.lineItems; + }, }, components: { funnelHeader, @@ -139,6 +189,7 @@ export default { textBlock, vehicleReview, damageReview, + servicePackageReview, }, }; diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 7c3aa1413..88ca110dd 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -49,6 +49,7 @@ const navigationScenarios = { // Review CLICKED_VEHICLE_EDIT: "CLICKED_VEHICLE_EDIT", CLICKED_DAMAGE_EDIT: "CLICKED_DAMAGE_EDIT", + CLICKED_SERVICE_PACKAGE_EDIT: "CLICKED_SERVICE_PACKAGE_EDIT", }; export { navigationScenarios }; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 0c2beffee..4238b659a 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -472,6 +472,10 @@ const routingTable = function (store) { scenario: navigationScenarios.CLICKED_DAMAGE_EDIT, destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, }, + { + scenario: navigationScenarios.CLICKED_SERVICE_PACKAGE_EDIT, + destinationFmgPageValue: fmgPageValues.QUOTE, + }, { scenario: navigationScenarios.CLICKED_BACK, destinationFmgPageValue: fmgPageValues.CUSTOMER_DETAILS, diff --git a/src/store/index.js b/src/store/index.js index f668d957f..fa2906387 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -13,6 +13,7 @@ import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js"; import { deepEqual } from "@/helpers/object-helper"; import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants"; +import { partTypeStrings } from "@/constants/part-type-strings"; // Export State const getDefaultState = () => { @@ -536,6 +537,14 @@ export const getters = { isMobileAppointment: (state) => { return state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE; }, + isRecalibrationOnOrder: (state) => { + return getHasRecalibrationPart(state); + }, + areRearWipersOnOrder: (state) => { + return !!state.order.lineItems.vaps?.some( + (vap) => vap.partType.toUpperCase() === partTypeStrings.REAR_WIPER.toUpperCase() + ); + }, lineItems: (state) => state.order.lineItems, pageData: (state) => (page) => { return state.applicationUser.pageData[page];