Merge branch 'develop' into feature/CSR-120_vehicle-banner-2
This commit is contained in:
commit
fc8a9632cb
34 changed files with 905 additions and 368 deletions
3
src/assets/img/icons/back-forward.svg
Normal file
3
src/assets/img/icons/back-forward.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45.6 36.1" xml:space="preserve">
|
||||||
|
<path d="M43.6 0H18.1c-.4 0-.8.1-1.1.4l-.3.3-16 16c-.8.8-.8 2 0 2.8l16 16 .3.3c.3.2.7.4 1.1.4h25.5c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2zm-3.4 28.1-1.4 1.4-10-10-10 10-1.4-1.4 10-10-10-10 1.4-1.4 10 10 10-10L40.2 8l-10 10 10 10.1z" fill="#8e9292"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 338 B |
3
src/assets/img/icons/close.svg
Normal file
3
src/assets/img/icons/close.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.7 23.7" xml:space="preserve">
|
||||||
|
<path d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 397 B |
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
describe("baseTemplate.vue", () => {
|
|
||||||
it("Is a test", () => {
|
|
||||||
expect(true).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="select-car sticky-lg-top py-4">
|
|
||||||
<div class="select-car-form overflow-hidden p-3 rounded">
|
|
||||||
<div class="car_info text-center">
|
|
||||||
<div class="car-image mb-3">
|
|
||||||
<img
|
|
||||||
class="vehicle-image img-fluid"
|
|
||||||
:class="{ blur: blurImg }"
|
|
||||||
:src="carImg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="current_car_info">
|
|
||||||
<transition appear name="fade">
|
|
||||||
<div
|
|
||||||
class="current_car_info-text"
|
|
||||||
v-on:click="backFunction ? backFunction() : null"
|
|
||||||
>
|
|
||||||
<span class="text-center text-secondary fs-5 d-block">{{
|
|
||||||
this.currentCarInfo
|
|
||||||
}}</span>
|
|
||||||
<span v-if="style" class="text-center text-secondary fs-6 mt-2">{{
|
|
||||||
style
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
<transition appear :name="slideTransition">
|
|
||||||
<div class="needed_car_info d-flex overflow-hidden mt-4 mb-3">
|
|
||||||
<span class="text-center fs-6 fw-bold needed_car_info-text">{{
|
|
||||||
this.neededCarInfo
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
<transition appear :name="slideTransition">
|
|
||||||
<slot></slot>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState } from "vuex";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "BaseTemplate",
|
|
||||||
computed: {
|
|
||||||
...mapState(["slideTransition", "carImg", "blurImg", "style"]),
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
currentCarInfo: String,
|
|
||||||
neededCarInfo: String,
|
|
||||||
backFunction: Function,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
<template>
|
|
||||||
<form class="list-view d-flex">
|
|
||||||
<div class="car_list">
|
|
||||||
<div v-for="attritbute in attritbutes" :key="attritbute" class="mb-2">
|
|
||||||
<buttonPrimary :buttonText="attritbute" v-on:click="selectAttribute(attritbute)" buttonType="btn-funnel" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import buttonPrimary from "@/uxComponents/buttonPrimary/buttonPrimary";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "CarAttributes",
|
|
||||||
props: {
|
|
||||||
attritbutes: Array,
|
|
||||||
selectAttribute: Function,
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
buttonPrimary,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
22
src/commonComponents/radioQuestion/radioQuestion.spec.js
Normal file
22
src/commonComponents/radioQuestion/radioQuestion.spec.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import radioQuestion from './radioQuestion';
|
||||||
|
|
||||||
|
describe('radioQuestion.vue', () => {
|
||||||
|
it("Should render the 'questionText' prop value as a span value for the radio question and the 'answer' values should render as text values for radio components.", () => {
|
||||||
|
// Act
|
||||||
|
const wrapper = shallowMount(radioQuestion, {
|
||||||
|
propsData: {
|
||||||
|
questionText: 'Question Text',
|
||||||
|
answers: ['2023', '2022', '2021'],
|
||||||
|
chooseAnswer: function(test){ console.log(test) }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.find('.needed_car_info-text').text()).toEqual('Question Text');
|
||||||
|
const radioButtons = wrapper.findAllComponents('[data-test="radio"]');
|
||||||
|
expect(radioButtons[0].attributes('text')).toEqual('2023');
|
||||||
|
expect(radioButtons[2].attributes('text')).toEqual('2021');
|
||||||
|
expect(typeof wrapper.props().chooseAnswer).toBe('function');
|
||||||
|
})
|
||||||
|
})
|
||||||
27
src/commonComponents/radioQuestion/radioQuestion.vue
Normal file
27
src/commonComponents/radioQuestion/radioQuestion.vue
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<template>
|
||||||
|
<div class="radio_question">
|
||||||
|
<div class="needed_car_info d-flex mt-4 mb-3">
|
||||||
|
<span class="text-center fs-6 fw-bold w-100 needed_car_info-text">{{ questionText }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="car_list overflow-scroll position-absolute">
|
||||||
|
<div v-for="answer in answers" :key="answer" class="mb-2">
|
||||||
|
<radio :text="answer" :value="answer" @click="chooseAnswer(answer)" data-test="radio" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import radio from "@/uxComponents/radio/radio";
|
||||||
|
export default {
|
||||||
|
name: "radio-question",
|
||||||
|
props: {
|
||||||
|
questionText: String,
|
||||||
|
answers: Array,
|
||||||
|
chooseAnswer: Function
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
radio
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -2,6 +2,25 @@ const endpoints = {
|
||||||
GetRouteInfoEndpoint: {
|
GetRouteInfoEndpoint: {
|
||||||
url: '/content/api/v1/content/RouteInfo',
|
url: '/content/api/v1/content/RouteInfo',
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
|
},
|
||||||
|
GetYears: {
|
||||||
|
url: '/vehicle/api/v1/vehicle/years',
|
||||||
|
method: 'GET'
|
||||||
|
},
|
||||||
|
GetMakes: {
|
||||||
|
url: '/vehicle/api/v1/vehicle/Makes',
|
||||||
|
method: 'POST'
|
||||||
|
},
|
||||||
|
GetModels: {
|
||||||
|
url: '/vehicle/api/v1/vehicle/Models',
|
||||||
|
method: 'POST'
|
||||||
|
},
|
||||||
|
GetStyles: {
|
||||||
|
url: '/vehicle/api/v1/vehicle/Styles',
|
||||||
|
method: 'POST'
|
||||||
|
},
|
||||||
|
GetPageData: {
|
||||||
|
method: 'GET'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
const storeActions = {
|
const storeActions = {
|
||||||
GET_ROUTE_INFO_ACTION: "getRouteInfo",
|
GET_ROUTE_INFO_ACTION: "getRouteInfo",
|
||||||
|
GET_YEARS: 'getYears',
|
||||||
|
GET_PAGE_DATA: 'getMockPageData',
|
||||||
}
|
}
|
||||||
|
|
||||||
export { storeActions }
|
export { storeActions }
|
||||||
|
|
@ -11,7 +11,7 @@ export default {
|
||||||
|
|
||||||
axios({
|
axios({
|
||||||
method: method,
|
method: method,
|
||||||
url: `${apiGatewayUrl}${endpoint}`,
|
url: apiGatewayUrl + endpoint,
|
||||||
data: payloadAndAnalyticsData,
|
data: payloadAndAnalyticsData,
|
||||||
crossDomain: true,
|
crossDomain: true,
|
||||||
responseType: {},
|
responseType: {},
|
||||||
|
|
@ -29,4 +29,30 @@ export default {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
callMockHttpClient({ method, endpoint}) {
|
||||||
|
// For Mock use only!
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
axios({
|
||||||
|
method: method,
|
||||||
|
url: endpoint,
|
||||||
|
crossDomain: true,
|
||||||
|
responseType: {},
|
||||||
|
}).then((response) => {
|
||||||
|
|
||||||
|
if (response.status == httpStatusCodes.OK) {
|
||||||
|
resolve(response);
|
||||||
|
} else {
|
||||||
|
reject(response);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return reject(error.response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
73
src/global-methods.spec.js
Normal file
73
src/global-methods.spec.js
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import globalMethods from "@/global-methods";
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
//Mock external dependencies
|
||||||
|
jest.mock('axios');
|
||||||
|
|
||||||
|
it("Global Methods - Call Http Client - Should Resolve Promise", () => {
|
||||||
|
//Arrange
|
||||||
|
const endpoint = 'https://mock.safelite.com';
|
||||||
|
const httpArgs = setupMocksForHttpClient({ endpoint: endpoint });
|
||||||
|
|
||||||
|
//Act
|
||||||
|
globalMethods.callHttpClient(httpArgs)
|
||||||
|
.then((response) => {
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(axios.mock.calls[0][0].url).toContain(endpoint);
|
||||||
|
expect(response.data.message).toContain('Success');
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Global Methods - Call Http Client - Should Reject Promise", () => {
|
||||||
|
//Arrange
|
||||||
|
const endpoint = 'https://mock.safelite.com';
|
||||||
|
const httpArgs = setupMocksForHttpClient({ endpoint: endpoint, isError: true });
|
||||||
|
|
||||||
|
//Act
|
||||||
|
globalMethods.callHttpClient(httpArgs)
|
||||||
|
.catch((err) => {
|
||||||
|
//Assert
|
||||||
|
expect(axios.mock.calls[0][0].url).toContain(endpoint);
|
||||||
|
expect(err.data.message).toContain('Error');
|
||||||
|
expect(err.status).toEqual(500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupMocksForHttpClient({ endpoint = null, isError = false, additionalData = null }) {
|
||||||
|
|
||||||
|
//Clear node module
|
||||||
|
axios.mockClear();
|
||||||
|
|
||||||
|
// Success Response
|
||||||
|
const response = {
|
||||||
|
status: 200,
|
||||||
|
data: {
|
||||||
|
message: 'Success',
|
||||||
|
additionalData: additionalData
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Error Response
|
||||||
|
const error = {
|
||||||
|
response: {
|
||||||
|
status: 500,
|
||||||
|
data: {
|
||||||
|
message: 'Error',
|
||||||
|
additionalData: additionalData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error interceptor on Axios returns a different object, so we need to mimic that.
|
||||||
|
if (isError) {
|
||||||
|
axios.mockRejectedValue(error);
|
||||||
|
} else {
|
||||||
|
axios.mockResolvedValue(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
endpoint: endpoint
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/helpers/unitTestHelper.js
Normal file
26
src/helpers/unitTestHelper.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { storeActions } from "@/constants/storeActions";
|
||||||
|
|
||||||
|
export function getMountOptions(mockData) {
|
||||||
|
// Define our mocks to attached to the 'global' object for Vue/Jest.
|
||||||
|
const mocks = {};
|
||||||
|
|
||||||
|
mocks.dispatchNonBlockingStoreAction = jest.fn();
|
||||||
|
mocks.dispatchNonBlockingStoreAction.mockImplementation((actionName) => {
|
||||||
|
|
||||||
|
let actionFilterResult = mockData.actionList.filter(x => x.actionName == actionName);
|
||||||
|
|
||||||
|
if (actionFilterResult.length > 0 && actionFilterResult.length === 1) {
|
||||||
|
|
||||||
|
return Promise.resolve({
|
||||||
|
data: actionFilterResult[0].data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Mock store actions from js file
|
||||||
|
mocks.storeActions = storeActions;
|
||||||
|
const global = {
|
||||||
|
mocks: mocks
|
||||||
|
};
|
||||||
|
|
||||||
|
return { global }
|
||||||
|
}
|
||||||
|
|
@ -1,55 +1,110 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container-fluid container-shadow p-2 rounded-3">
|
<div class="container-fluid container-shadow p-2 rounded-3">
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4 class="m-0 p-2 bg-light rounded">Radio Card</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row g-2">
|
<div class="row g-2">
|
||||||
<radioCard
|
<radioCard
|
||||||
radioLabel="Windshield"
|
radioLabel="Windshield"
|
||||||
radioImage="windshield-damage.svg"
|
radioImage="windshield-damage.svg"
|
||||||
altText="Windshield"
|
altText="Windshield"
|
||||||
groupName="damageKey"
|
groupName="damageKey"
|
||||||
radioID="windshield"
|
radioID="windshield"
|
||||||
/>
|
/>
|
||||||
<radioCard
|
<radioCard
|
||||||
radioLabel="Side Window"
|
radioLabel="Side Window"
|
||||||
radioImage="side-window-damage.svg"
|
radioImage="side-window-damage.svg"
|
||||||
altText="Side Window"
|
altText="Side Window"
|
||||||
groupName="damageKey"
|
groupName="damageKey"
|
||||||
radioID="sidewindow"
|
radioID="sidewindow"
|
||||||
/>
|
/>
|
||||||
<radioCard
|
<radioCard
|
||||||
radioLabel="Back Glass"
|
radioLabel="Back Glass"
|
||||||
radioImage="back-glass-damage.svg"
|
radioImage="back-glass-damage.svg"
|
||||||
altText="Back Glass"
|
altText="Back Glass"
|
||||||
groupName="damageKey"
|
groupName="damageKey"
|
||||||
radioID="backglass"
|
radioID="backglass"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4 class="m-0 p-2 bg-light rounded">Buttons</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col my-3 d-flex align-items-center">
|
<div class="col my-3 d-flex align-items-center">
|
||||||
<buttonPrimary
|
<buttonPrimary
|
||||||
buttonText="Primary"
|
buttonText="Primary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col my-3 d-flex align-items-center">
|
<div class="col my-3 d-flex align-items-center">
|
||||||
<buttonSecondary
|
<buttonSecondary
|
||||||
buttonText="Secondary"
|
buttonText="Secondary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4 class="m-0 p-2 bg-light rounded">List Button</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col my-3 d-flex align-items-center">
|
<div class="col my-3 d-flex align-items-center">
|
||||||
<listButton
|
<listButton
|
||||||
buttonText="List Button"
|
buttonText="List Button"
|
||||||
errorText="Test error message"
|
errorText="Test error message"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4 class="m-0 p-2 bg-light rounded">Radio Button Group</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<!-- The role="radiogroup" and aria-labelledby must be included in the parent component for the radio group -->
|
||||||
|
<div role="radiogroup" aria-labelledby="select-year-radio-group" class="col my-3 d-flex align-items-center flex-column">
|
||||||
|
<!-- The h3 and id must be included. The id must match the aria-labelledby of the parent div. -->
|
||||||
|
<h3 class="visually-hidden" id="select-year-radio-group">Select Vehicle Year</h3>
|
||||||
|
<radioList
|
||||||
|
groupName="demo"
|
||||||
|
ariaLabelBy="vehicle-year"
|
||||||
|
radioID="2021"
|
||||||
|
errorMessage="Test error message"
|
||||||
|
/>
|
||||||
|
<radioList
|
||||||
|
groupName="demo"
|
||||||
|
ariaLabelBy="vehicle-year"
|
||||||
|
radioID="2020"
|
||||||
|
errorMessage="Test error message"
|
||||||
|
/>
|
||||||
|
<radioList
|
||||||
|
groupName="demo"
|
||||||
|
ariaLabelBy="vehicle-year"
|
||||||
|
radioID="2019"
|
||||||
|
errorMessage="Test error message"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4 class="m-0 p-2 bg-light rounded">Text Link</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col my-3 d-flex align-items-center">
|
<div class="col my-3 d-flex align-items-center">
|
||||||
<a href="#">Text Link</a>
|
<a href="#">Text Link</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4 class="m-0 p-2 bg-light rounded">Typogrophy</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row my-2">
|
<div class="row my-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<p>This is default body copy font size/weight</p>
|
<p>This is default body copy font size/weight</p>
|
||||||
|
|
@ -57,6 +112,11 @@
|
||||||
<p><small>This is also small using <code><small></code> tag</small></p>
|
<p><small>This is also small using <code><small></code> tag</small></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4 class="m-0 p-2 bg-light rounded">Headings</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row my-2">
|
<div class="row my-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h1>h1 Heading</h1>
|
<h1>h1 Heading</h1>
|
||||||
|
|
@ -98,6 +158,71 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row my-4">
|
||||||
|
<div class="col">
|
||||||
|
<h4 class="m-0 p-2 bg-light rounded">Alerts</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row my-2">
|
||||||
|
<div class="col">
|
||||||
|
<alert
|
||||||
|
alertClass="alert-success"
|
||||||
|
alertHeadline="Dismissible Alert"
|
||||||
|
alertCopy="This is an example of a DISMISSIBLE alert. It will fade away and content around it will shift when dismissed."
|
||||||
|
v-bind:isDismissible = "true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row my-2">
|
||||||
|
<div class="col">
|
||||||
|
<alert
|
||||||
|
alertClass="alert-danger"
|
||||||
|
alertHeadline="NON-Dismissible Alert"
|
||||||
|
alertCopy="This is an example of a NON-DISMISSIBLE alert."
|
||||||
|
v-bind:isDismissible = "false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row my-2">
|
||||||
|
<div class="col">
|
||||||
|
<alert
|
||||||
|
alertClass="alert-warning"
|
||||||
|
alertHeadline="Warning Alert"
|
||||||
|
alertCopy="This is an example of a WARNING alert."
|
||||||
|
v-bind:isDismissible = "false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row my-2">
|
||||||
|
<div class="col">
|
||||||
|
<alert
|
||||||
|
alertClass="alert-info"
|
||||||
|
alertHeadline="Info Alert"
|
||||||
|
alertCopy="This is an example of a INFO alert."
|
||||||
|
v-bind:isDismissible = "false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row my-2">
|
||||||
|
<div class="col">
|
||||||
|
<alert
|
||||||
|
alertClass="alert-danger"
|
||||||
|
alertHeadline="Danger Alert"
|
||||||
|
alertCopy="This is an example of a DANGER alert."
|
||||||
|
v-bind:isDismissible = "false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row my-2">
|
||||||
|
<div class="col">
|
||||||
|
<alert
|
||||||
|
alertClass="alert-success"
|
||||||
|
alertHeadline="No Body Copy Alert"
|
||||||
|
alertCopy=""
|
||||||
|
v-bind:isDismissible = "false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -107,6 +232,8 @@ import buttonSecondary from "@/uxComponents/buttonSecondary/buttonSecondary";
|
||||||
import radioCard from "@/uxComponents/radioCard/radioCard";
|
import radioCard from "@/uxComponents/radioCard/radioCard";
|
||||||
import listButton from "@/uxComponents/listButton/listButton";
|
import listButton from "@/uxComponents/listButton/listButton";
|
||||||
import vehicleBanner from "@/commonComponents/vehicleBanner/vehicleBanner";
|
import vehicleBanner from "@/commonComponents/vehicleBanner/vehicleBanner";
|
||||||
|
import radioList from "@/uxComponents/radioList/radioList";
|
||||||
|
import alert from "@/uxComponents/alert/alert";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
|
|
@ -115,7 +242,14 @@ export default {
|
||||||
buttonSecondary,
|
buttonSecondary,
|
||||||
radioCard,
|
radioCard,
|
||||||
listButton,
|
listButton,
|
||||||
vehicleBanner
|
vehicleBanner,
|
||||||
|
radioList,
|
||||||
|
alert
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
years: [2023, 2022, 2021, 2020],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<baseTemplate
|
|
||||||
:currentCarInfo="year + ' ' + make + ' ' + model"
|
|
||||||
neededCarInfo="What is your damage?"
|
|
||||||
>
|
|
||||||
<div class="damage-section text-center">
|
|
||||||
<div class="choose-damage row">
|
|
||||||
<div class="col">
|
|
||||||
<radioCard />
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<radioCard />
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<radioCard />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<transition name="fade">
|
|
||||||
<div v-if="damage" class="how-bad mt-3">
|
|
||||||
<span class="text-center fs-6 fw-bold">How bad is it?</span>
|
|
||||||
<div class="choose-how-bad row mt-2">
|
|
||||||
<div class="col">
|
|
||||||
<radioCard />
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<radioCard />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
<div class="next-action row">
|
|
||||||
<div class="col">
|
|
||||||
<div v-on:click="goBack" class="change">
|
|
||||||
<span>Change Vehicle</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</baseTemplate>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
|
||||||
import radioCard from "@/uxComponents/radioCard/radioCard";
|
|
||||||
import { mapState } from "vuex";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "SelectCar",
|
|
||||||
computed: {
|
|
||||||
...mapState(["year", "make", "model"]),
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
damage: "",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
chooseDamage(damage) {
|
|
||||||
this.damage = damage;
|
|
||||||
console.log(this.damage);
|
|
||||||
},
|
|
||||||
goBack() {
|
|
||||||
this.$store.state.slideTransition = "slide_reverse";
|
|
||||||
this.$store.commit("removeStyle");
|
|
||||||
this.$router.push(
|
|
||||||
`/select-style?year=${this.$store.state.year}&make=${this.$store.state.make}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
baseTemplate,
|
|
||||||
radioCard,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,14 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="select-car overflow-hidden">
|
||||||
<baseTemplate :currentCarInfo="year" neededCarInfo="What make is your vehicle?" :backFunction="goBack">
|
<div class="select-car-form rounded text-center">
|
||||||
<carAttributes :attritbutes="makes" :selectAttribute="selectMake" />
|
<Header
|
||||||
</baseTemplate>
|
:text="year"
|
||||||
</div>
|
/>
|
||||||
|
<radioQuestion
|
||||||
|
questionText="What is the make of your vehicle?"
|
||||||
|
:answers="makes"
|
||||||
|
:chooseAnswer="selectMake"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
import radioQuestion from "@/commonComponents/radioQuestion/radioQuestion";
|
||||||
import carAttributes from "@/commonComponents/carAttributes/carAttributes";
|
import Header from "@/uxComponents/header/header";
|
||||||
|
import store from "@/store";
|
||||||
|
import router from "@/router";
|
||||||
import {
|
import {
|
||||||
mapState
|
mapState
|
||||||
} from "vuex";
|
} from "vuex";
|
||||||
|
|
@ -20,7 +29,11 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
selectMake(make) {
|
selectMake(make) {
|
||||||
this.$store.dispatch("selectMake", make);
|
this.dispatchNonBlockingStoreAction("selectMake", { make: make }).then( (response) => {
|
||||||
|
const models = response;
|
||||||
|
store.commit('updateMake', {make, models});
|
||||||
|
router.push(`/select-model?year=${store.year}&make=${make}`);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
goBack() {
|
goBack() {
|
||||||
this.$store.state.slideTransition = "slide_reverse";
|
this.$store.state.slideTransition = "slide_reverse";
|
||||||
|
|
@ -28,8 +41,8 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
baseTemplate,
|
radioQuestion,
|
||||||
carAttributes,
|
Header,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="select-car overflow-hidden">
|
||||||
<baseTemplate
|
<div class="select-car-form rounded text-center">
|
||||||
:currentCarInfo="year + ' ' + make"
|
<Header
|
||||||
:neededCarInfo="'What is the model of your ' + make + '?'"
|
:text="year + ' ' + make"
|
||||||
:backFunction="goBack"
|
/>
|
||||||
>
|
<radioQuestion
|
||||||
<carAttributes :attritbutes="models" :selectAttribute="selectModel" />
|
:questionText="'What is the model of your ' + make + '?'"
|
||||||
</baseTemplate>
|
:answers="models"
|
||||||
|
:chooseAnswer="selectModel"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
import radioQuestion from "@/commonComponents/radioQuestion/radioQuestion";
|
||||||
import carAttributes from "@/commonComponents/carAttributes/carAttributes";
|
import Header from "@/uxComponents/header/header";
|
||||||
|
import store from "@/store";
|
||||||
|
import router from "@/router";
|
||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -22,16 +27,20 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
selectModel(model) {
|
selectModel(model) {
|
||||||
this.$store.dispatch("selectModel", model);
|
this.dispatchNonBlockingStoreAction("selectModel", { model: model }).then( (response) => {
|
||||||
|
const styles = response;
|
||||||
|
store.commit("updateModel", { model, styles });
|
||||||
|
router.push(`/select-style?year=${store.year}&make=${store.make}&model=${model}`);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
goBack() {
|
goBack() {
|
||||||
this.$store.state.slideTransition = "slide_reverse";
|
this.$store.state.slideTransition = "slide_reverse";
|
||||||
this.$router.push(`/select-make?year=${this.$store.state.year}`);
|
this.$router.push(`/select-make?year=${store.year}`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
baseTemplate,
|
radioQuestion,
|
||||||
carAttributes,
|
Header,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="select-car overflow-hidden">
|
||||||
<baseTemplate
|
<div class="select-car-form rounded text-center">
|
||||||
:currentCarInfo="year + ' ' + make + ' ' + model"
|
<Header
|
||||||
:neededCarInfo="'What style is your ' + model + '?'"
|
:text="year + ' ' + make + ' ' + model"
|
||||||
:backFunction="goBack"
|
/>
|
||||||
>
|
<radioQuestion
|
||||||
<carAttributes :attritbutes="styles" :selectAttribute="selectStyle" />
|
:questionText="'What style is your ' + model + '?'"
|
||||||
</baseTemplate>
|
:answers="styles"
|
||||||
|
:chooseAnswer="selectStyle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
import radioQuestion from "@/commonComponents/radioQuestion/radioQuestion";
|
||||||
import carAttributes from "@/commonComponents/carAttributes/carAttributes";
|
import Header from "@/uxComponents/header/header";
|
||||||
|
import store from "@/store";
|
||||||
|
import router from "@/router";
|
||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -22,18 +27,21 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
selectStyle(style) {
|
selectStyle(style) {
|
||||||
this.$store.dispatch("selectStyle", style);
|
store.commit("updateStyle", { style });
|
||||||
|
router.push(
|
||||||
|
`/select-damage?year=${store.year}&make=${store.make}&model=${store.model}&style=${style}`
|
||||||
|
);
|
||||||
},
|
},
|
||||||
goBack() {
|
goBack() {
|
||||||
this.$store.state.slideTransition = "slide_reverse";
|
this.$store.state.slideTransition = "slide_reverse";
|
||||||
this.$router.push(
|
this.$router.push(
|
||||||
`/select-model?year=${this.$store.state.year}&make=${this.$store.state.make}`
|
`/select-model?year=${store.year}&make=${store.make}`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
baseTemplate,
|
radioQuestion,
|
||||||
carAttributes,
|
Header,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1 +1,55 @@
|
||||||
test.todo('some test to be written in the future');
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import { nextTick } from 'vue'
|
||||||
|
import { getMountOptions } from '@/helpers/unitTestHelper.js';
|
||||||
|
import { storeActions } from '@/constants/storeActions.js'
|
||||||
|
import selectYear from './selectYear.vue';
|
||||||
|
|
||||||
|
describe('selectYear.vue', () => {
|
||||||
|
test("Should render the 'pageHeader.Text' data value 'text' prop value for the Header component, 'radioQuestion.Question' data value as 'questionText' prop value for the 'radioQuestion' component and 'years' values for 'answers' prop values for the 'radioQuestion' component.", async () => {
|
||||||
|
|
||||||
|
// Arrange
|
||||||
|
const mockDataAndAction = {
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.GET_PAGE_DATA,
|
||||||
|
data: {
|
||||||
|
"Result": [
|
||||||
|
{
|
||||||
|
Type: "PageHeadingWidget",
|
||||||
|
Model: {
|
||||||
|
Text: "Mock Data"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "RadioQuestionWidget",
|
||||||
|
Model: {
|
||||||
|
Question: "Mock Data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionName: storeActions.GET_YEARS,
|
||||||
|
data: ['2023', '2022', '2021']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const mountOptions = getMountOptions(mockDataAndAction);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const wrapper = shallowMount(selectYear, mountOptions);
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const header = await wrapper.find('.Header');
|
||||||
|
expect(header.attributes('text')).toEqual("Mock Data");
|
||||||
|
|
||||||
|
const radioQuestion = await wrapper.findComponent('.radioQuestion');
|
||||||
|
expect(radioQuestion.attributes('answers')).toEqual('2023,2022,2021');
|
||||||
|
expect(radioQuestion.attributes('questiontext')).toEqual("Mock Data");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
@ -1,60 +1,78 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="select-car">
|
||||||
<baseTemplate :currentCarInfo="pageHeader.Text" :neededCarInfo="radioQuestion.Question">
|
<div class="select-car-form rounded text-center">
|
||||||
<carAttributes :attritbutes="years" :selectAttribute="selectYear" />
|
|
||||||
</baseTemplate>
|
<Header
|
||||||
</div>
|
:text="pageHeader.Text" class="Header"
|
||||||
|
/>
|
||||||
|
<radioQuestion
|
||||||
|
class="radioQuestion"
|
||||||
|
:questionText="radioQuestion.Question"
|
||||||
|
:answers="this.years"
|
||||||
|
:chooseAnswer="selectYear"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import baseTemplate from "@/commonComponents/baseTemplate/baseTemplate";
|
import radioQuestion from "@/commonComponents/radioQuestion/radioQuestion";
|
||||||
import carAttributes from "@/commonComponents/carAttributes/carAttributes";
|
import Header from "@/uxComponents/header/header";
|
||||||
import axios from "axios";
|
import store from "@/store";
|
||||||
|
import router from "@/router";
|
||||||
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SelectCar",
|
name: "SelectYear",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
years: [],
|
years: [],
|
||||||
pageHeader: {},
|
pageHeader: {},
|
||||||
radioQuestion: {}
|
radioQuestion: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
computed: {
|
||||||
axios.get("https://mockey.qa.sagaws.net/service/years").then((response) => {
|
...mapState(["slideTransition", "carImg", "blurImg", "style"]),
|
||||||
this.years = response.data.Result;
|
},
|
||||||
});
|
mounted() {
|
||||||
|
// Mocking Sitefinity data to (For Page Header and Radio Question)
|
||||||
|
this.dispatchNonBlockingStoreAction(this.storeActions.GET_PAGE_DATA, {relativeUrl: 'https://mockey.qa.sagaws.net/service/content/selectYear'})
|
||||||
|
.then( (response) => {
|
||||||
|
response.data.Result.forEach((m) => {
|
||||||
|
switch (m.Type) {
|
||||||
|
case 'PageHeadingWidget': {
|
||||||
|
this.pageHeader = m.Model;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'RadioQuestionWidget': {
|
||||||
|
this.radioQuestion = m.Model;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
// Sample Call to Mockey to represent real data being sent back from the API, and how the modles are supposed to
|
// Getting Years list
|
||||||
// be prosessed and passed to child components.
|
this.dispatchNonBlockingStoreAction(this.storeActions.GET_YEARS)
|
||||||
axios.get("https://mockey.qa.sagaws.net/service/content/selectYear").then((response) => {
|
.then( (response) => {
|
||||||
|
this.years = response.data;
|
||||||
response.data.Result.forEach((m) => {
|
});
|
||||||
switch (m.Type) {
|
},
|
||||||
case this.widgetNames.PAGE_HEADING_WIDGET: {
|
methods: {
|
||||||
this.pageHeader = m.Model;
|
selectYear(year) {
|
||||||
break;
|
this.dispatchNonBlockingStoreAction("selectYear", { year: year }).then( (response) => {
|
||||||
}
|
const makes = response;
|
||||||
case this.widgetNames.RADIO_QUESTION_WIDGET: {
|
store.commit('updateYear', {year, makes});
|
||||||
this.radioQuestion = m.Model;
|
router.push(`select-make?year=${year}`);
|
||||||
break;
|
});
|
||||||
}
|
}
|
||||||
default: {
|
},
|
||||||
break;
|
components: {
|
||||||
}
|
radioQuestion,
|
||||||
}
|
Header,
|
||||||
})
|
},
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
selectYear(year) {
|
|
||||||
this.$store.dispatch("selectYear", year);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
baseTemplate,
|
|
||||||
carAttributes,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
import { createStore } from "vuex";
|
import { createStore } from "vuex";
|
||||||
import { endpoints } from "@/constants/endpoints.js";
|
import { endpoints } from "@/constants/endpoints.js";
|
||||||
import createPersistedState from "vuex-persistedstate";
|
import createPersistedState from "vuex-persistedstate";
|
||||||
import axios from "axios";
|
|
||||||
import globalMethods from "@/global-methods";
|
import globalMethods from "@/global-methods";
|
||||||
import router from "@/router";
|
|
||||||
|
|
||||||
export default createStore({
|
export default createStore({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|
@ -27,17 +25,17 @@ export default createStore({
|
||||||
mutations: {
|
mutations: {
|
||||||
updateYear(state, data) {
|
updateYear(state, data) {
|
||||||
state.year = data.year;
|
state.year = data.year;
|
||||||
state.makes = data.makes;
|
state.makes = data.makes.data;
|
||||||
state.slideTransition = "slide";
|
state.slideTransition = "slide";
|
||||||
},
|
},
|
||||||
updateMake(state, data) {
|
updateMake(state, data) {
|
||||||
state.make = data.make;
|
state.make = data.make;
|
||||||
state.models = data.models.data.Result;
|
state.models = data.models.data;
|
||||||
state.slideTransition = "slide";
|
state.slideTransition = "slide";
|
||||||
},
|
},
|
||||||
updateModel(state, data) {
|
updateModel(state, data) {
|
||||||
state.model = data.model;
|
state.model = data.model;
|
||||||
state.styles = data.styles.data.Result;
|
state.styles = data.styles.data;
|
||||||
state.slideTransition = "slide";
|
state.slideTransition = "slide";
|
||||||
},
|
},
|
||||||
updateStyle(state, data) {
|
updateStyle(state, data) {
|
||||||
|
|
@ -55,50 +53,60 @@ export default createStore({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async selectYear(context, year) {
|
getYears(){
|
||||||
let makes = [];
|
return globalMethods.callHttpClient({
|
||||||
await globalMethods
|
method: endpoints.GetYears.method,
|
||||||
.callHttpClient({
|
endpoint: endpoints.GetYears.url,
|
||||||
method: "GET",
|
payload:{}
|
||||||
endpoint: `https://mockey.qa.sagaws.net/service/makes/year=${year}`,
|
|
||||||
payload: {},
|
|
||||||
})
|
|
||||||
.then(function (response) {
|
|
||||||
makes = response.data.Result;
|
|
||||||
});
|
});
|
||||||
context.commit("updateYear", { year, makes });
|
},
|
||||||
router.push(`/select-make?year=${year}`);
|
selectYear(context, { year }) {
|
||||||
},
|
return globalMethods.callHttpClient({
|
||||||
async selectMake({ commit, state }, make) {
|
method: endpoints.GetMakes.method,
|
||||||
const models = await axios.get(
|
endpoint: endpoints.GetMakes.url,
|
||||||
`https://mockey.qa.sagaws.net/service/models/year=${state.year}/make=${make}`
|
payload:{
|
||||||
);
|
"Year": year
|
||||||
commit("updateMake", { make, models });
|
}
|
||||||
router.push(`/select-model?year=${state.year}&make=${make}`);
|
});
|
||||||
},
|
},
|
||||||
async selectModel({ commit, state }, model) {
|
selectMake({ commit, state }, { make }) {
|
||||||
const styles = await axios.get(
|
return globalMethods.callHttpClient({
|
||||||
`https://mockey.qa.sagaws.net/service/styles/year=${state.year}/make=${state.make}/model=${model}`
|
method: endpoints.GetModels.method,
|
||||||
);
|
endpoint: endpoints.GetModels.url,
|
||||||
commit("updateModel", { model, styles });
|
payload:{
|
||||||
router.push(
|
"Year": state.year,
|
||||||
`/select-style?year=${state.year}&make=${state.make}&model=${model}`
|
"Make": make
|
||||||
);
|
}
|
||||||
},
|
});
|
||||||
selectStyle({ commit, state }, style) {
|
},
|
||||||
commit("updateStyle", { style });
|
selectModel({ commit, state }, { model }) {
|
||||||
router.push(
|
return globalMethods.callHttpClient({
|
||||||
`/damage?year=${state.year}&make=${state.make}&model=${state.model}&style=${style}`
|
method: endpoints.GetStyles.method,
|
||||||
);
|
endpoint: endpoints.GetStyles.url,
|
||||||
},
|
payload:{
|
||||||
getRouteInfo(context, { pageName }) {
|
"Year": state.year,
|
||||||
return globalMethods.callHttpClient({
|
"Make": state.make,
|
||||||
method: endpoints.GetRouteInfoEndpoint.method,
|
"Model": model
|
||||||
endpoint: endpoints.GetRouteInfoEndpoint.url,
|
}
|
||||||
payload: {
|
});
|
||||||
pageName: pageName,
|
},
|
||||||
},
|
getRouteInfo(context, { relativeUrl }) {
|
||||||
});
|
return globalMethods.callHttpClient({
|
||||||
},
|
method: endpoints.GetRouteInfoEndpoint.method,
|
||||||
|
endpoint: endpoints.GetRouteInfoEndpoint.url,
|
||||||
|
payload: {
|
||||||
|
relativeUrl: relativeUrl,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// For mock data purposes only
|
||||||
|
getMockPageData(context, { relativeUrl }) {
|
||||||
|
return globalMethods.callMockHttpClient({
|
||||||
|
method: endpoints.GetPageData.method,
|
||||||
|
endpoint: relativeUrl,
|
||||||
|
payload: {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,61 +1,41 @@
|
||||||
.vehicle-select-attributes {
|
.select-car {
|
||||||
height: 100vh;
|
height: calc(100vh - 1rem);
|
||||||
|
|
||||||
.select-car-form {
|
.car_list {
|
||||||
background: $white;
|
// Height will be determined by overall height of content above list
|
||||||
height: 100%;
|
height: calc(100% - 100px);
|
||||||
|
width: calc(100% - 1rem);
|
||||||
form {
|
|
||||||
height: calc(100% - 230px);
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.car_list, .current_car_info-text, .needed_car_info-text {
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
transition: transform .3s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.current_car_info {
|
|
||||||
position: relative;
|
|
||||||
min-height: 2.5rem;
|
|
||||||
|
|
||||||
.current_car_info-text {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Animations
|
||||||
.slide-enter-from {
|
.slide-enter-from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(30vw);
|
transform: translateX(30vw);
|
||||||
}
|
}
|
||||||
.slide-enter-active, .slide-leave-active {
|
.slide-enter-active, .slide-leave-active {
|
||||||
transition: all .4s;
|
transition: all .4s;
|
||||||
}
|
}
|
||||||
.slide-leave-to {
|
.slide-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-30vw);
|
transform: translateX(-30vw);
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide_reverse-enter-from {
|
.slide_reverse-enter-from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-30vw);
|
transform: translateX(-30vw);
|
||||||
}
|
}
|
||||||
.slide_reverse-enter-active, .slide_reverse-leave-active {
|
.slide_reverse-enter-active, .slide_reverse-leave-active {
|
||||||
transition: all .4s;
|
transition: all .4s;
|
||||||
}
|
}
|
||||||
.slide_reverse-leave-to {
|
.slide_reverse-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(30vw);
|
transform: translateX(30vw);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter-from, .fade-leave-to {
|
.fade-enter-from, .fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
.fade-enter-active, .fade-leave-active {
|
.fade-enter-active, .fade-leave-active {
|
||||||
transition: all .5s ease;
|
transition: all .5s ease;
|
||||||
}
|
}
|
||||||
59
src/styles/commonRadioStyles.scss
Normal file
59
src/styles/commonRadioStyles.scss
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
.radiogroup {
|
||||||
|
&.radio-list-button {
|
||||||
|
input[type="radio"] {
|
||||||
|
opacity: 0;
|
||||||
|
position: fixed;
|
||||||
|
width: 0;
|
||||||
|
&:focus-visible + label {
|
||||||
|
box-shadow: 0 0 0 2px $blue;
|
||||||
|
}
|
||||||
|
&:focus + label {
|
||||||
|
box-shadow: 0 0 0 2px $blue;
|
||||||
|
}
|
||||||
|
&:checked + label {
|
||||||
|
background: $blue-100;
|
||||||
|
box-shadow: 0 0 0 1px $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
position: relative;
|
||||||
|
background: $white;
|
||||||
|
height: 3rem;
|
||||||
|
transition: all 150ms linear;
|
||||||
|
border-radius: $border-radius-lg;
|
||||||
|
border: 1px solid $gray-500;
|
||||||
|
width: 100%;
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 0 4px $blue-100;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
+ p {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.error {
|
||||||
|
border: 1px solid $danger;
|
||||||
|
+ p {
|
||||||
|
display: flex;
|
||||||
|
color: $danger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.button-loader {
|
||||||
|
padding: 0 40px 0 12px;
|
||||||
|
&:after {
|
||||||
|
content: url(../../assets/img/icons/button-spinner-blue.svg);
|
||||||
|
position: absolute;
|
||||||
|
right: 14px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-left: 12px;
|
||||||
|
animation: rotation 1s infinite linear;
|
||||||
|
@keyframes rotation {
|
||||||
|
100% {
|
||||||
|
transform:rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -163,3 +163,8 @@ $box-shadow: 0 .5rem 1rem rgba($black, .15);
|
||||||
$box-shadow-sm: 0 .125rem .25rem rgba($black, .075);
|
$box-shadow-sm: 0 .125rem .25rem rgba($black, .075);
|
||||||
$box-shadow-lg: 0 1rem 3rem rgba($black, .25);//Safelite default
|
$box-shadow-lg: 0 1rem 3rem rgba($black, .25);//Safelite default
|
||||||
$box-shadow-inset: inset 0 1px 2px rgba($black, .075);
|
$box-shadow-inset: inset 0 1px 2px rgba($black, .075);
|
||||||
|
|
||||||
|
//Alerts
|
||||||
|
$alert-bg-scale: -90%;
|
||||||
|
$alert-border-scale: -100%;
|
||||||
|
$alert-color-scale: 40%;
|
||||||
|
|
|
||||||
81
src/uxComponents/alert/alert.vue
Normal file
81
src/uxComponents/alert/alert.vue
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
<template>
|
||||||
|
<div class="alert fade show text-center mb-0" role="alert"
|
||||||
|
:class="[ isDismissible ? 'alert-dismissible' : '', this.alertClass ]"
|
||||||
|
>
|
||||||
|
<p class="m-0 fw-bold alert-heading">{{alertHeadline}}</p>
|
||||||
|
<p class="m-0 text-body">{{alertCopy}}</p>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.7 23.7" xml:space="preserve">
|
||||||
|
<path d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "alert",
|
||||||
|
props: {
|
||||||
|
alertHeadline: String,
|
||||||
|
alertCopy: String,
|
||||||
|
isDismissible: Boolean,
|
||||||
|
/*
|
||||||
|
alertClass class names:
|
||||||
|
alert-sucess (green)
|
||||||
|
alert-danger (red)
|
||||||
|
alert-warning (yellow)
|
||||||
|
alert-info (blue)
|
||||||
|
*/
|
||||||
|
alertClass: String
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.alert {
|
||||||
|
button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.btn-close {
|
||||||
|
background: none;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
&.alert-dismissible {
|
||||||
|
button {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.alert-info {
|
||||||
|
.alert-heading {
|
||||||
|
color: $blue-700;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
fill: $blue-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.alert-danger {
|
||||||
|
.alert-heading {
|
||||||
|
color: $red-700;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
fill: $red-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.alert-warning {
|
||||||
|
.alert-heading {
|
||||||
|
color: $yellow-700;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
fill: $yellow-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.alert-success {
|
||||||
|
.alert-heading {
|
||||||
|
color: $green-700;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
fill: $green-700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -14,12 +14,12 @@
|
||||||
export default {
|
export default {
|
||||||
name: "buttonPrimary",
|
name: "buttonPrimary",
|
||||||
props: {
|
props: {
|
||||||
buttonText: String
|
buttonText: String,
|
||||||
|
isDisabled: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false
|
||||||
isDisabled: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
16
src/uxComponents/header/header.spec.js
Normal file
16
src/uxComponents/header/header.spec.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import Header from './header';
|
||||||
|
|
||||||
|
describe('Header.vue', () => {
|
||||||
|
it("Should render the 'text' prop value as a span value for the header span text value.", () => {
|
||||||
|
// Act
|
||||||
|
const wrapper = shallowMount(Header, {
|
||||||
|
propsData: {
|
||||||
|
text: 'Header Content'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.find('span').text()).toContain("Header Content");
|
||||||
|
})
|
||||||
|
});
|
||||||
16
src/uxComponents/header/header.vue
Normal file
16
src/uxComponents/header/header.vue
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<template>
|
||||||
|
<div class="current_car_info-text">
|
||||||
|
<div class="d-flex align-items-center justify-content-center">
|
||||||
|
<span class="text-center text-dark fs-5 d-block">{{ text }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Header",
|
||||||
|
props: {
|
||||||
|
text: String
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
23
src/uxComponents/radio/radio.spec.js
Normal file
23
src/uxComponents/radio/radio.spec.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import radio from './radio';
|
||||||
|
|
||||||
|
describe('radio.vue', () => {
|
||||||
|
it("Should render the 'text' prop value as a span value for the radio button label and add the 'value' prop value as the radio button value and id.", () => {
|
||||||
|
// Act
|
||||||
|
const wrapper = shallowMount(radio, {
|
||||||
|
propsData: {
|
||||||
|
value: '2023',
|
||||||
|
text: '12'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.find('span').text()).toEqual('12');
|
||||||
|
expect(wrapper.find('input').attributes()).toEqual({
|
||||||
|
class: 'position-absolute opacity-0',
|
||||||
|
id: '2023',
|
||||||
|
type: 'radio',
|
||||||
|
value: '2023'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
||||||
39
src/uxComponents/radio/radio.vue
Normal file
39
src/uxComponents/radio/radio.vue
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
:id="this.value"
|
||||||
|
:value="this.value"
|
||||||
|
class="position-absolute opacity-0"
|
||||||
|
v-on:click="showLoader()"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
:for="this.value"
|
||||||
|
class="btn list-button d-flex align-items-center"
|
||||||
|
v-bind:class="[this.isLoading ? 'button-loader' : '']"
|
||||||
|
>
|
||||||
|
<span>{{ text }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "radio",
|
||||||
|
props: [
|
||||||
|
"value",
|
||||||
|
"text"
|
||||||
|
],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isLoading: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showLoader() {
|
||||||
|
this.isLoading = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
34
src/uxComponents/radioList/radioList.vue
Normal file
34
src/uxComponents/radioList/radioList.vue
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<div class="radiogroup radio-list-button d-flex flex-column w-100">
|
||||||
|
<input type="radio" v-bind:id="radioID" v-bind:name="groupName" v-bind:value="radioID">
|
||||||
|
<label role="radio" tabindex="0" aria-checked="false" v-bind:for="radioID" class="mb-2 d-flex align-items-center p-2"
|
||||||
|
v-on:click="showLoader()"
|
||||||
|
v-bind:class="[this.isLoading ? 'button-loader' : 'not-loading',this.isError ? 'error' : '']"
|
||||||
|
>{{radioID}}</label>
|
||||||
|
<p class="small">{{errorMessage}}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "radioList",
|
||||||
|
props: [
|
||||||
|
"groupName",
|
||||||
|
"ariaLabelBy",
|
||||||
|
"radioID",
|
||||||
|
"errorMessage"
|
||||||
|
|
||||||
|
],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isLoading: false,
|
||||||
|
isError: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showLoader() {
|
||||||
|
this.isLoading = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -24,6 +24,7 @@ module.exports = {
|
||||||
@import "./node_modules/bootstrap/scss/bootstrap";
|
@import "./node_modules/bootstrap/scss/bootstrap";
|
||||||
@import "@/styles/commonStyles.scss";
|
@import "@/styles/commonStyles.scss";
|
||||||
@import "@/styles/commonButtonStyles.scss";
|
@import "@/styles/commonButtonStyles.scss";
|
||||||
|
@import "@/styles/commonRadioStyles.scss";
|
||||||
@import "@/styles/commonTypographyStyles.scss";
|
@import "@/styles/commonTypographyStyles.scss";
|
||||||
@import "@/styles/commonComponentStyles/ymmsCommonStyles.scss";
|
@import "@/styles/commonComponentStyles/ymmsCommonStyles.scss";
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ module.exports = {
|
||||||
@import "./node_modules/bootstrap/scss/bootstrap";
|
@import "./node_modules/bootstrap/scss/bootstrap";
|
||||||
@import "@/styles/commonStyles.scss";
|
@import "@/styles/commonStyles.scss";
|
||||||
@import "@/styles/commonButtonStyles.scss";
|
@import "@/styles/commonButtonStyles.scss";
|
||||||
|
@import "@/styles/commonRadioStyles.scss";
|
||||||
@import "@/styles/commonTypographyStyles.scss";
|
@import "@/styles/commonTypographyStyles.scss";
|
||||||
@import "@/styles/commonComponentStyles/ymmsCommonStyles.scss";
|
@import "@/styles/commonComponentStyles/ymmsCommonStyles.scss";
|
||||||
`
|
`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue