Merge remote-tracking branch 'origin/develop' into feature/digital/SSR-1063
This commit is contained in:
commit
042dfd848b
13 changed files with 96 additions and 56 deletions
|
|
@ -385,17 +385,10 @@ export default {
|
||||||
{},
|
{},
|
||||||
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
|
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
|
||||||
);
|
);
|
||||||
} else if (useMainStore().issConfig.enableTPAFlow) {
|
|
||||||
this.$router.navigate(
|
|
||||||
navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED,
|
|
||||||
this.$route,
|
|
||||||
{},
|
|
||||||
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.TPANotEnabled());
|
this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback());
|
||||||
this.$router.navigate(
|
this.$router.navigate(
|
||||||
navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED,
|
navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
|
||||||
this.$route,
|
this.$route,
|
||||||
{},
|
{},
|
||||||
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
|
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ export default {
|
||||||
|
|
||||||
span {
|
span {
|
||||||
&.small {
|
&.small {
|
||||||
font-size: 0.75rem;
|
font-size: $font-size-xsm;
|
||||||
color: $gray-550;
|
color: $gray-550;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
|
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||||
import paymentMethodQuestion from '@/layouts/payment-method/payment-method-question/payment-method-question.vue';
|
import paymentMethodQuestion from '@/layouts/payment-method/payment-method-question/payment-method-question.vue';
|
||||||
|
import baseMixin from '@/mixins/base-mixin';
|
||||||
|
|
||||||
let cmsContent;
|
let cmsContent;
|
||||||
|
|
||||||
const mockCmsContent = {
|
const mockCmsContent = {
|
||||||
QuestionText: 'Choose a payment option',
|
[widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT]: 'Choose a payment option',
|
||||||
Answers: [
|
[widgetFields.INPUT_QUESTION_WIDGET.ANSWERS]: [
|
||||||
{
|
{
|
||||||
Name: 'NameA',
|
Name: 'NameA',
|
||||||
Text: 'TextA',
|
Text: 'TextA',
|
||||||
|
|
@ -39,6 +40,7 @@ function setupMocks(customMountOptions) {
|
||||||
|
|
||||||
const mockMixin = {
|
const mockMixin = {
|
||||||
methods: {
|
methods: {
|
||||||
|
...baseMixin.methods,
|
||||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent[cmsFieldName])
|
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent[cmsFieldName])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ export default {
|
||||||
return this.getCmsContent(this.cmsWidgetName, widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT);
|
return this.getCmsContent(this.cmsWidgetName, widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT);
|
||||||
},
|
},
|
||||||
paymentMethodAnswerData() {
|
paymentMethodAnswerData() {
|
||||||
const cmsData = this.getAnswersNullSafe(this.cmsWidgetName);
|
const cmsData = this.getInputQuestionWidgetAnswersNullSafe(this.cmsWidgetName);
|
||||||
|
|
||||||
return cmsData.map((answer) => ({
|
return cmsData.map((answer) => ({
|
||||||
buttonLabel: answer.Text,
|
buttonLabel: answer.Text,
|
||||||
|
|
@ -59,17 +59,6 @@ export default {
|
||||||
buttonImage: answer.AnswerImageUrl
|
buttonImage: answer.AnswerImageUrl
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getAnswersNullSafe(widgetName) {
|
|
||||||
const rawData = this.getCmsContent(widgetName, widgetFields.INPUT_QUESTION_WIDGET.ANSWERS);
|
|
||||||
|
|
||||||
if (!rawData) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return rawData;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -53,14 +53,10 @@ import { useMainStore } from '@/store';
|
||||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||||
import paymentMethods from '@/constants/payment-method-constants';
|
import paymentMethods from '@/constants/payment-method-constants';
|
||||||
import globalRules from '@/constants/global-rules';
|
import globalRules from '@/constants/global-rules';
|
||||||
import { Form, defineRule } from 'vee-validate';
|
import { Form } from 'vee-validate';
|
||||||
|
|
||||||
import { required } from '@/helpers/validation-rules';
|
|
||||||
import errorMessages from '@/constants/error-messages';
|
|
||||||
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
||||||
|
|
||||||
defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED));
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'payment-method',
|
name: 'payment-method',
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -210,9 +206,6 @@ export default {
|
||||||
this.$refs.siteFooter.updateButtonText(newValue);
|
this.$refs.siteFooter.updateButtonText(newValue);
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
// Multiple paths based on payment
|
|
||||||
console.log('forward button hit...');
|
|
||||||
|
|
||||||
await useMainStore().savePaymentMethodChoice(this.paymentMethod);
|
await useMainStore().savePaymentMethodChoice(this.paymentMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { useMainStore } from '@/store';
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js';
|
import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js';
|
||||||
|
import baseMixin from '@/mixins/base-mixin';
|
||||||
|
|
||||||
jest.mock('@/helpers/damage-review-content-generator.js', () => ({
|
jest.mock('@/helpers/damage-review-content-generator.js', () => ({
|
||||||
getDamageDisplayContent: jest.fn(),
|
getDamageDisplayContent: jest.fn(),
|
||||||
|
|
@ -16,6 +17,7 @@ jest.mock('@/helpers/damage-review-content-generator.js', () => ({
|
||||||
let cmsContent;
|
let cmsContent;
|
||||||
const mockMixin = {
|
const mockMixin = {
|
||||||
methods: {
|
methods: {
|
||||||
|
...baseMixin.methods,
|
||||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
|
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -33,20 +33,14 @@ export default {
|
||||||
},
|
},
|
||||||
driverSideDamageAnswers() {
|
driverSideDamageAnswers() {
|
||||||
const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers);
|
const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers);
|
||||||
return this.getAnswersNullSafe(answerContent?.SubWidgetName);
|
return this.getInputQuestionWidgetAnswersNullSafe(answerContent?.SubWidgetName);
|
||||||
},
|
},
|
||||||
passengerSideDamageAnswers() {
|
passengerSideDamageAnswers() {
|
||||||
const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers);
|
const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers);
|
||||||
return this.getAnswersNullSafe(answerContent?.SubWidgetName);
|
return this.getInputQuestionWidgetAnswersNullSafe(answerContent?.SubWidgetName);
|
||||||
},
|
},
|
||||||
locationAnswers() {
|
locationAnswers() {
|
||||||
return this.getAnswersNullSafe(this.damageLocationsWidgetName);
|
return this.getInputQuestionWidgetAnswersNullSafe(this.damageLocationsWidgetName);
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getAnswersNullSafe(widgetName) {
|
|
||||||
const rawAnswers = this.getCmsContent(widgetName, 'Answers');
|
|
||||||
return rawAnswers || [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@
|
||||||
inputId="phoneNumber"
|
inputId="phoneNumber"
|
||||||
:cmsWidgetName="widget.phoneNumberQuestion"
|
:cmsWidgetName="widget.phoneNumberQuestion"
|
||||||
isRequired
|
isRequired
|
||||||
|
mask="###-###-####"
|
||||||
|
disableAutoFill
|
||||||
:validationRules="rules.phoneNumber" />
|
:validationRules="rules.phoneNumber" />
|
||||||
</template>
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import settleAllPromises from '@/helpers/layout-helper.js';
|
||||||
import widgetFields from '@/constants/cms-widget-fields.js';
|
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||||
import { toTitleCase, formatAddress, toDisplayPhoneNumber } from '@/helpers/text-helper.js';
|
import { toTitleCase, formatAddress, toDisplayPhoneNumber } from '@/helpers/text-helper.js';
|
||||||
import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js';
|
import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js';
|
||||||
|
import baseMixin from '@/mixins/base-mixin';
|
||||||
|
|
||||||
// Mock fetchCmsContentForPage
|
// Mock fetchCmsContentForPage
|
||||||
jest.mock('@/helpers/cms-content-helper', () => ({
|
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||||
|
|
@ -35,6 +36,12 @@ jest.mock('@/helpers/damage-review-content-generator.js', () => ({
|
||||||
// Mock our module for promises.
|
// Mock our module for promises.
|
||||||
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
|
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
|
||||||
|
|
||||||
|
const mockMixin = {
|
||||||
|
methods: {
|
||||||
|
...baseMixin.methods
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRunAfterInitializingStore = () => {}) {
|
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRunAfterInitializingStore = () => {}) {
|
||||||
const mountOptions = getMountOptions({
|
const mountOptions = getMountOptions({
|
||||||
router: {
|
router: {
|
||||||
|
|
@ -52,6 +59,7 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
|
||||||
|
|
||||||
mountOptions.global.plugins = [testingPinia];
|
mountOptions.global.plugins = [testingPinia];
|
||||||
mountOptions.data = () => (initialData);
|
mountOptions.data = () => (initialData);
|
||||||
|
mountOptions.mixins = [mockMixin];
|
||||||
|
|
||||||
const apiResponses = { cmsContent: {} };
|
const apiResponses = { cmsContent: {} };
|
||||||
|
|
||||||
|
|
@ -775,14 +783,14 @@ describe('tpa-submit', () => {
|
||||||
[[], []],
|
[[], []],
|
||||||
[undefined, []],
|
[undefined, []],
|
||||||
[null, []]
|
[null, []]
|
||||||
])('getAnswersNullSafe', (rawAnswers, expected) => {
|
])('getInputQuestionWidgetAnswersNullSafe', (rawAnswers, expected) => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const widgetName = 'WidgetName';
|
const widgetName = 'WidgetName';
|
||||||
const { wrapper } = getMountedComponent();
|
const { wrapper } = getMountedComponent();
|
||||||
wrapper.vm.getCmsContent = jest.fn().mockImplementationOnce(() => rawAnswers);
|
wrapper.vm.getCmsContent = jest.fn().mockImplementationOnce(() => rawAnswers);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = wrapper.vm.getAnswersNullSafe(widgetName);
|
const result = wrapper.vm.getInputQuestionWidgetAnswersNullSafe(widgetName);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
|
|
|
||||||
|
|
@ -208,15 +208,15 @@ export default {
|
||||||
return [line];
|
return [line];
|
||||||
},
|
},
|
||||||
locationAnswers() {
|
locationAnswers() {
|
||||||
return this.getAnswersNullSafe(this.widget.damageLocations);
|
return this.getInputQuestionWidgetAnswersNullSafe(this.widget.damageLocations);
|
||||||
},
|
},
|
||||||
driverSideDamageAnswers() {
|
driverSideDamageAnswers() {
|
||||||
const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers);
|
const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers);
|
||||||
return this.getAnswersNullSafe(answerContent?.SubWidgetName);
|
return this.getInputQuestionWidgetAnswersNullSafe(answerContent?.SubWidgetName);
|
||||||
},
|
},
|
||||||
passengerSideDamageAnswers() {
|
passengerSideDamageAnswers() {
|
||||||
const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers);
|
const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers);
|
||||||
return this.getAnswersNullSafe(answerContent?.SubWidgetName);
|
return this.getInputQuestionWidgetAnswersNullSafe(answerContent?.SubWidgetName);
|
||||||
},
|
},
|
||||||
getDamageLines() {
|
getDamageLines() {
|
||||||
const { glassToReplace, isRepair } = useMainStore().order.damage;
|
const { glassToReplace, isRepair } = useMainStore().order.damage;
|
||||||
|
|
@ -285,10 +285,6 @@ export default {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getAnswersNullSafe(widgetName) {
|
|
||||||
const rawAnswers = this.getCmsContent(widgetName, 'Answers');
|
|
||||||
return rawAnswers || [];
|
|
||||||
},
|
|
||||||
openContactDetailsModal() {
|
openContactDetailsModal() {
|
||||||
this.$refs.contactDetailsDrawer.openModal();
|
this.$refs.contactDetailsDrawer.openModal();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import vehicleCategories from '@/constants/vehicle-categories.js';
|
||||||
import queryStrings from '@/constants/query-strings';
|
import queryStrings from '@/constants/query-strings';
|
||||||
import dynamicStrings from '@/constants/dynamic-strings';
|
import dynamicStrings from '@/constants/dynamic-strings';
|
||||||
import routerParams from '@/router/router-constants/router-params';
|
import routerParams from '@/router/router-constants/router-params';
|
||||||
|
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -19,6 +20,10 @@ export default {
|
||||||
getCmsContent(widgetName, fieldName) {
|
getCmsContent(widgetName, fieldName) {
|
||||||
return this.$root.cmsContentByWidget?.[widgetName]?.[fieldName] ? this.$root.cmsContentByWidget[widgetName][fieldName] : '';
|
return this.$root.cmsContentByWidget?.[widgetName]?.[fieldName] ? this.$root.cmsContentByWidget[widgetName][fieldName] : '';
|
||||||
},
|
},
|
||||||
|
getInputQuestionWidgetAnswersNullSafe(widgetName) {
|
||||||
|
const rawAnswers = this.getCmsContent(widgetName, widgetFields.INPUT_QUESTION_WIDGET.ANSWERS);
|
||||||
|
return rawAnswers || [];
|
||||||
|
},
|
||||||
getFooterInfoBoxHeight() {
|
getFooterInfoBoxHeight() {
|
||||||
const footerInfoBox = document.querySelector('.footer#infoBox');
|
const footerInfoBox = document.querySelector('.footer#infoBox');
|
||||||
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
|
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import baseMixin from '@/mixins/base-mixin';
|
import baseMixin from '@/mixins/base-mixin';
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||||
|
|
||||||
describe('base-mixin', () => {
|
describe('base-mixin', () => {
|
||||||
it('should set and get cms content', () => {
|
it('should set and get cms content', () => {
|
||||||
|
|
@ -20,4 +21,63 @@ describe('base-mixin', () => {
|
||||||
const localThis = { cmsWidgetName: 'testWidget' };
|
const localThis = { cmsWidgetName: 'testWidget' };
|
||||||
expect(baseMixin.computed.cssClassNameForCmsWidget.call(localThis)).toBe('widget-name-testWidget');
|
expect(baseMixin.computed.cssClassNameForCmsWidget.call(localThis)).toBe('widget-name-testWidget');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('getInputQuestionWidgetAnswersNullSafe returns an empty array when the input question widget has no answers', () => {
|
||||||
|
// Arrange
|
||||||
|
const widgetName = 'inputQuestionWidget';
|
||||||
|
const wrapper = shallowMount(baseMixin, {
|
||||||
|
propsData: {
|
||||||
|
cmsContentByWidget: {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const cmsContent = {
|
||||||
|
[widgetName]: {
|
||||||
|
[widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT]: 'Choose an option',
|
||||||
|
[widgetFields.INPUT_QUESTION_WIDGET.ANSWERS]: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
wrapper.componentVM.setCmsContent(cmsContent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const answers = wrapper.componentVM.getInputQuestionWidgetAnswersNullSafe(widgetName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(answers).not.toBeNull(); // Check that answers is not null
|
||||||
|
expect(Array.isArray(answers)).toBeTruthy(); // Check that answers is an array
|
||||||
|
expect(answers).toHaveLength(0); // Check that answers is empty
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getInputQuestionWidgetAnswersNullSafe returns a non-empty array when the input question widget has answers', () => {
|
||||||
|
// Arrange
|
||||||
|
const widgetName = 'inputQuestionWidget';
|
||||||
|
const wrapper = shallowMount(baseMixin, {
|
||||||
|
propsData: {
|
||||||
|
cmsContentByWidget: {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const cmsContent = {
|
||||||
|
[widgetName]: {
|
||||||
|
[widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT]: 'Choose an option',
|
||||||
|
[widgetFields.INPUT_QUESTION_WIDGET.ANSWERS]: [
|
||||||
|
{
|
||||||
|
Name: 'NameA',
|
||||||
|
Text: 'TextA'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'NameB',
|
||||||
|
Text: 'TextB'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
wrapper.componentVM.setCmsContent(cmsContent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const answers = wrapper.componentVM.getInputQuestionWidgetAnswersNullSafe(widgetName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(answers).not.toBeNull(); // Check that answers is not null
|
||||||
|
expect(Array.isArray(answers)).toBeTruthy(); // Check that answers is an array
|
||||||
|
expect(answers).not.toHaveLength(0); // Check that answers is not empty
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -509,11 +509,7 @@ const routingTable = () => [
|
||||||
destinationIssPageValue: issPageValues.SERVICE_LOCATION
|
destinationIssPageValue: issPageValues.SERVICE_LOCATION
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED,
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
|
||||||
destinationIssPageValue: issPageValues.TPA_SEARCH
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED,
|
|
||||||
destinationIssPageValue: issPageValues.BAILOUT_PAGE
|
destinationIssPageValue: issPageValues.BAILOUT_PAGE
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue