diff --git a/package-lock.json b/package-lock.json
index de0a70e2..a062bda3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -63,7 +63,7 @@
"typescript-eslint": "^8.11.0",
"vite": "^6.4.1",
"vitest": "^3.2.4",
- "volar-service-vetur": "latest",
+ "volar-service-vetur": "*",
"wait-on": "^8.0.2"
}
},
@@ -4419,6 +4419,28 @@
"node": ">=10"
}
},
+ "node_modules/@types/eslint": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
+ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "node_modules/@types/eslint-scope": {
+ "version": "3.7.7",
+ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+ "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/eslint": "*",
+ "@types/estree": "*"
+ }
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -5999,148 +6021,163 @@
"dev": true
},
"node_modules/@webassemblyjs/ast": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
- "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
+ "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@webassemblyjs/helper-numbers": "1.11.6",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
+ "@webassemblyjs/helper-numbers": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2"
}
},
"node_modules/@webassemblyjs/floating-point-hex-parser": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
- "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
- "dev": true
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
+ "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@webassemblyjs/helper-api-error": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
- "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
- "dev": true
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
+ "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@webassemblyjs/helper-buffer": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
- "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
- "dev": true
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
+ "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@webassemblyjs/helper-numbers": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
- "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
+ "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@webassemblyjs/floating-point-hex-parser": "1.11.6",
- "@webassemblyjs/helper-api-error": "1.11.6",
+ "@webassemblyjs/floating-point-hex-parser": "1.13.2",
+ "@webassemblyjs/helper-api-error": "1.13.2",
"@xtuc/long": "4.2.2"
}
},
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
- "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
- "dev": true
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
+ "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@webassemblyjs/helper-wasm-section": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
- "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
+ "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
- "@webassemblyjs/helper-buffer": "1.12.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/wasm-gen": "1.12.1"
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/wasm-gen": "1.14.1"
}
},
"node_modules/@webassemblyjs/ieee754": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
- "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
+ "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
}
},
"node_modules/@webassemblyjs/leb128": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
- "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
+ "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"@xtuc/long": "4.2.2"
}
},
"node_modules/@webassemblyjs/utf8": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
- "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
- "dev": true
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
+ "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@webassemblyjs/wasm-edit": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
- "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
+ "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
- "@webassemblyjs/helper-buffer": "1.12.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/helper-wasm-section": "1.12.1",
- "@webassemblyjs/wasm-gen": "1.12.1",
- "@webassemblyjs/wasm-opt": "1.12.1",
- "@webassemblyjs/wasm-parser": "1.12.1",
- "@webassemblyjs/wast-printer": "1.12.1"
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/helper-wasm-section": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-opt": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1",
+ "@webassemblyjs/wast-printer": "1.14.1"
}
},
"node_modules/@webassemblyjs/wasm-gen": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
- "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
+ "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/ieee754": "1.11.6",
- "@webassemblyjs/leb128": "1.11.6",
- "@webassemblyjs/utf8": "1.11.6"
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/ieee754": "1.13.2",
+ "@webassemblyjs/leb128": "1.13.2",
+ "@webassemblyjs/utf8": "1.13.2"
}
},
"node_modules/@webassemblyjs/wasm-opt": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
- "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
+ "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
- "@webassemblyjs/helper-buffer": "1.12.1",
- "@webassemblyjs/wasm-gen": "1.12.1",
- "@webassemblyjs/wasm-parser": "1.12.1"
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1"
}
},
"node_modules/@webassemblyjs/wasm-parser": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
- "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
+ "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
- "@webassemblyjs/helper-api-error": "1.11.6",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/ieee754": "1.11.6",
- "@webassemblyjs/leb128": "1.11.6",
- "@webassemblyjs/utf8": "1.11.6"
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-api-error": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/ieee754": "1.13.2",
+ "@webassemblyjs/leb128": "1.13.2",
+ "@webassemblyjs/utf8": "1.13.2"
}
},
"node_modules/@webassemblyjs/wast-printer": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
- "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
+ "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@webassemblyjs/ast": "1.12.1",
+ "@webassemblyjs/ast": "1.14.1",
"@xtuc/long": "4.2.2"
}
},
@@ -6148,13 +6185,15 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
- "dev": true
+ "dev": true,
+ "license": "BSD-3-Clause"
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
- "dev": true
+ "dev": true,
+ "license": "Apache-2.0"
},
"node_modules/abab": {
"version": "2.0.6",
@@ -6225,13 +6264,17 @@
"node": ">=0.4.0"
}
},
- "node_modules/acorn-import-attributes": {
- "version": "1.9.5",
- "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
- "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
+ "node_modules/acorn-import-phases": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
+ "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
"dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.13.0"
+ },
"peerDependencies": {
- "acorn": "^8"
+ "acorn": "^8.14.0"
}
},
"node_modules/acorn-jsx": {
@@ -6999,6 +7042,16 @@
}
]
},
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.9.19",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
+ "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
"node_modules/batch": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@@ -7156,9 +7209,9 @@
"dev": true
},
"node_modules/browserslist": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
- "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
+ "version": "4.28.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
+ "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
"dev": true,
"funding": [
{
@@ -7174,11 +7227,13 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
- "caniuse-lite": "^1.0.30001646",
- "electron-to-chromium": "^1.5.4",
- "node-releases": "^2.0.18",
- "update-browserslist-db": "^1.1.0"
+ "baseline-browser-mapping": "^2.9.0",
+ "caniuse-lite": "^1.0.30001759",
+ "electron-to-chromium": "^1.5.263",
+ "node-releases": "^2.0.27",
+ "update-browserslist-db": "^1.2.0"
},
"bin": {
"browserslist": "cli.js"
@@ -7393,9 +7448,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001653",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz",
- "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==",
+ "version": "1.0.30001768",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001768.tgz",
+ "integrity": "sha512-qY3aDRZC5nWPgHUgIB84WL+nySuo19wk0VJpp/XI9T34lrvkyhRvNVOFJOp2kxClQhiFBu+TaUSudf6oa3vkSA==",
"dev": true,
"funding": [
{
@@ -7410,7 +7465,8 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
- ]
+ ],
+ "license": "CC-BY-4.0"
},
"node_modules/case-sensitive-paths-webpack-plugin": {
"version": "2.4.0",
@@ -9295,10 +9351,11 @@
"dev": true
},
"node_modules/electron-to-chromium": {
- "version": "1.5.13",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz",
- "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==",
- "dev": true
+ "version": "1.5.286",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
+ "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
+ "dev": true,
+ "license": "ISC"
},
"node_modules/emittery": {
"version": "0.8.1",
@@ -9373,13 +9430,14 @@
}
},
"node_modules/enhanced-resolve": {
- "version": "5.17.1",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
- "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
+ "version": "5.19.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz",
+ "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
+ "tapable": "^2.3.0"
},
"engines": {
"node": ">=10.13.0"
@@ -9556,10 +9614,11 @@
}
},
"node_modules/escalade": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
- "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -10355,6 +10414,23 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
+ "node_modules/fast-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
+ "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
"node_modules/fastq": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
@@ -10904,7 +10980,8 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
- "dev": true
+ "dev": true,
+ "license": "BSD-2-Clause"
},
"node_modules/globals": {
"version": "11.12.0",
@@ -15186,12 +15263,17 @@
}
},
"node_modules/loader-runner": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
- "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz",
+ "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6.11.5"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
}
},
"node_modules/loader-utils": {
@@ -16372,10 +16454,11 @@
"dev": true
},
"node_modules/node-releases": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
- "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
- "dev": true
+ "version": "2.0.27",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
+ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/nopt": {
"version": "6.0.0",
@@ -19604,12 +19687,17 @@
"dev": true
},
"node_modules/tapable": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
- "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
+ "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
}
},
"node_modules/tar": {
@@ -19743,16 +19831,17 @@
}
},
"node_modules/terser-webpack-plugin": {
- "version": "5.3.10",
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
- "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
+ "version": "5.3.16",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz",
+ "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@jridgewell/trace-mapping": "^0.3.20",
+ "@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5",
- "schema-utils": "^3.1.1",
- "serialize-javascript": "^6.0.1",
- "terser": "^5.26.0"
+ "schema-utils": "^4.3.0",
+ "serialize-javascript": "^6.0.2",
+ "terser": "^5.31.1"
},
"engines": {
"node": ">= 10.13.0"
@@ -19776,6 +19865,63 @@
}
}
},
+ "node_modules/terser-webpack-plugin/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
+ "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
"node_modules/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -20411,9 +20557,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
- "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"dev": true,
"funding": [
{
@@ -20429,9 +20575,10 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
- "escalade": "^3.1.2",
- "picocolors": "^1.0.1"
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
},
"bin": {
"update-browserslist-db": "cli.js"
@@ -21516,10 +21663,11 @@
}
},
"node_modules/watchpack": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
- "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
+ "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@@ -21556,34 +21704,37 @@
}
},
"node_modules/webpack": {
- "version": "5.94.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
- "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
+ "version": "5.105.0",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz",
+ "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@types/estree": "^1.0.5",
- "@webassemblyjs/ast": "^1.12.1",
- "@webassemblyjs/wasm-edit": "^1.12.1",
- "@webassemblyjs/wasm-parser": "^1.12.1",
- "acorn": "^8.7.1",
- "acorn-import-attributes": "^1.9.5",
- "browserslist": "^4.21.10",
+ "@types/eslint-scope": "^3.7.7",
+ "@types/estree": "^1.0.8",
+ "@types/json-schema": "^7.0.15",
+ "@webassemblyjs/ast": "^1.14.1",
+ "@webassemblyjs/wasm-edit": "^1.14.1",
+ "@webassemblyjs/wasm-parser": "^1.14.1",
+ "acorn": "^8.15.0",
+ "acorn-import-phases": "^1.0.3",
+ "browserslist": "^4.28.1",
"chrome-trace-event": "^1.0.2",
- "enhanced-resolve": "^5.17.1",
- "es-module-lexer": "^1.2.1",
+ "enhanced-resolve": "^5.19.0",
+ "es-module-lexer": "^2.0.0",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.2.11",
"json-parse-even-better-errors": "^2.3.1",
- "loader-runner": "^4.2.0",
+ "loader-runner": "^4.3.1",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
- "schema-utils": "^3.2.0",
- "tapable": "^2.1.1",
- "terser-webpack-plugin": "^5.3.10",
- "watchpack": "^2.4.1",
- "webpack-sources": "^3.2.3"
+ "schema-utils": "^4.3.3",
+ "tapable": "^2.3.0",
+ "terser-webpack-plugin": "^5.3.16",
+ "watchpack": "^2.5.1",
+ "webpack-sources": "^3.3.3"
},
"bin": {
"webpack": "bin/webpack.js"
@@ -21945,10 +22096,11 @@
}
},
"node_modules/webpack-sources": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
- "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz",
+ "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10.13.0"
}
@@ -21959,6 +22111,70 @@
"integrity": "sha512-h9atBP/bsZohWpHnr+2sic8Iecb60GxftXsWNLLLSqewgIsGzByd2gcIID4nXcG+3tNe4GQG3dLcff3kXupdRA==",
"dev": true
},
+ "node_modules/webpack/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/webpack/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/webpack/node_modules/es-module-lexer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
+ "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/webpack/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/webpack/node_modules/schema-utils": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
+ "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
"node_modules/websocket-driver": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js
index 81f0fad0..224c6e30 100644
--- a/src/constants/error-messages.js
+++ b/src/constants/error-messages.js
@@ -65,7 +65,9 @@ const errorMessages = Object.freeze({
STYLE_REQUIRED: 'Vehicle style is required.',
MOBILE_LOCATION_REQUIRED: 'Please enter your service address',
DATE_REQUIRED: 'Please select a date',
- TIME_REQUIRED: 'Please select an appointment time.'
+ TIME_REQUIRED: 'Please select an appointment time.',
+ PRIMARY_PHONE_REQUIRED: 'Primary phone number is required.',
+ BAILOUT_EMAIL_ADDRESS_REQUIRED: 'Email address is required.'
});
export default errorMessages;
diff --git a/src/constants/global-rules.js b/src/constants/global-rules.js
index e82b118a..878b7a27 100644
--- a/src/constants/global-rules.js
+++ b/src/constants/global-rules.js
@@ -26,7 +26,9 @@ const globalRules = Object.freeze({
EXTENSION_FORMAT: 'extension-format',
ZIP_CODE_REQUIRED: 'zip-code-required',
ZIP_CODE_SEARCH_FORMAT: 'zip-code-search-format',
- OPTION_REQUIRED: 'option-required'
+ OPTION_REQUIRED: 'option-required',
+ PRIMARY_PHONE_REQUIRED: 'primary-phone-required',
+ BAILOUT_EMAIL_ADDRESS_REQUIRED: 'bailout-email-address-required'
});
export default globalRules;
diff --git a/src/constants/progress-bar-mapper.js b/src/constants/progress-bar-mapper.js
index e80fbb5c..efb6225d 100644
--- a/src/constants/progress-bar-mapper.js
+++ b/src/constants/progress-bar-mapper.js
@@ -53,10 +53,10 @@ export const pageProgressMapper = {
'schedule-page': {
percent: 70
},
- 'contact-details': {
- percent: 80
- },
'service-packages': {
+ percent: 75
+ },
+ 'contact-details': {
percent: 85
},
'payment-method': {
diff --git a/src/constants/vin-lookup-methods.js b/src/constants/vin-lookup-methods.js
index 539bdb3d..fd12a0ee 100644
--- a/src/constants/vin-lookup-methods.js
+++ b/src/constants/vin-lookup-methods.js
@@ -1,7 +1,8 @@
const vinLookupMethodSelections = Object.freeze({
MANUALVIN: 'ManualVin',
LICENSEPLATE: 'LicensePlate',
- HOMEADDRESS: 'HomeAddress'
+ HOMEADDRESS: 'HomeAddress',
+ NOVIN: 'NoVin'
});
export default vinLookupMethodSelections;
diff --git a/src/digital-components/button-question/button-question.vue b/src/digital-components/button-question/button-question.vue
index 68ca6d57..ca731b44 100644
--- a/src/digital-components/button-question/button-question.vue
+++ b/src/digital-components/button-question/button-question.vue
@@ -79,7 +79,7 @@
diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue
index b785a171..9d1a1443 100644
--- a/src/digital-components/date-picker/date-picker.vue
+++ b/src/digital-components/date-picker/date-picker.vue
@@ -559,6 +559,7 @@ export default {
this.selectTimeSlotForDay(timeSlot);
},
async setCalendarData(config = {}) {
+ // set selectable dates data
config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
const dateObjectToPush = {
date: selectableDate.date,
diff --git a/src/digital-components/textarea-question/textarea-question.spec.js b/src/digital-components/textarea-question/textarea-question.spec.js
index 27968aa1..c3d903a1 100644
--- a/src/digital-components/textarea-question/textarea-question.spec.js
+++ b/src/digital-components/textarea-question/textarea-question.spec.js
@@ -67,7 +67,7 @@ describe('textarea-question.vue', () => {
},
mixins: [mockMixin]
});
- const expected = `${maxLength}/${maxLength}`;
+ const expected = `${maxLength} characters allowed`;
// Act
// Assert
diff --git a/src/digital-components/textarea-question/textarea-question.vue b/src/digital-components/textarea-question/textarea-question.vue
index 60293dde..f6d94ebb 100644
--- a/src/digital-components/textarea-question/textarea-question.vue
+++ b/src/digital-components/textarea-question/textarea-question.vue
@@ -18,7 +18,7 @@
:id="inputId"
:ref="inputId"
v-model.trim="value"
- class="form-control"
+ class="textarea-input"
:name="inputId"
:rows="[inputRows ?? 10]"
:placeholder="placeholderText"
@@ -32,8 +32,15 @@
@drop="trimOnPaste">
-
- {{ maxLength - characterCount }}/{{ maxLength }} characters remaining
+
+ {{ maxLength }} characters allowed
+
+
+ {{ maxLength - characterCount }} characters left
diff --git a/src/helpers/bailout-helper.js b/src/helpers/bailout-helper.js
index 0191755d..b0d364c5 100644
--- a/src/helpers/bailout-helper.js
+++ b/src/helpers/bailout-helper.js
@@ -10,7 +10,7 @@ function canBailoutNavigateBack() {
switch (code) {
case BailoutCode.VehicleNotFound:
- case BailoutCode.DoNotSeeMyShop:
+ case BailoutCode.RequestCallback:
case BailoutCode.TPANotEnabled:
return true;
diff --git a/src/helpers/global-rule-definer.js b/src/helpers/global-rule-definer.js
index 5aca4f66..b91f3dc0 100644
--- a/src/helpers/global-rule-definer.js
+++ b/src/helpers/global-rule-definer.js
@@ -24,6 +24,7 @@ function defineGlobalNameRules() {
*/
function defineGlobalEmailRules() {
defineRule(globalRules.EMAIL_ADDRESS_REQUIRED, required(errorMessages.EMAIL_ADDRESS_REQUIRED));
+ defineRule(globalRules.BAILOUT_EMAIL_ADDRESS_REQUIRED, required(errorMessages.BAILOUT_EMAIL_ADDRESS_REQUIRED));
defineRule(
globalRules.EMAIL_ADDRESS_FORMAT,
regex(
@@ -71,6 +72,7 @@ function defineGlobalDateOfLossRules() {
*/
function defineGlobalPhoneNumberRules() {
defineRule(globalRules.PHONE_NUMBER_REQUIRED, required(errorMessages.PHONE_NUMBER_REQUIRED));
+ defineRule(globalRules.PRIMARY_PHONE_REQUIRED, required(errorMessages.PRIMARY_PHONE_REQUIRED));
defineRule(
globalRules.PHONE_NUMBER_FORMAT,
regex(
diff --git a/src/iss-components/questions-page-layout/questions-page-layout.vue b/src/iss-components/questions-page-layout/questions-page-layout.vue
index 4ce11fa1..97d06a51 100644
--- a/src/iss-components/questions-page-layout/questions-page-layout.vue
+++ b/src/iss-components/questions-page-layout/questions-page-layout.vue
@@ -33,9 +33,17 @@
ref="siteFooter"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
- :isForwardActionDisabled="!isMetaValid"
+ :isForwardButtonHidden="!isMetaValid"
@backClicked="handleBackButtonAction"
@ForwardClicked="handleForwardButtonAction" />
+
+
+
@@ -48,6 +56,8 @@ import alert from '@/ux-components/alert/alert.vue';
import questionChain from '@/digital-components/question-chain/question-chain.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
+import textLink from '@/ux-components/text-link/text-link.vue';
+import widgetFields from '@/constants/cms-widget-fields';
export default {
name: 'questions-page',
@@ -56,7 +66,8 @@ export default {
alert,
questionChain,
siteSubHeader,
- siteFooter
+ siteFooter,
+ textLink
},
props: {
isMetaValid: Boolean,
@@ -68,7 +79,7 @@ export default {
loadingText: Array,
index: Number
},
- emits: ['update:modelValue', 'forwardButtonAction', 'back-click'],
+ emits: ['update:modelValue', 'forwardButtonAction', 'back-click', 'need-help-click'],
computed: {
selectedAnswers: {
get() {
@@ -77,6 +88,9 @@ export default {
set(newValue) {
this.$emit('update:modelValue', newValue);
}
+ },
+ needHelpLinkText() {
+ return this.getCmsContent('NeedHelpLinkWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
}
},
methods: {
@@ -98,6 +112,9 @@ export default {
},
handleBackButtonAction() {
this.$emit('back-click');
+ },
+ handleNeedHelpClick() {
+ this.$emit('need-help-click');
}
}
};
@@ -122,4 +139,7 @@ export default {
}
}
}
+.need-help-link-container {
+ margin-bottom: 2.25rem;
+}
diff --git a/src/layouts/bailout-page/__snapshots__/bailout-page.spec.js.snap b/src/layouts/bailout-page/__snapshots__/bailout-page.spec.js.snap
index 62f2829b..b191b402 100644
--- a/src/layouts/bailout-page/__snapshots__/bailout-page.spec.js.snap
+++ b/src/layouts/bailout-page/__snapshots__/bailout-page.spec.js.snap
@@ -12,13 +12,14 @@ Object {
"phoneNumber": "6145550909",
},
"rules": Object {
- "email": "email-required|email-address-format",
- "firstName": "first-name-required",
- "lastName": "last-name-required",
- "phoneNumber": "phone-number-required|phone-number-format",
+ "email": "bailout-email-address-required|email-address-format",
+ "firstName": "policyholder-first-name-required",
+ "lastName": "policyholder-last-name-required",
+ "phoneNumber": "primary-phone-required|phone-number-format",
},
"widget": Object {
"defaultSiteHeader": "SiteSubHeaderWidget",
+ "disclaimerText": "DisclaimerWidget",
"noTpa": "ContentGroupNoTPAWidget",
"notSeeingPreferredShop": "ContentGroupNotSeeingPreferredShop",
},
diff --git a/src/layouts/bailout-page/bailout-page.spec.js b/src/layouts/bailout-page/bailout-page.spec.js
index 5b0c68ee..3ccd149b 100644
--- a/src/layouts/bailout-page/bailout-page.spec.js
+++ b/src/layouts/bailout-page/bailout-page.spec.js
@@ -156,6 +156,16 @@ describe('Bailout page', () => {
// Assert
expect(siteFooter.exists()).toBeTruthy();
});
+ test('disclaimer text block', () => {
+ // Arrange
+ const wrapper = shallowMount(bailoutPage, getMountOptions());
+
+ // Act
+ const disclaimerText = wrapper.findComponent({ ref: 'disclaimerText' });
+
+ // Assert
+ expect(disclaimerText.exists()).toBeTruthy();
+ });
});
describe('computed', () => {
describe('subHeaderCmsWidgetName', () => {
diff --git a/src/layouts/bailout-page/bailout-page.vue b/src/layouts/bailout-page/bailout-page.vue
index a84f0dfe..db6aa074 100644
--- a/src/layouts/bailout-page/bailout-page.vue
+++ b/src/layouts/bailout-page/bailout-page.vue
@@ -20,28 +20,34 @@
:subContentProperty="subContentProperty"
class="sub-header-content mt-2 mb-5"
justification="left" />
-
-
+
+
@@ -77,6 +86,7 @@ import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
+import textBlock from '@/digital-components/text-block/text-block.vue';
// Supporting files
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
@@ -99,7 +109,8 @@ export default {
siteFooter,
textboxQuestion,
// eslint-disable-next-line vue/no-reserved-component-names
- Form
+ Form,
+ textBlock
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
@@ -130,13 +141,14 @@ export default {
widget: {
defaultSiteHeader: 'SiteSubHeaderWidget',
noTpa: 'ContentGroupNoTPAWidget',
- notSeeingPreferredShop: 'ContentGroupNotSeeingPreferredShop'
+ notSeeingPreferredShop: 'ContentGroupNotSeeingPreferredShop',
+ disclaimerText: 'DisclaimerWidget'
},
rules: {
- firstName: globalRules.FIRST_NAME_REQUIRED,
- lastName: globalRules.LAST_NAME_REQUIRED,
- phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`,
- email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`
+ firstName: globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED,
+ lastName: globalRules.POLICYHOLDER_LAST_NAME_REQUIRED,
+ phoneNumber: `${globalRules.PRIMARY_PHONE_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`,
+ email: `${globalRules.BAILOUT_EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`
}
};
},
@@ -221,9 +233,7 @@ export default {
};
-
diff --git a/src/layouts/contact-confirmation/contact-confirmation.vue b/src/layouts/contact-confirmation/contact-confirmation.vue
index 29c52745..2819efd6 100644
--- a/src/layouts/contact-confirmation/contact-confirmation.vue
+++ b/src/layouts/contact-confirmation/contact-confirmation.vue
@@ -24,6 +24,7 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import issPageValues from '@/router/router-constants/issPage-values.js';
import settleAllPromises from '@/helpers/layout-helper';
import { useMainStore } from '@/store';
+import showIssLoadingModal from '@/helpers/loading-modal-helper';
export default {
name: 'contact-confirmation',
@@ -47,6 +48,7 @@ export default {
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
+ showIssLoadingModal(false);
},
setup() {
const mainStore = useMainStore();
diff --git a/src/layouts/contact-details/contact-details.spec.js b/src/layouts/contact-details/contact-details.spec.js
index 58d16b8e..5b5131a8 100644
--- a/src/layouts/contact-details/contact-details.spec.js
+++ b/src/layouts/contact-details/contact-details.spec.js
@@ -32,65 +32,175 @@ describe('contactDetails.vue', () => {
// Assert
expect(siteSubHeader.exists()).toBe(true);
});
- test('Should render first name question subcomponent', () => {
+ test('Should render appointment information alert', () => {
// Arrange
const wrapper = shallowMount(contactDetails, getMountOptions());
// Act
- const firstNameQuestion = wrapper.findComponent({ ref: 'firstNameQuestion' });
+ const appointmentInformationAlert = wrapper.findComponent({ ref: 'appointmentInformationAlert' });
// Assert
- expect(firstNameQuestion.exists()).toBe(true);
+ expect(appointmentInformationAlert.exists()).toBe(true);
});
- test('Should render last name question subcomponent', () => {
+ test('Should render same as policy address question subcomponent if service zip is same as customer zip', async () => {
// Arrange
- const wrapper = shallowMount(contactDetails, getMountOptions());
-
- // Act
- const lastNameQuestion = wrapper.findComponent({ ref: 'lastNameQuestion' });
-
- // Assert
- expect(lastNameQuestion.exists()).toBe(true);
- });
- test('Should render email question subcomponent', () => {
- // Arrange
- const wrapper = shallowMount(contactDetails, getMountOptions());
-
- // Act
- const emailQuestion = wrapper.findComponent({ ref: 'emailQuestion' });
-
- // Assert
- expect(emailQuestion.exists()).toBe(true);
- });
- test('Should render phone number question subcomponent', () => {
- // Arrange
- const wrapper = shallowMount(contactDetails, getMountOptions());
-
- // Act
- const phoneNumberQuestion = wrapper.findComponent({ ref: 'phoneNumberQuestion' });
-
- // Assert
- expect(phoneNumberQuestion.exists()).toBe(true);
- });
- test('Should render text updates checkbox subcomponent', () => {
- // Arrange
- const checkboxLabel = getRandomString(50, 100);
- const mockMixin = {
- methods: {
- getCmsContent: jest.fn().mockImplementation(() => checkboxLabel),
- setCmsContent: jest.fn()
+ const mountOptions = getMountOptions();
+
+ const customerStreetAddress = getRandomString(10, 50);
+ const customerStreetAddress2 = getRandomString(0, 50);
+ const customerCity = getRandomString(4, 20);
+ const customerState = getRandomString(2, 2);
+ const serviceStreetAddress = getRandomString(10, 50);
+ const serviceStreetAddress2 = getRandomString(0, 50);
+ const serviceCity = getRandomString(4, 20);
+ const serviceState = getRandomString(2, 2);
+ const zipCode = getRandomInt(10000, 99999).toString();
+ const mainInitialState = {
+ order: {
+ customer: {
+ address: {
+ streetAddress: customerStreetAddress,
+ streetAddress2: customerStreetAddress2,
+ city: customerCity,
+ state: customerState,
+ zipCode
+ }
+ },
+ serviceLocation: {
+ streetAddress: serviceStreetAddress,
+ streetAddress2: serviceStreetAddress2,
+ city: serviceCity,
+ state: serviceState,
+ zipCode
+ }
}
};
+ mountOptions.global.plugins = [createTestingPinia({
+ initialState: {
+ main: mainInitialState
+ }
+ })];
+ const wrapper = shallowMount(contactDetails, mountOptions);
+
+ await wrapper.vm.$nextTick();
+
+ // Act
+ const sameAsPolicyAddressQuestion = wrapper.findComponent({ ref: 'sameAsPolicyAddressQuestion' });
+
+ // Assert
+ expect(sameAsPolicyAddressQuestion.exists()).toBe(true);
+ });
+ test('Should not render same as policy address question subcomponent if service zip is different from customer zip', () => {
+ // Arrange
const mountOptions = getMountOptions();
- mountOptions.mixins = [mockMixin];
+
+ const firstName = getRandomString(4, 15);
+ const lastName = getRandomString(4, 15);
+ const emailAddress = getRandomString(10, 20);
+ const servicePhone = getRandomInt(1000000000, 9999999999).toString();
+ const testZipCode = getRandomInt(10000, 99999);
+ const customerZipCode = testZipCode.toString();
+ const serviceZipCode = (testZipCode + 1).toString();
+ const mainInitialState = {
+ order: {
+ customer: {
+ firstName,
+ lastName,
+ emailAddress,
+ address: {
+ zipCode: customerZipCode
+ }
+ },
+ contactInfo: {
+ servicePhone
+ },
+ serviceLocation: {
+ zipCode: serviceZipCode
+ }
+ }
+ };
+ mountOptions.global.plugins = [createTestingPinia({
+ initialState: {
+ main: mainInitialState
+ }
+ })];
const wrapper = shallowMount(contactDetails, mountOptions);
// Act
- const textUpdatesCheckbox = wrapper.findComponent({ ref: 'requestTextUpdatesCheckbox' });
+ const sameAsPolicyAddressQuestion = wrapper.findComponent({ ref: 'sameAsPolicyAddressQuestion' });
// Assert
- expect(textUpdatesCheckbox.exists()).toBe(true);
- expect(wrapper.vm.requestTextUpdatesCheckboxText).toBe(`${checkboxLabel}*`);
+ expect(sameAsPolicyAddressQuestion.exists()).toBe(false);
+ });
+ test('Should render address question subcomponent', () => {
+ // Arrange
+ const wrapper = shallowMount(contactDetails, getMountOptions());
+
+ // Act
+ const addressQuestion = wrapper.findComponent({ ref: 'addressQuestion' });
+
+ // Assert
+ expect(addressQuestion.exists()).toBe(true);
+ });
+ test('Should render apartment question subcomponent', () => {
+ // Arrange
+ const wrapper = shallowMount(contactDetails, getMountOptions());
+
+ // Act
+ const address2Question = wrapper.findComponent({ ref: 'address2Question' });
+
+ // Assert
+ expect(address2Question.exists()).toBe(true);
+ });
+ test('Should render city question subcomponent', () => {
+ // Arrange
+ const wrapper = shallowMount(contactDetails, getMountOptions());
+
+ // Act
+ const cityQuestion = wrapper.findComponent({ ref: 'cityQuestion' });
+
+ // Assert
+ expect(cityQuestion.exists()).toBe(true);
+ });
+ test('Should render state question subcomponent', () => {
+ // Arrange
+ const wrapper = shallowMount(contactDetails, getMountOptions());
+
+ // Act
+ const stateQuestion = wrapper.findComponent({ ref: 'stateQuestion' });
+
+ // Assert
+ expect(stateQuestion.exists()).toBe(true);
+ });
+ test('Should render zip code question subcomponent', () => {
+ // Arrange
+ const wrapper = shallowMount(contactDetails, getMountOptions());
+
+ // Act
+ const zipCodeQuestion = wrapper.findComponent({ ref: 'zipCodeQuestion' });
+
+ // Assert
+ expect(zipCodeQuestion.exists()).toBe(true);
+ });
+ test('Should render change zip code alert', () => {
+ // Arrange
+ const wrapper = shallowMount(contactDetails, getMountOptions());
+
+ // Act
+ const changeZipCodeAlert = wrapper.findComponent({ ref: 'changeZipCodeAlert' });
+
+ // Assert
+ expect(changeZipCodeAlert.exists()).toBe(true);
+ });
+ test('Should render vehicle protected question subcomponent', () => {
+ // Arrange
+ const wrapper = shallowMount(contactDetails, getMountOptions());
+
+ // Act
+ const vehicleProtectedQuestion = wrapper.findComponent({ ref: 'vehicleProtectedQuestion' });
+
+ // Assert
+ expect(vehicleProtectedQuestion.exists()).toBe(true);
});
test('Should render technician notes textarea question subcomponent', () => {
// Arrange
@@ -102,46 +212,15 @@ describe('contactDetails.vue', () => {
// Assert
expect(notesQuestion.exists()).toBe(true);
});
- test('Should render disclaimer text', () => {
- // Arrange
- const disclaimerText = getRandomString(50, 100);
- const mockMixin = {
- methods: {
- getCmsContent: jest.fn().mockImplementation(() => disclaimerText),
- setCmsContent: jest.fn()
- }
- };
- const mountOptions = getMountOptions();
- mountOptions.mixins = [mockMixin];
- const wrapper = shallowMount(contactDetails, mountOptions);
- const expectedDisclaimerText = `*${disclaimerText} I also agree to Safelite's`;
-
- // Act
- const componentText = wrapper.text();
-
- // Assert
- expect(wrapper.vm.textUpdateDisclaimerText).toBe(`*${disclaimerText}`);
- expect(componentText).toContain(expectedDisclaimerText);
- });
- test('Should render privacy policy link', () => {
+ test('Should render clearance text subcomponent', () => {
// Arrange
const wrapper = shallowMount(contactDetails, getMountOptions());
// Act
- const privacyPolicyLink = wrapper.findComponent({ ref: 'privacyPolicyLink' });
+ const clearanceText = wrapper.findComponent({ ref: 'clearanceText' });
// Assert
- expect(privacyPolicyLink.exists()).toBe(true);
- });
- test('Should render terms of use link', () => {
- // Arrange
- const wrapper = shallowMount(contactDetails, getMountOptions());
-
- // Act
- const termsOfUseLink = wrapper.findComponent({ ref: 'termsOfUseLink' });
-
- // Assert
- expect(termsOfUseLink.exists()).toBe(true);
+ expect(clearanceText.exists()).toBe(true);
});
test('Should render site footer', () => {
// Arrange
@@ -153,82 +232,48 @@ describe('contactDetails.vue', () => {
// Assert
expect(footer.exists()).toBe(true);
});
- test('Mocked store with no contact info yields expected data', () => {
+ test('Mocked store yields expected data', () => {
// Arrange
const mountOptions = getMountOptions();
- const firstName = getRandomString(4, 15);
- const lastName = getRandomString(4, 15);
- const emailAddress = getRandomString(10, 20);
- const servicePhone = getRandomInt(1000000000, 9999999999).toString();
+ const address = getRandomString(10, 50);
+ const address2 = getRandomString(0, 50);
+ const city = getRandomString(4, 20);
+ const state = getRandomString(2, 2);
+ const zipCode = getRandomInt(10000, 99999).toString();
+ const notesForTechnician = getRandomString(1, 100);
+ const isVehicleProtected = getRandomBoolean();
const mainInitialState = {
order: {
- customer: {
- firstName,
- lastName,
- emailAddress
+ serviceLocation: {
+ address,
+ address2,
+ city,
+ state,
+ zipCode,
+ isVehicleProtected
},
contactInfo: {
- servicePhone
+ notesForTechnician
}
}
};
- mountOptions.global = {
- plugins: [createTestingPinia({
- initialState: {
- main: mainInitialState
- }
- })]
- };
+ mountOptions.global.plugins = [createTestingPinia({
+ initialState: {
+ main: mainInitialState
+ }
+ })];
const wrapper = shallowMount(contactDetails, mountOptions);
// Assert
- expect(wrapper.vm.firstName).toBe(firstName);
- expect(wrapper.vm.lastName).toBe(lastName);
- expect(wrapper.vm.emailAddress).toBe(emailAddress);
- expect(wrapper.vm.phoneNumber).toBe(servicePhone);
- });
- test('Mock store with contact info yields expected data', () => {
- // Arrange
- const customer = {
- firstName: getRandomString(4, 15),
- lastName: getRandomString(4, 15),
- emailAddress: getRandomString(10, 20),
- phoneNumber: getRandomInt(1000000000, 9999999999)
- };
- const contactInfo = {
- firstName: getRandomString(4, 15),
- lastName: getRandomString(4, 15),
- emailAddress: getRandomString(10, 20),
- servicePhone: getRandomInt(1000000000, 9999999999),
- requestTextUpdates: getRandomBoolean(),
- notesForTechnician: getRandomString(50, 100)
- };
- const mainInitialState = {
- order: {
- customer,
- contactInfo
- }
- };
- const mountOptions = getMountOptions();
- mountOptions.global = {
- plugins: [createTestingPinia({
- initialState: {
- main: mainInitialState
- }
- })]
- };
-
- const wrapper = shallowMount(contactDetails, mountOptions);
-
- // Assert
- expect(wrapper.vm.firstName).toBe(contactInfo.firstName);
- expect(wrapper.vm.lastName).toBe(contactInfo.lastName);
- expect(wrapper.vm.emailAddress).toBe(contactInfo.emailAddress);
- expect(wrapper.vm.phoneNumber).toBe(contactInfo.servicePhone);
- expect(wrapper.vm.requestTextUpdates).toBe(contactInfo.requestTextUpdates);
- expect(wrapper.vm.notesForTechnician).toBe(contactInfo.notesForTechnician);
+ expect(wrapper.vm.address).toBe(address);
+ expect(wrapper.vm.address2).toBe(address2);
+ expect(wrapper.vm.city).toBe(city);
+ expect(wrapper.vm.state).toBe(state);
+ expect(wrapper.vm.zipCode).toBe(zipCode);
+ expect(wrapper.vm.isVehicleProtected).toBe(isVehicleProtected);
+ expect(wrapper.vm.notesForTechnician).toBe(notesForTechnician);
});
});
@@ -250,7 +295,7 @@ describe('contactDetails.vue', () => {
expect(wrapper.vm.$router.navigateWithSpinner)
.toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK, undefined);
});
- test('Forward button clicked triggers appropriate navigation when safelite shop', () => {
+ test('Forward button clicked triggers appropriate navigation', () => {
// Arrange
const mountOptions = getMountOptions({
router: {
@@ -276,37 +321,44 @@ describe('contactDetails.vue', () => {
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
expect(wrapper.vm.$router.navigate)
- .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP, undefined);
+ .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD, undefined);
});
- test('Forward button clicked triggers appropriate navigation when TPA shop', () => {
+ test('Forward button click updates service location info', () => {
// Arrange
const mountOptions = getMountOptions({
router: {
navigate: jest.fn()
- },
- navigationScenarios
+ }
});
- const mainInitialState = {
- order: {
- serviceLocation: { IsSafeliteProvider: false }
- }
- };
- mountOptions.global.plugins = [createTestingPinia({
- initialState: {
- main: mainInitialState
- }
- })];
const wrapper = shallowMount(contactDetails, mountOptions);
+ const address = getRandomString(10, 50);
+ const address2 = getRandomString(0, 50);
+ const city = getRandomString(4, 20);
+ const state = getRandomString(2, 2);
+ const zipCode = getRandomInt(10000, 99999).toString();
+ const isVehicleProtected = getRandomBoolean().toString();
+ wrapper.setData({
+ address,
+ address2,
+ city,
+ state,
+ zipCode,
+ isVehicleProtected
+ });
// Act
wrapper.vm.forwardButtonAction();
// Assert
- expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
- expect(wrapper.vm.$router.navigate)
- .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, undefined);
+ expect(useMainStore().updateServiceLocation).toHaveBeenCalledWith({
+ address,
+ address2,
+ city,
+ isVehicleProtected
+ });
});
- test('Forward button click updates contact info', () => {
+
+ test('Forward button click updates notes for technician', () => {
// Arrange
const mountOptions = getMountOptions({
router: {
@@ -314,18 +366,8 @@ describe('contactDetails.vue', () => {
}
});
const wrapper = shallowMount(contactDetails, mountOptions);
- const firstName = getRandomString(4, 15);
- const lastName = getRandomString(4, 15);
- const emailAddress = getRandomString(10, 20);
- const phoneNumber = getRandomInt(1000000000, 9999999999).toString();
- const requestTextUpdates = getRandomBoolean();
const notesForTechnician = getRandomString(1, 100);
wrapper.setData({
- firstName,
- lastName,
- emailAddress,
- phoneNumber,
- requestTextUpdates,
notesForTechnician
});
@@ -334,146 +376,8 @@ describe('contactDetails.vue', () => {
// Assert
expect(useMainStore().updateContactInfo).toHaveBeenCalledWith({
- firstName,
- lastName,
- emailAddress,
- requestTextUpdates,
notesForTechnician
});
});
-
- test('Forward button click updates phone numbers request text updates', () => {
- // Arrange
- const mountOptions = getMountOptions({
- router: {
- navigate: jest.fn()
- }
- });
- const wrapper = shallowMount(contactDetails, mountOptions);
- const phoneNumber = getRandomInt(1000000000, 9999999999).toString();
- const requestTextUpdates = true;
- wrapper.setData({
- phoneNumber,
- requestTextUpdates
- });
-
- // Act
- wrapper.vm.forwardButtonAction();
-
- // Assert
- expect(useMainStore().updatePhoneNumbers).toHaveBeenCalledWith({
- service: phoneNumber,
- alternative: phoneNumber
- });
- });
-
- test('Forward button click updates phone numbers dot not request text updates', () => {
- // Arrange
- const mountOptions = getMountOptions({
- router: {
- navigate: jest.fn()
- }
- });
- const wrapper = shallowMount(contactDetails, mountOptions);
- const phoneNumber = getRandomInt(1000000000, 9999999999).toString();
- const requestTextUpdates = false;
- wrapper.setData({
- phoneNumber,
- requestTextUpdates
- });
-
- // Act
- wrapper.vm.forwardButtonAction();
-
- // Assert
- expect(useMainStore().updatePhoneNumbers).toHaveBeenCalledWith({
- home: phoneNumber,
- service: phoneNumber
- });
- });
- });
-
- test('Mocked store with no contact info yields expected data', () => {
- // Arrange
- const mountOptions = getMountOptions();
-
- const firstName = getRandomString(4, 15);
- const lastName = getRandomString(4, 15);
- const emailAddress = getRandomString(10, 20);
- const servicePhone = getRandomInt(1000000000, 9999999999);
- const mainInitialState = {
- order: {
- customer: {
- firstName,
- lastName,
- emailAddress
- },
- contactInfo: {
- firstName: null,
- lastName: null,
- emailAddress: null,
- servicePhone,
- requestTextUpdates: null,
- notesForTechnician: null
- }
- }
- };
- mountOptions.global = {
- plugins: [createTestingPinia({
- initialState: {
- main: mainInitialState
- }
- })]
- };
-
- const wrapper = shallowMount(contactDetails, mountOptions);
-
- // Assert
- expect(wrapper.vm.firstName).toBe(firstName);
- expect(wrapper.vm.lastName).toBe(lastName);
- expect(wrapper.vm.emailAddress).toBe(emailAddress);
- expect(wrapper.vm.phoneNumber).toBe(servicePhone);
- });
-
- test('Mock store with contact info yields expected data', () => {
- // Arrange
- const customer = {
- firstName: getRandomString(4, 15),
- lastName: getRandomString(4, 15),
- emailAddress: getRandomString(10, 20),
- phoneNumber: getRandomInt(1000000000, 9999999999)
- };
- const contactInfo = {
- firstName: getRandomString(4, 15),
- lastName: getRandomString(4, 15),
- emailAddress: getRandomString(10, 20),
- servicePhone: getRandomInt(1000000000, 9999999999),
- requestTextUpdates: getRandomBoolean(),
- notesForTechnician: getRandomString(50, 100)
- };
- const mainInitialState = {
- order: {
- customer,
- contactInfo
- }
- };
- const mountOptions = getMountOptions();
- mountOptions.global = {
- plugins: [createTestingPinia({
- initialState: {
- main: mainInitialState
- }
- })]
- };
-
- const wrapper = shallowMount(contactDetails, mountOptions);
-
- // Assert
- expect(wrapper.vm.firstName).toBe(contactInfo.firstName);
- expect(wrapper.vm.lastName).toBe(contactInfo.lastName);
- expect(wrapper.vm.emailAddress).toBe(contactInfo.emailAddress);
- expect(wrapper.vm.phoneNumber).toBe(contactInfo.servicePhone);
- expect(wrapper.vm.requestTextUpdates).toBe(contactInfo.requestTextUpdates);
- expect(wrapper.vm.notesForTechnician).toBe(contactInfo.notesForTechnician);
});
});
diff --git a/src/layouts/contact-details/contact-details.vue b/src/layouts/contact-details/contact-details.vue
index 7e0b22f1..c28d0d3a 100644
--- a/src/layouts/contact-details/contact-details.vue
+++ b/src/layouts/contact-details/contact-details.vue
@@ -15,81 +15,92 @@
-
-
-
-
+
+
+ v-if="showSameAsPolicyAddressQuestion"
+ ref="sameAsPolicyAddressQuestion"
+ v-model="isSameAsPolicyAddress"
+ checkboxName="sameAsPolicyAddress"
+ buttonID="sameAsPolicyAddress"
+ class="form-group same-address-checkbox"
+ :checkboxLabel="sameAsPolicyAddressQuestionText" />
+
+
+
+
+
+
+
+
-
- {{ textUpdateDisclaimerText }} I also agree to
- Safelite's
-
- and
- .
-
diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js
index 88f9c71c..6a06885a 100644
--- a/src/layouts/order-confirmation/order-confirmation.spec.js
+++ b/src/layouts/order-confirmation/order-confirmation.spec.js
@@ -79,12 +79,14 @@ const initialStore = {
isInsurance: true,
paymentMethod: paymentMethods.PAY_AT_TIME_OF_SERVICE
},
- contactInfo: {
+ customer: {
firstName: 'Test',
lastName: 'Test',
- servicePhone: '111-111-1111',
emailAddress: 'test@email.com'
},
+ contactInfo: {
+ servicePhone: '123-456-7890'
+ },
damage: {
isRepair: false
},
@@ -138,7 +140,14 @@ const sessionStorage = {
make: 'Honda',
model: 'Civic'
},
- customer: {},
+ customer: {
+ firstName: 'Test',
+ lastName: 'Test',
+ emailAddress: 'test@email.com'
+ },
+ contactInfo: {
+ servicePhone: '123-456-7890'
+ },
customerPortalLoginToken: 'token',
currentDeductible: {
replace: 100,
diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue
index 98edaf23..c3514995 100644
--- a/src/layouts/order-confirmation/order-confirmation.vue
+++ b/src/layouts/order-confirmation/order-confirmation.vue
@@ -373,7 +373,7 @@ export default {
);
// Contact Info
- const { contactInfo } = useMainStore().order;
+ const { contactInfo } = useMainStore();
const contactInfoReqs = !!(
contactInfo.firstName
&& contactInfo.lastName
diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue
index 8690e91a..d1e5641a 100644
--- a/src/layouts/part-questions/part-questions.vue
+++ b/src/layouts/part-questions/part-questions.vue
@@ -12,7 +12,8 @@
:validationRules="rules.optionRequired"
:index="currentGlassIndex"
@forwardButtonAction="forwardButtonAction"
- @backClick="navigateBackByVehicleQuestions" />
+ @backClick="navigateBackByVehicleQuestions"
+ @needHelpClick="requestCallbackBailout" />
@@ -29,6 +30,8 @@ import { Form } from 'vee-validate';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import globalRules from '@/constants/global-rules';
+import bailoutMessage from '@/constants/bailoutMessage';
+import navigationScenarios from '@/router/router-constants/navigation-scenarios';
export default {
name: 'part-questions',
@@ -145,6 +148,10 @@ export default {
// TODO KO delete for quote mvp
this.navigateForward(glassPartsForStore, null);
},
+ requestCallbackBailout() {
+ this.mainStore.setBailout(bailoutMessage.RequestCallback());
+ this.$router.navigate(navigationScenarios.CLICKED_NEED_HELP_WITH_BAILOUT, this.$route);
+ }
},
};
diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue
index 3dbacbe2..195909ec 100644
--- a/src/layouts/payment-method/payment-method.vue
+++ b/src/layouts/payment-method/payment-method.vue
@@ -52,7 +52,7 @@
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
:isStackedVertically="true"
- @backClicked="navigateBack"
+ @backClicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
@@ -230,7 +230,7 @@ export default {
const customerReqs = !!(firstName && lastName && emailAddress);
// Contact Info
- const { contactInfo } = useMainStore().order;
+ const { contactInfo } = useMainStore();
const contactInfoReqs = !!(
contactInfo.firstName
&& contactInfo.lastName
@@ -291,6 +291,15 @@ export default {
{ [routerParams.SKIP_SAVE_SESSION]: true }
);
}
+ },
+ backButtonAction() {
+ const scenario = this.mainStore.isMobileAppointment
+ ? this.navigationScenarios.CLICKED_BACK_MOBILE
+ : this.navigationScenarios.CLICKED_BACK_INSHOP;
+ this.$router.navigate(
+ scenario,
+ this.$route
+ );
}
}
};
diff --git a/src/layouts/payment-method/review-dropdown/review-dropdown.vue b/src/layouts/payment-method/review-dropdown/review-dropdown.vue
index da2c09cb..d1504da4 100644
--- a/src/layouts/payment-method/review-dropdown/review-dropdown.vue
+++ b/src/layouts/payment-method/review-dropdown/review-dropdown.vue
@@ -92,7 +92,7 @@ export default {
return useMainStore().order.serviceLocation.appointmentType;
},
customerInfo() {
- return useMainStore().order.contactInfo;
+ return useMainStore().contactInfo;
}
},
methods: {
diff --git a/src/layouts/payment-page/payment-page.spec.js b/src/layouts/payment-page/payment-page.spec.js
index 257a6367..89293dd4 100644
--- a/src/layouts/payment-page/payment-page.spec.js
+++ b/src/layouts/payment-page/payment-page.spec.js
@@ -182,10 +182,12 @@ const defaultOrder = {
},
techNotes: ''
},
- contactInfo: {
+ customer: {
firstName: 'first',
lastName: 'last',
- emailAddress: 'builddigitaltest@safelite.com',
+ emailAddress: 'builddigitaltest@safelite.com'
+ },
+ contactInfo: {
servicePhone: '555-555-5555'
},
damage: {
diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue
index 8ac64f7c..7dd6b673 100644
--- a/src/layouts/payment-page/payment-page.vue
+++ b/src/layouts/payment-page/payment-page.vue
@@ -479,15 +479,15 @@ export default {
authSignature: '',
authSignatureStart: '',
referralSequenceNumber: useMainStore().order.referralSequenceNumber,
- emailAddress: useMainStore().order.contactInfo.emailAddress,
+ emailAddress: useMainStore().contactInfo.emailAddress,
address1: this.getAddress1(),
address2: this.getAddress2(),
city: this.getCity(),
state: this.getState(),
zipCode: this.getZipCode(),
- firstName: useMainStore().order.contactInfo.firstName,
- lastName: useMainStore().order.contactInfo.lastName,
- phoneNumber: useMainStore().order.contactInfo.servicePhone,
+ firstName: useMainStore().contactInfo.firstName,
+ lastName: useMainStore().contactInfo.lastName,
+ phoneNumber: useMainStore().contactInfo.servicePhone,
ctu: useMainStore().order.serviceLocation.provider?.address?.zipCodeCtu ?? useMainStore().order.serviceLocation.zipCodeCtu,
referralCorrelationId: useMainStore().order.referralCorrelationId,
workOrderNumber: this.getWorkOrderNumber(),
@@ -593,7 +593,7 @@ export default {
);
// Contact Info
- const { contactInfo } = useMainStore().order;
+ const { contactInfo } = useMainStore();
const contactInfoReqs = !!(
contactInfo.firstName
&& contactInfo.lastName
diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue
index 99139a0a..0cd0f480 100644
--- a/src/layouts/schedule-page/schedule-page.vue
+++ b/src/layouts/schedule-page/schedule-page.vue
@@ -20,6 +20,7 @@
ref="serviceLocation"
@appointmentTypeChanged="appointmentTypeChangedFromServiceLocation"
@cityUpdated="cityUpdatedFromServiceLocation"
+ @inShopZipUpdated="inShopZipUpdatedFromServiceLocation"
@mobileZipUpdated="mobileZipUpdatedFromServiceLocation"
@providerChanged="providerChangedFromServiceLocation" />
@@ -182,7 +183,8 @@ const getAvailableDates = async (
storeAction.payload.endDate,
storeAction.payload.zipCodeOverride
).catch((error) => {
- console.log('Error fetching mobile time slots:', error);
+ // eslint-disable-next-line no-console
+ console.warn('Error fetching mobile time slots:', error);
});
}
@@ -224,6 +226,8 @@ export default {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const storeServiceLocation = useMainStore().order.serviceLocation;
const storeSelectedAppointmentType = storeServiceLocation?.appointmentType;
+ const isMobileAppointment = storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE
+ || storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP;
const storeSelectedProvider = storeServiceLocation?.provider;
const serviceZipCode = storeServiceLocation?.zipCode || useMainStore().order.customer.address.zipCode;
const zipCodeData = getZipCodeData(serviceZipCode);
@@ -275,6 +279,9 @@ export default {
// use resultMap to populate layout content.
const resultMap = await settleAllPromises(promiseResultMap);
const serviceLocationData = {
+ defaultMobileZipCode: isMobileAppointment
+ ? storeServiceLocation?.zipCode
+ : '',
glassFees: resultMap.glassFees,
mobileFeePart: resultMap.mobileFeePart,
providers: resultMap.providers,
@@ -285,8 +292,6 @@ export default {
next(async (vm) => {
const providerToUse = resultMap.providers?.shopProviders
.find((provider) => provider.providerNumber === storeSelectedProvider?.providerNumber) || resultMap.providers?.shopProviders[0];
- const isMobileAppointment = storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE
- || storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP;
const initialServiceLocationObj = {
mobileProviderNumber: isMobileAppointment
? storeSelectedProvider?.providerNumber
@@ -314,10 +319,10 @@ export default {
mobileFeePart: null,
mobilePremiumAppointmentFee: null,
mobileProviderNumber: null,
- mobileZipCodeOverride: null,
selectableDatesData: [],
selectedAppointmentType: this.getAppointmentType(),
selectedDate: this.getSelectedDate(),
+ selectedMobileZipCode: null,
selectedProvider: this.getSelectedProvider(),
selectedServiceLocation: this.getServiceLocation(),
selectedServiceLocationCity: this.getServiceLocationCity(),
@@ -401,6 +406,7 @@ export default {
});
} else {
this.mobileProviderNumber = initialServiceLocationObj.mobileProviderNumber;
+ this.selectedMobileZipCode = initialServiceLocationObj.zipCode;
await this.getDatePickerInitialData().then((initialData) => {
this.selectableDatesData = initialData.initialShopTimeSlotsResponse;
this.$refs.datePicker.setCalendarData(initialData);
@@ -430,11 +436,18 @@ export default {
return this.mainStore.order?.serviceLocation?.appointmentType;
},
async getAvailableDatesMethod(startDate, endDate) {
+ let mobileProviderNumberToUse = this.mobileProviderNumber;
+ if (this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
+ || this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
+ mobileProviderNumberToUse = this.selectedServiceLocation.mobileProviderNumber;
+ }
+
const newShopTimeSlots = await getAvailableDates(
startDate,
endDate,
this.selectedAppointmentType,
- this.selectedProvider.providerNumber
+ this.selectedProvider.providerNumber || mobileProviderNumberToUse,
+ this.selectedMobileZipCode
);
// ADD API CALL RESULTS TO EXISTING DATE DATA
this.selectableDatesData.days =
@@ -590,9 +603,17 @@ export default {
handleMqlChange(e) {
this.isMobileView = !e.matches;
},
+ inShopZipUpdatedFromServiceLocation(inShopZipServiceLocation) {
+ if (inShopZipServiceLocation) {
+ this.mobileProviderNumber = null;
+ this.selectedMobileZipCode = null;
+ this.selectedServiceLocation = inShopZipServiceLocation;
+ }
+ },
mobileZipUpdatedFromServiceLocation(mobileZipServiceLocation) {
if (mobileZipServiceLocation) {
this.mobileProviderNumber = mobileZipServiceLocation.mobileProviderNumber;
+ this.selectedMobileZipCode = mobileZipServiceLocation.zipCode;
this.selectedServiceLocation = mobileZipServiceLocation;
if (mobileZipServiceLocation.refreshDatePicker) {
diff --git a/src/layouts/schedule-page/service-location/service-location.vue b/src/layouts/schedule-page/service-location/service-location.vue
index ea0911c6..e48dddcc 100644
--- a/src/layouts/schedule-page/service-location/service-location.vue
+++ b/src/layouts/schedule-page/service-location/service-location.vue
@@ -159,7 +159,7 @@ export default {
serviceZipQuestion
},
mixins: [baseFormMixin],
- emits: ['appointment-type-changed', 'city-updated', 'mobile-zip-updated', 'provider-changed'],
+ emits: ['appointment-type-changed', 'city-updated', 'in-shop-zip-updated', 'mobile-zip-updated', 'provider-changed'],
setup() {
const mainStore = useMainStore();
return { mainStore };
@@ -171,6 +171,7 @@ export default {
city: this.getServiceCityFromStore(),
state: this.getServiceStateFromStore(),
zipCode: this.getServiceZipCodeFromStore(),
+ initializingData: false,
isGlassServiceableInshop: null,
isRecalibrationServiceableInshop: null,
isGlassServiceableMobile: null,
@@ -289,7 +290,7 @@ export default {
}
},
async mobileZipCode(newZip, oldZip) {
- if (newZip !== '' && newZip !== oldZip) {
+ if (newZip !== '' && newZip !== oldZip && !this.initializingData) {
showIssLoadingModal(true);
await this.updateMobileZip();
const updateMobileZipServiceLocationObj = {
@@ -348,8 +349,10 @@ export default {
}
},
methods: {
- initializeComponent(initialData) {
- this.setData(initialData);
+ async initializeComponent(initialData) {
+ this.initializingData = true;
+ await this.setData(initialData);
+ this.initializingData = false;
},
async forwardButtonAction() {
let provider = this.selectedProvider;
@@ -372,9 +375,6 @@ export default {
}
this.mainStore.saveServiceLocation({
- address: this.streetAddress,
- address2: this.streetAddress2,
- city: this.city,
state: this.state,
zipCode: this.zipCode,
zipCodeCtu: this.zipCodeCtu,
@@ -417,6 +417,7 @@ export default {
this.zipCode = newZip;
const zipCodeData = await getZipCodeData(this.zipCode);
this.city = zipCodeData.city;
+ this.state = zipCodeData.state;
this.setCtuForMobile(zipCodeData.zipCodeCtu);
this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase);
@@ -426,6 +427,17 @@ export default {
if (details) {
this.setServiceabilityDetails(details);
}
+
+ const inShopZipServiceLocationObj = {
+ appointmentType: AppointmentTypeStrings.IN_SHOP,
+ mobileProviderNumber: null,
+ provider: this.selectedProvider,
+ refreshDatePicker: false,
+ resetDatePicker: false,
+ zipCode: newZip,
+ zipCodeCtu: zipCodeData.zipCodeCtu
+ };
+ this.$emit('in-shop-zip-updated', inShopZipServiceLocationObj);
});
},
refreshAvailabilityRating() {
@@ -449,11 +461,16 @@ export default {
setCtuForMobile(val) {
this.zipCodeCtu = val;
},
- setData(initialData) {
+ async setData(initialData) {
+ if (initialData.defaultMobileZipCode) {
+ this.mobileZipCode = initialData.defaultMobileZipCode;
+ }
+
if (initialData.zipCodeData) {
this.zipContainsMilitaryBase = initialData.zipCodeData.containsMilitaryBase;
this.zipCodeCtu = initialData.zipCodeData.zipCodeCtu;
this.city = initialData.zipCodeData.city;
+ this.state = initialData.zipCodeData.state;
}
if (initialData.serviceabilityDetails) {
@@ -523,6 +540,7 @@ export default {
this.mobileZipError = errorMessages.NO_SERVICE_IN_AREA(toTitleCase(zipCodeData.city));
} else {
this.city = zipCodeData.city;
+ this.state = zipCodeData.state;
this.zipCode = this.mobileZipCode;
this.setCtuForMobile(zipCodeData.zipCodeCtu);
this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase);
@@ -601,12 +619,6 @@ $page-side-padding: 1.5rem;
div.alert {
margin-top: 0.625rem;
- :deep(.alert-header) {
- button.btn-collapse {
- display: block;
- }
- }
-
button.looka-likea-link {
background: none;
border: none;
diff --git a/src/layouts/service-packages/service-packages.vue b/src/layouts/service-packages/service-packages.vue
index 692546ce..1bed0a7c 100644
--- a/src/layouts/service-packages/service-packages.vue
+++ b/src/layouts/service-packages/service-packages.vue
@@ -195,8 +195,12 @@ export default {
}
store.updateVaps(this.selectedVaps);
+ const scenario = store.isMobileAppointment
+ ? this.navigationScenarios.CLICKED_FORWARD_MOBILE
+ : this.navigationScenarios.CLICKED_FORWARD_INSHOP;
+
this.$router.navigate(
- this.navigationScenarios.CLICKED_FORWARD,
+ scenario,
this.$route
);
}
diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue
index 9476a7ad..83d211c1 100644
--- a/src/layouts/tpa-search/tpa-search.vue
+++ b/src/layouts/tpa-search/tpa-search.vue
@@ -389,9 +389,9 @@ export default {
return getTpaProvidersResult?.data?.shopProviders ?? [];
},
doNotSeeMyShopLinkClick() {
- this.mainStore.setBailout(bailoutMessage.doNotSeeMyShop());
+ this.mainStore.setBailout(bailoutMessage.RequestCallback());
this.$router.navigate(
- this.navigationScenarios.CLICKED_DO_NOT_SEE_MY_SHOP_LINK,
+ this.navigationScenarios.CLICKED_NEED_HELP,
this.$route
);
},
diff --git a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js
index 901effe9..04fe6ce6 100644
--- a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js
+++ b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js
@@ -38,10 +38,12 @@ describe('contact-details-drawer', () => {
const servicePhone = '606-009-2943';
const mainInitialState = {
order: {
- contactInfo: {
+ customer: {
firstName,
lastName,
- emailAddress,
+ emailAddress
+ },
+ contactInfo: {
servicePhone
}
}
@@ -112,10 +114,12 @@ describe('contact-details-drawer', () => {
const phoneNumber = '123-456-1234';
const mainInitialState = {
order: {
- contactInfo: {
+ customer: {
firstName,
lastName,
- emailAddress,
+ emailAddress
+ },
+ contactInfo: {
phoneNumber
}
}
diff --git a/src/layouts/tpa-submit/tpa-submit.spec.js b/src/layouts/tpa-submit/tpa-submit.spec.js
index 63b61c40..11136dd7 100644
--- a/src/layouts/tpa-submit/tpa-submit.spec.js
+++ b/src/layouts/tpa-submit/tpa-submit.spec.js
@@ -388,10 +388,12 @@ describe('tpa-submit', () => {
companyName: providerCompanyName
}
},
- contactInfo: {
+ customer: {
firstName,
lastName,
- emailAddress,
+ emailAddress
+ },
+ contactInfo: {
servicePhone
}
}
@@ -433,10 +435,12 @@ describe('tpa-submit', () => {
companyName: providerCompanyName
}
},
- contactInfo: {
+ customer: {
firstName,
lastName,
- emailAddress,
+ emailAddress
+ },
+ contactInfo: {
servicePhone,
extension
}
diff --git a/src/layouts/vehicle-lookup/vehicle-lookup.spec.js b/src/layouts/vehicle-lookup/vehicle-lookup.spec.js
index 0aa12f8a..300b656d 100644
--- a/src/layouts/vehicle-lookup/vehicle-lookup.spec.js
+++ b/src/layouts/vehicle-lookup/vehicle-lookup.spec.js
@@ -13,6 +13,7 @@ import errorMessages from '@/constants/error-messages';
import globalRules from '@/constants/global-rules';
import { required } from '@/helpers/validation-rules';
import VehicleLookup from '@/layouts/vehicle-lookup/vehicle-lookup.vue';
+import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
const pinia = createTestingPinia();
useMainStore(pinia);
@@ -40,6 +41,13 @@ const vinLookupMethodsMockData = {
SubText: 'Most convenient VIN match',
ImageId: '',
SubWidgetName: ''
+ },
+ {
+ Name: 'NoVin',
+ Text: 'I\'d prefer not to share my VIN',
+ SubText: '',
+ ImageId: '',
+ SubWidgetName: ''
}
]
};
@@ -118,7 +126,8 @@ function setupMocks() {
},
stubs: {
SiteHeader: true,
- SiteSubHeader: true
+ SiteSubHeader: true,
+ TextBlock: true
}
}
});
@@ -264,6 +273,29 @@ describe('vehicle-lookup.vue', () => {
* Currently just trust that our custom navigate() method does its job properly.
*/
});
+
+ test('Select "I\'d prefer not to share my VIN" then click "Continue". Calls navigateForward from vehicleQuestionsMixin', async () => {
+ useMainStore().getPartsOrQuestions = () => ({ data: { partsOrQuestions: [] } });
+ navigateSpy = jest.spyOn(vehicleQuestionsMixin.methods, 'navigateForward').mockImplementation(async () => {});
+ const { wrapper } = setupMocks();
+
+ const vinLookupMethodsWrapper = wrapper.findComponent({ name: 'vin-lookup-methods' });
+ // Not using initializeComponent() because it doesn't trigger reactivity in test.
+ await vinLookupMethodsWrapper.setData({
+ questionTextFromCms: vinLookupMethodsMockData.QuestionText,
+ answersFromCms: vinLookupMethodsMockData.Answers
+ });
+
+ const noVinOptionLabel = wrapper
+ .find('[data-test-id="vin-lookup-methods-button-question"] label[for="VinLookupMethods-NoVin"]');
+ await noVinOptionLabel.trigger('mousedown');
+
+ const continueButton = wrapper.get('[data-test-id="site-footer-main-button"]');
+ await continueButton.trigger('click');
+
+ // Assert
+ expect(navigateSpy).toHaveBeenCalled();
+ });
/**
* To Do: Error message is not displayed when running test
diff --git a/src/layouts/vehicle-lookup/vehicle-lookup.vue b/src/layouts/vehicle-lookup/vehicle-lookup.vue
index 27ef29db..ad251447 100644
--- a/src/layouts/vehicle-lookup/vehicle-lookup.vue
+++ b/src/layouts/vehicle-lookup/vehicle-lookup.vue
@@ -10,8 +10,8 @@
+ class="subheader mt-4"
+ subHeaderMarginClasses="mt-4" />
+
@@ -35,6 +38,7 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin';
+import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import vinLookupMethodSelections from '@/constants/vin-lookup-methods';
// Import Component
@@ -42,6 +46,7 @@ import SiteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import SiteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import VinLookupMethods from '@/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue';
+import TextBlock from '@/digital-components/text-block/text-block.vue';
export default {
name: 'vehicle-lookup',
@@ -51,9 +56,10 @@ export default {
SiteFooter,
siteHeader,
SiteSubHeader,
- VinLookupMethods
+ VinLookupMethods,
+ TextBlock
},
- mixins: [BaseFormMixin],
+ mixins: [BaseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
@@ -86,7 +92,7 @@ export default {
arePagePrerequisiteValid() {
return true;
},
- forwardButtonAction() {
+ async forwardButtonAction() {
switch (this.selectedVinLookupMethod) {
case vinLookupMethodSelections.MANUALVIN:
this.$router.navigate(
@@ -106,6 +112,24 @@ export default {
this.$route
);
break;
+ case vinLookupMethodSelections.NOVIN:
+ const partsOrQuestionsResponse = await this.getPartsOrQuestions();
+ if (partsOrQuestionsResponse.error) {
+ this.mainStore.setBailout(bailoutMessage.PartsServiceError(partsOrQuestionsResponse.error.data));
+ window.console.error('Error on retrieving PartsOrQuestions');
+ this.hasBailedOut = true;
+ this.$router.navigate(
+ this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
+ this.$route
+ );
+ }
+ else {
+ await this.navigateForward(
+ partsOrQuestionsResponse.data.partsOrQuestions,
+ this
+ );
+ }
+ break;
default:
break;
}
@@ -124,5 +148,23 @@ export default {
padding-right: .9375rem;
}
}
-
+.subheader {
+ :deep(.all-caps) {
+ text-transform: uppercase;
+ }
+ :deep(.subheader-secondary>p) {
+ margin-bottom: 0;
+ }
+}
+.security-text {
+ text-align: center;
+ margin-bottom: 1.5rem;
+ :deep(a) {
+ font-weight: $font-weight-normal;
+ color: $heritage-blue-primary;
+ &:hover {
+ color: #125b7e;
+ }
+ }
+}
diff --git a/src/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue b/src/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue
index 6c92856a..633dc865 100644
--- a/src/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue
+++ b/src/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue
@@ -1,11 +1,11 @@
@@ -83,3 +83,18 @@ export default {
}
};
+
\ No newline at end of file
diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue
index 4f0a38ee..677cd1fd 100644
--- a/src/layouts/welcome-page/welcome-page.vue
+++ b/src/layouts/welcome-page/welcome-page.vue
@@ -509,7 +509,6 @@ form {
:deep(.input-wrapper) {
input[type="date"]::-webkit-calendar-picker-indicator {
background-color: $svg-calendar-error-fill-color;
- // eslint-disable-next-line max-len
background-image: url($svg-error-calendar-graphic);
}
}
diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js
index 24a0ffb9..6f17494d 100644
--- a/src/router/router-constants/navigation-scenarios.js
+++ b/src/router/router-constants/navigation-scenarios.js
@@ -73,7 +73,7 @@ const navigationScenarios = Object.freeze({
PRICING_LOOKUP_ERROR: 'PRICING_LOOKUP_ERROR',
// TPA Search
- CLICKED_DO_NOT_SEE_MY_SHOP_LINK: 'CLICKED_DO_NOT_SEE_MY_SHOP_LINK',
+ CLICKED_NEED_HELP: 'CLICKED_NEED_HELP',
CLICKED_FORWARD_WITH_SAFELITE_SHOP: 'CLICKED_FORWARD_WITH_SAFELITE_SHOP',
CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP: 'CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP',
@@ -90,6 +90,10 @@ const navigationScenarios = Object.freeze({
CLICKED_FORWARD_WITH_TPA_DISABLED: 'CLICKED_FORWARD_WITH_TPA_DISABLED',
CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: 'CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES',
+ // Service Package
+ CLICKED_FORWARD_INSHOP: 'CLICKED_FORWARD_INSHOP',
+ CLICKED_FORWARD_MOBILE: 'CLICKED_FORWARD_MOBILE',
+
// Review Page
CLICKED_CUSTOMER_EDIT: 'CLICKED_CUSTOMER_EDIT',
CLICKED_DAMAGE_EDIT: 'CLICKED_DAMAGE_EDIT',
@@ -99,13 +103,16 @@ const navigationScenarios = Object.freeze({
CLICKED_VEHICLE_EDIT: 'CLICKED_VEHICLE_EDIT',
// Payment
+ CLICKED_BACK_INSHOP: 'CLICKED_BACK_INSHOP',
+ CLICKED_BACK_MOBILE: 'CLICKED_BACK_MOBILE',
CLICKED_PAY_NOW: 'CLICKED_PAY_NOW',
PAY_IN_ADVANCE_ERROR: 'PAY_IN_ADVANCE_ERROR',
PAY_IN_ADVANCE_CREDIT_CARD_ERROR: 'PAY_IN_ADVANCE_CREDIT_CARD_ERROR',
PAY_IN_ADVANCE_SUCCESS: 'PAY_IN_ADVANCE_SUCCESS',
// Bailout
- CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT'
+ CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT',
+ CLICKED_NEED_HELP_WITH_BAILOUT: 'CLICKED_NEED_HELP_WITH_BAILOUT',
});
export default navigationScenarios;
diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js
index a23699d8..dea1daae 100644
--- a/src/router/router-constants/routing-table.js
+++ b/src/router/router-constants/routing-table.js
@@ -80,6 +80,26 @@ const routingTable = () => [
{
scenario: navigationScenarios.SELECTED_HOME_ADDRESS,
destinationIssPageValue: issPageValues.ADDRESS_LOOKUP
+ },
+ {
+ scenario: navigationScenarios.CLICKED_FORWARD_WITH_PART_QUESTIONS,
+ destinationIssPageValue: issPageValues.PART_QUESTIONS
+ },
+ {
+ scenario: navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_PARTS_TO_CHOOSE,
+ destinationIssPageValue: issPageValues.VEHICLE_PARTS
+ },
+ {
+ scenario: navigationScenarios.CLICKED_FORWARD_WITH_MOLDING_QUESTIONS,
+ destinationIssPageValue: issPageValues.MOLDING_QUESTIONS
+ },
+ {
+ scenario: navigationScenarios.CLICKED_FORWARD_WITH_CAPABILITY_QUESTIONS,
+ destinationIssPageValue: issPageValues.CAPABILITY_QUESTIONS
+ },
+ {
+ scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
+ destinationIssPageValue: issPageValues.COVERAGE_STATEMENT
}
]
},
@@ -191,6 +211,10 @@ const routingTable = () => [
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
destinationIssPageValue: issPageValues.COVERAGE_STATEMENT
+ },
+ {
+ scenario: navigationScenarios.CLICKED_NEED_HELP_WITH_BAILOUT,
+ destinationIssPageValue: issPageValues.BAILOUT_PAGE
}
]
},
@@ -584,7 +608,7 @@ const routingTable = () => [
},
{
scenario: navigationScenarios.CLICKED_FORWARD,
- destinationIssPageValue: issPageValues.CONTACT_DETAILS
+ destinationIssPageValue: issPageValues.SERVICE_PACKAGES
}
]
},
@@ -596,12 +620,8 @@ const routingTable = () => [
destinationIssPageValue: issPageValues.SCHEDULE_PAGE
},
{
- scenario: navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP,
- destinationIssPageValue: issPageValues.SERVICE_PACKAGES
- },
- {
- scenario: navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
- destinationIssPageValue: issPageValues.TPA_SUBMIT
+ scenario: navigationScenarios.CLICKED_FORWARD,
+ destinationIssPageValue: issPageValues.PAYMENT_METHOD
}
]
},
@@ -610,11 +630,15 @@ const routingTable = () => [
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
- destinationIssPageValue: issPageValues.CONTACT_DETAILS
+ destinationIssPageValue: issPageValues.SCHEDULE_PAGE
},
{
- scenario: navigationScenarios.CLICKED_FORWARD,
+ scenario: navigationScenarios.CLICKED_FORWARD_INSHOP,
destinationIssPageValue: issPageValues.PAYMENT_METHOD
+ },
+ {
+ scenario: navigationScenarios.CLICKED_FORWARD_MOBILE,
+ destinationIssPageValue: issPageValues.CONTACT_DETAILS
}
]
},
@@ -622,9 +646,13 @@ const routingTable = () => [
issPageValue: issPageValues.PAYMENT_METHOD,
maps: [
{
- scenario: navigationScenarios.CLICKED_BACK,
+ scenario: navigationScenarios.CLICKED_BACK_INSHOP,
destinationIssPageValue: issPageValues.SERVICE_PACKAGES
},
+ {
+ scenario: navigationScenarios.CLICKED_BACK_MOBILE,
+ destinationIssPageValue: issPageValues.CONTACT_DETAILS
+ },
{
scenario: navigationScenarios.CLICKED_FORWARD,
destinationIssPageValue: issPageValues.ORDER_CONFIRMATION
@@ -740,7 +768,7 @@ const routingTable = () => [
destinationIssPageValue: issPageValues.TPA_SUBMIT
},
{
- scenario: navigationScenarios.CLICKED_DO_NOT_SEE_MY_SHOP_LINK,
+ scenario: navigationScenarios.CLICKED_NEED_HELP,
destinationIssPageValue: issPageValues.BAILOUT_PAGE
}
]
diff --git a/src/store/index.js b/src/store/index.js
index 86ac47d8..65c09a29 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -191,9 +191,6 @@ export const getDefaultState = () => ({
}
},
contactInfo: {
- firstName: null,
- lastName: null,
- emailAddress: null,
homePhone: null,
alternativePhone: null,
servicePhone: null,
@@ -358,9 +355,9 @@ export const useMainStore = defineStore({
};
},
contactInfo: (s) => ({
- firstName: s.order.contactInfo.firstName ?? s.order.customer.firstName,
- lastName: s.order.contactInfo.lastName ?? s.order.customer.lastName,
- emailAddress: s.order.contactInfo.emailAddress ?? s.order.customer.emailAddress,
+ firstName: s.order.customer.firstName,
+ lastName: s.order.customer.lastName,
+ emailAddress: s.order.customer.emailAddress,
homePhone: s.order.contactInfo.homePhone,
alternativePhone: s.order.contactInfo.alternativePhone,
servicePhone: s.order.contactInfo.servicePhone,
@@ -1472,9 +1469,9 @@ export const useMainStore = defineStore({
state: customer.address?.state,
zipCode: customer.address?.zipCode?.toString()
},
- emailAddress: contactInfo.emailAddress || customer.emailAddress,
- firstName: contactInfo.firstName || customer.firstName,
- lastName: contactInfo.lastName || customer.lastName,
+ emailAddress: customer.emailAddress,
+ firstName: customer.firstName,
+ lastName: customer.lastName,
homePhone: contactInfo.extension && contactInfo.homePhone ? contactInfo.homePhone + contactInfo.extension : contactInfo.homePhone,
servicePhone: contactInfo.servicePhone,
alternativePhone: contactInfo.alternativePhone,
@@ -1679,11 +1676,10 @@ export const useMainStore = defineStore({
order.customer.address.city = data.customer?.address?.city;
order.customer.address.state = data.customer?.address?.state;
order.customer.address.zipCode = data.customer?.address?.zipCode;
- order.customer.emailAddress = data.customer?.emailAddress;
+ order.customer.firstName = data?.customer?.firstName;
+ order.customer.lastName = data?.customer?.lastName;
+ order.customer.emailAddress = data?.customer?.emailAddress;
- order.contactInfo.firstName = data?.customer?.firstName;
- order.contactInfo.lastName = data?.customer?.lastName;
- order.contactInfo.emailAddress = data?.customer?.emailAddress;
order.contactInfo.extension = data?.customer?.homePhone?.slice(10);
order.contactInfo.homePhone = data?.customer?.homePhone?.slice(0, 10);
order.contactInfo.servicePhone = data?.customer?.servicePhone;
@@ -1829,27 +1825,29 @@ export const useMainStore = defineStore({
this.order.vehicle.registration.lastName = registrationInfo?.lastName;
},
updateServiceLocation(serviceLocationInfo) {
- this.order.serviceLocation.address = serviceLocationInfo.address;
- this.order.serviceLocation.address2 = serviceLocationInfo.address2;
- this.order.serviceLocation.city = serviceLocationInfo.city;
- this.order.serviceLocation.state = serviceLocationInfo.state;
- this.order.serviceLocation.zipCode = serviceLocationInfo.zipCode;
- this.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu;
- this.order.serviceLocation.appointmentType = serviceLocationInfo.appointmentType;
- this.order.serviceLocation.isVehicleProtected = serviceLocationInfo.isVehicleProtected;
+ this.order.serviceLocation.address = serviceLocationInfo.address ?? this.order.serviceLocation.address;
+ this.order.serviceLocation.address2 = serviceLocationInfo.address2 ?? this.order.serviceLocation.address2;
+ this.order.serviceLocation.city = serviceLocationInfo.city ?? this.order.serviceLocation.city;
+ this.order.serviceLocation.state = serviceLocationInfo.state ?? this.order.serviceLocation.state;
+ this.order.serviceLocation.zipCode = serviceLocationInfo.zipCode ?? this.order.serviceLocation.zipCode;
+ this.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu ?? this.order.serviceLocation.zipCodeCtu;
+ this.order.serviceLocation.appointmentType = serviceLocationInfo.appointmentType ?? this.order.serviceLocation.appointmentType;
+ this.order.serviceLocation.isVehicleProtected = serviceLocationInfo.isVehicleProtected ?? this.order.serviceLocation.isVehicleProtected;
- this.order.serviceLocation.provider = {
- providerNumber: serviceLocationInfo.provider?.providerNumber,
- address: {
- streetAddress: serviceLocationInfo.provider?.address?.streetAddress,
- city: serviceLocationInfo.provider?.address?.city,
- state: serviceLocationInfo.provider?.address?.state,
- zipCode: serviceLocationInfo.provider?.address?.zipCode,
- zipCodeCtu: serviceLocationInfo.provider?.address?.zipCodeCtu
- },
- companyName: serviceLocationInfo.provider?.companyName,
- phoneNumber: serviceLocationInfo.provider?.phoneNumber
- };
+ if (serviceLocationInfo.provider) {
+ this.order.serviceLocation.provider = {
+ providerNumber: serviceLocationInfo.provider?.providerNumber,
+ address: {
+ streetAddress: serviceLocationInfo.provider?.address?.streetAddress,
+ city: serviceLocationInfo.provider?.address?.city,
+ state: serviceLocationInfo.provider?.address?.state,
+ zipCode: serviceLocationInfo.provider?.address?.zipCode,
+ zipCodeCtu: serviceLocationInfo.provider?.address?.zipCodeCtu
+ },
+ companyName: serviceLocationInfo.provider?.companyName,
+ phoneNumber: serviceLocationInfo.provider?.phoneNumber
+ };
+ }
this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter;
},
@@ -2122,9 +2120,6 @@ export const useMainStore = defineStore({
},
resetContactInfo() {
- this.order.contactInfo.firstName = null;
- this.order.contactInfo.lastName = null;
- this.order.contactInfo.emailAddress = null;
this.order.contactInfo.homePhone = null;
this.order.contactInfo.alternativePhone = null;
this.order.contactInfo.servicePhone = null;
@@ -2608,9 +2603,10 @@ export const useMainStore = defineStore({
},
updateContactInfo(contactInfo) {
- this.order.contactInfo.firstName = contactInfo?.firstName ?? '';
- this.order.contactInfo.lastName = contactInfo?.lastName ?? '';
- this.order.contactInfo.emailAddress = contactInfo?.emailAddress ?? '';
+ this.order.customer.firstName = contactInfo?.firstName ?? this.order.customer.firstName;
+ this.order.customer.lastName = contactInfo?.lastName ?? this.order.customer.lastName;
+ this.order.customer.emailAddress = contactInfo?.emailAddress ?? this.order.customer.emailAddress;
+
this.order.contactInfo.requestTextUpdates = contactInfo?.requestTextUpdates ?? false;
this.order.contactInfo.notesForTechnician = contactInfo?.notesForTechnician ?? '';
},
diff --git a/src/store/store.spec.js b/src/store/store.spec.js
index a2539b94..3af3f359 100644
--- a/src/store/store.spec.js
+++ b/src/store/store.spec.js
@@ -487,7 +487,7 @@ describe('Store', () => {
// Arrange
const firstName = getRandomString(4, 10);
const lastName = getRandomString(5, 15);
- const emailAddress = false;
+ const emailAddress = getRandomString(5, 15);
const requestTextUpdates = getRandomBoolean();
const notesForTechnician = getRandomString(50, 150);
@@ -526,14 +526,14 @@ describe('Store', () => {
expect(store.contactInfo.alternativePhone).toEqual(altPhone);
expect(store.contactInfo.extension).toEqual(extension);
});
- it('All null values => contact info set in store to all nulls', () => {
+ it('All null values => contact info set in store to all null/default', () => {
// Act
store.updateContactInfo({});
// Assert
- expect(store.contactInfo.firstName).toEqual('');
- expect(store.contactInfo.lastName).toEqual('');
- expect(store.contactInfo.emailAddress).toEqual('');
+ expect(store.contactInfo.firstName).toEqual(null);
+ expect(store.contactInfo.lastName).toEqual(null);
+ expect(store.contactInfo.emailAddress).toEqual(null);
expect(store.contactInfo.requestTextUpdates).toEqual(false);
expect(store.contactInfo.notesForTechnician).toEqual('');
});
@@ -755,13 +755,13 @@ describe('Store', () => {
const contactServicePhone = getRandomString(6, 6);
const contactAlternativePhone = getRandomString(6, 6);
const requestTextUpdates = getRandomBoolean();
- store.order.contactInfo.firstName = contactFirstName;
- store.order.contactInfo.lastName = contactLastName;
- store.order.contactInfo.emailAddress = contactEmail;
store.order.contactInfo.homePhone = contactHomePhone;
store.order.contactInfo.servicePhone = contactServicePhone;
store.order.contactInfo.alternativePhone = contactAlternativePhone;
store.order.contactInfo.requestTextUpdates = requestTextUpdates;
+ store.order.customer.firstName = contactFirstName;
+ store.order.customer.lastName = contactLastName;
+ store.order.customer.emailAddress = contactEmail;
store.order.customer.address.streetAddress = streetAddress;
store.order.customer.address.streetAddress2 = streetAddress2;
store.order.customer.address.city = city;
diff --git a/src/ux-components/alert/alert.vue b/src/ux-components/alert/alert.vue
index 1a74bdf9..4d50bc1b 100644
--- a/src/ux-components/alert/alert.vue
+++ b/src/ux-components/alert/alert.vue
@@ -31,41 +31,44 @@
-
-
+