axitech-widget 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -0
- package/dist/Modal-fab2abfa.mjs +4 -0
- package/dist/axitech-widget.es.js +7 -0
- package/dist/axitech-widget.iife.js +698 -0
- package/dist/axitech-widget.umd.js +698 -0
- package/dist/index-2839010c.mjs +30306 -0
- package/dist/style.css +1 -0
- package/dist/types/components/base/ActionCard.vue.d.ts +36 -0
- package/dist/types/components/base/Button.vue.d.ts +9 -0
- package/dist/types/components/base/Collapse.vue.d.ts +2 -0
- package/dist/types/components/base/DatePicker.vue.d.ts +70 -0
- package/dist/types/components/base/GoogleAutocomplete.vue.d.ts +23 -0
- package/dist/types/components/base/GoogleMap.vue.d.ts +26 -0
- package/dist/types/components/base/Input.vue.d.ts +43 -0
- package/dist/types/components/base/Modal.vue.d.ts +55 -0
- package/dist/types/components/base/SelectButton.vue.d.ts +56 -0
- package/dist/types/components/base/Spinner.vue.d.ts +34 -0
- package/dist/types/components/base/uploader/ImageUpload.vue.d.ts +23 -0
- package/dist/types/components/base/uploader/Upload.vue.d.ts +4 -0
- package/dist/types/components/claims-widget/ClaimsWidget.ce.vue.d.ts +2 -0
- package/dist/types/components/claims-widget/components/Error.vue.d.ts +2 -0
- package/dist/types/components/claims-widget/components/SkeletonLoader.vue.d.ts +56 -0
- package/dist/types/components/claims-widget/components/StepConfirm.vue.d.ts +6 -0
- package/dist/types/components/claims-widget/components/StepSelector.vue.d.ts +6 -0
- package/dist/types/components/claims-widget/components/accident/Accident.vue.d.ts +8 -0
- package/dist/types/components/claims-widget/components/accident/ImageSection.vue.d.ts +29 -0
- package/dist/types/components/claims-widget/components/accident/MapSection.vue.d.ts +29 -0
- package/dist/types/components/claims-widget/components/accident/NoteSection.vue.d.ts +21 -0
- package/dist/types/components/claims-widget/components/accident/SectionWrapper.vue.d.ts +23 -0
- package/dist/types/components/claims-widget/components/accident/YourVehicle.vue.d.ts +2 -0
- package/dist/types/components/claims-widget/components/fireWater/FireWater.vue.d.ts +6 -0
- package/dist/types/components/claims-widget/components/illustration/Accident.vue.d.ts +2 -0
- package/dist/types/components/claims-widget/components/illustration/Location.vue.d.ts +2 -0
- package/dist/types/components/claims-widget/components/illustration/SubmittedSuccessfully.vue.d.ts +2 -0
- package/dist/types/components/claims-widget/components/illustration/Unsupported.vue.d.ts +2 -0
- package/dist/types/components/claims-widget/components/windscreen/Windscreen.vue.d.ts +6 -0
- package/dist/types/components/claims-widget/components/windscreen/WindscreenLoading.vue.d.ts +2 -0
- package/dist/types/components/index.d.ts +2 -0
- package/dist/types/composables/googleMaps.d.ts +11 -0
- package/dist/types/constants/index.d.ts +1 -0
- package/dist/types/index.d.ts +34 -0
- package/dist/types/plugins/firebase.d.ts +2 -0
- package/dist/types/plugins/firebaseCloudStorage.d.ts +16 -0
- package/dist/types/utils/autocomplete.d.ts +2 -0
- package/dist/types/utils/colorHelpers.d.ts +7 -0
- package/dist/types/utils/config.d.ts +131 -0
- package/dist/types/utils/customElementRegister.d.ts +1 -0
- package/dist/types/utils/fontUtils.d.ts +1 -0
- package/dist/types/utils/index.d.ts +141 -0
- package/dist/types/utils/map.d.ts +21 -0
- package/dist/types/utils/request.d.ts +30 -0
- package/dist/types/utils/svgUtils.d.ts +0 -0
- package/dist/types/utils/themeUtils.d.ts +9 -0
- package/package.json +77 -0
- package/src/assets/fonts/Volvo Novum-Italic.eot +0 -0
- package/src/assets/fonts/Volvo Novum-Italic.svg +723 -0
- package/src/assets/fonts/Volvo Novum-Italic.woff +0 -0
- package/src/assets/fonts/Volvo Novum-Italic.woff2 +0 -0
- package/src/assets/fonts/Volvo Novum-Light.eot +0 -0
- package/src/assets/fonts/Volvo Novum-Light.svg +707 -0
- package/src/assets/fonts/Volvo Novum-Light.woff +0 -0
- package/src/assets/fonts/Volvo Novum-Light.woff2 +0 -0
- package/src/assets/fonts/Volvo Novum-LightItalic.eot +0 -0
- package/src/assets/fonts/Volvo Novum-LightItalic.svg +723 -0
- package/src/assets/fonts/Volvo Novum-LightItalic.woff +0 -0
- package/src/assets/fonts/Volvo Novum-LightItalic.woff2 +0 -0
- package/src/assets/fonts/Volvo Novum-Medium.eot +0 -0
- package/src/assets/fonts/Volvo Novum-Medium.svg +706 -0
- package/src/assets/fonts/Volvo Novum-Medium.woff +0 -0
- package/src/assets/fonts/Volvo Novum-Medium.woff2 +0 -0
- package/src/assets/fonts/Volvo Novum-MediumItalic.eot +0 -0
- package/src/assets/fonts/Volvo Novum-MediumItalic.svg +724 -0
- package/src/assets/fonts/Volvo Novum-MediumItalic.woff +0 -0
- package/src/assets/fonts/Volvo Novum-MediumItalic.woff2 +0 -0
- package/src/assets/fonts/Volvo Novum-Regular.eot +0 -0
- package/src/assets/fonts/Volvo Novum-Regular.svg +707 -0
- package/src/assets/fonts/Volvo Novum-Regular.woff +0 -0
- package/src/assets/fonts/Volvo Novum-Regular.woff2 +0 -0
- package/src/assets/fonts/Volvo Novum-SemiLight.eot +0 -0
- package/src/assets/fonts/Volvo Novum-SemiLight.svg +706 -0
- package/src/assets/fonts/Volvo Novum-SemiLight.woff +0 -0
- package/src/assets/fonts/Volvo Novum-SemiLight.woff2 +0 -0
- package/src/assets/fonts/Volvo Novum-SemiLightItalic.eot +0 -0
- package/src/assets/fonts/Volvo Novum-SemiLightItalic.svg +722 -0
- package/src/assets/fonts/Volvo Novum-SemiLightItalic.woff +0 -0
- package/src/assets/fonts/Volvo Novum-SemiLightItalic.woff2 +0 -0
- package/src/assets/styles/collapse.sass +20 -0
- package/src/assets/styles/datepicker.sass +14 -0
- package/src/assets/styles/main.sass +182 -0
- package/src/assets/styles/map.sass +41 -0
- package/src/assets/styles/togglebutton.sass +4 -0
- package/src/components/base/ActionCard.vue +49 -0
- package/src/components/base/Button.vue +16 -0
- package/src/components/base/Collapse.vue +41 -0
- package/src/components/base/DatePicker.vue +94 -0
- package/src/components/base/GoogleAutocomplete.vue +116 -0
- package/src/components/base/GoogleMap.vue +114 -0
- package/src/components/base/Input.vue +44 -0
- package/src/components/base/Modal.vue +117 -0
- package/src/components/base/SelectButton.vue +67 -0
- package/src/components/base/Spinner.vue +39 -0
- package/src/components/base/uploader/ImageUpload.vue +85 -0
- package/src/components/base/uploader/Upload.vue +14 -0
- package/src/components/claims-widget/ClaimsWidget.ce.vue +117 -0
- package/src/components/claims-widget/assets/accident.svg +181 -0
- package/src/components/claims-widget/assets/car.svg +6 -0
- package/src/components/claims-widget/assets/currentlocation.svg +3 -0
- package/src/components/claims-widget/assets/door.svg +3 -0
- package/src/components/claims-widget/assets/location.svg +20 -0
- package/src/components/claims-widget/assets/marker.svg +1 -0
- package/src/components/claims-widget/assets/unsupported.svg +107 -0
- package/src/components/claims-widget/assets/windscreen.svg +3 -0
- package/src/components/claims-widget/assets/zoomin.svg +3 -0
- package/src/components/claims-widget/assets/zoomout.svg +3 -0
- package/src/components/claims-widget/components/Error.vue +21 -0
- package/src/components/claims-widget/components/SkeletonLoader.vue +77 -0
- package/src/components/claims-widget/components/StepConfirm.vue +85 -0
- package/src/components/claims-widget/components/StepSelector.vue +58 -0
- package/src/components/claims-widget/components/accident/Accident.vue +267 -0
- package/src/components/claims-widget/components/accident/ImageSection.vue +82 -0
- package/src/components/claims-widget/components/accident/MapSection.vue +72 -0
- package/src/components/claims-widget/components/accident/NoteSection.vue +83 -0
- package/src/components/claims-widget/components/accident/SectionWrapper.vue +16 -0
- package/src/components/claims-widget/components/accident/YourVehicle.vue +60 -0
- package/src/components/claims-widget/components/fireWater/FireWater.vue +42 -0
- package/src/components/claims-widget/components/illustration/Accident.vue +735 -0
- package/src/components/claims-widget/components/illustration/Location.vue +74 -0
- package/src/components/claims-widget/components/illustration/SubmittedSuccessfully.vue +2270 -0
- package/src/components/claims-widget/components/illustration/Unsupported.vue +393 -0
- package/src/components/claims-widget/components/windscreen/Windscreen.vue +44 -0
- package/src/components/claims-widget/components/windscreen/WindscreenLoading.vue +34 -0
- package/src/components/index.ts +3 -0
- package/src/composables/googleMaps.ts +157 -0
- package/src/constants/index.ts +1 -0
- package/src/index.ts +76 -0
- package/src/plugins/firebase.ts +18 -0
- package/src/plugins/firebaseCloudStorage.ts +88 -0
- package/src/utils/autocomplete.ts +57 -0
- package/src/utils/colorHelpers.ts +96 -0
- package/src/utils/config.ts +140 -0
- package/src/utils/customElementRegister.ts +40 -0
- package/src/utils/fontUtils.ts +24 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/map.ts +212 -0
- package/src/utils/request.ts +76 -0
- package/src/utils/svgUtils.ts +0 -0
- package/src/utils/themeUtils.ts +40 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="[bgClass, loaderClass, 'relative overflow-hidden']">
|
|
3
|
+
<div class="shimmer absolute top-0 right-0 bottom-0 left-0" :style="shimmerStyle"></div>
|
|
4
|
+
<slot />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
const LOADER_TYPES = { rectangle: 'rectangle', circle: 'circle' };
|
|
10
|
+
|
|
11
|
+
const LOADER_CSS_CLASSES = {
|
|
12
|
+
[LOADER_TYPES.rectangle]: 'rounded',
|
|
13
|
+
[LOADER_TYPES.circle]: 'rounded-full',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type LoaderTypesKeys = keyof typeof LOADER_TYPES;
|
|
17
|
+
type LoaderTypesValues = (typeof LOADER_TYPES)[LoaderTypesKeys];
|
|
18
|
+
|
|
19
|
+
const SHIMMER_COLOR = '#ffffff';
|
|
20
|
+
|
|
21
|
+
const isHexColor = (hexColor: string) => {
|
|
22
|
+
const hex = hexColor.replace('#', '');
|
|
23
|
+
|
|
24
|
+
return typeof hexColor === 'string' && hexColor.startsWith('#') && hex.length === 6 && !isNaN(Number('0x' + hex));
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const hexToRgb = (hex: string) => `${hex.match(/\w\w/g)?.map((x) => +`0x${x}`)}`;
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script setup lang="ts">
|
|
31
|
+
import { computed } from 'vue';
|
|
32
|
+
|
|
33
|
+
const props = defineProps({
|
|
34
|
+
type: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: LOADER_TYPES.rectangle,
|
|
37
|
+
validator(value: LoaderTypesValues) {
|
|
38
|
+
return Object.values(LOADER_TYPES).includes(value);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
bgClass: {
|
|
42
|
+
type: String,
|
|
43
|
+
default: 'bg-gray-300',
|
|
44
|
+
},
|
|
45
|
+
cssClass: {
|
|
46
|
+
type: String,
|
|
47
|
+
default: '',
|
|
48
|
+
},
|
|
49
|
+
shimmerColor: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: SHIMMER_COLOR,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const shimmerStyle = computed(() => {
|
|
56
|
+
const rgb = isHexColor(props.shimmerColor) ? hexToRgb(props.shimmerColor) : SHIMMER_COLOR;
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
backgroundImage: `linear-gradient(90deg, rgba(${rgb}, 0) 0%, rgba(${rgb}, 0.2) 20%, rgba(${rgb}, 0.5) 60%, rgba(${rgb}, 0))`,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const loaderClass = computed(() => (props.cssClass ? props.cssClass : LOADER_CSS_CLASSES[props.type]));
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<style lang="css" scoped>
|
|
67
|
+
.shimmer {
|
|
68
|
+
transform: translateX(-100%);
|
|
69
|
+
animation: shimmer 1.4s infinite;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@keyframes shimmer {
|
|
73
|
+
100% {
|
|
74
|
+
transform: translateX(100%);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
</style>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section id="widget-confirm" class="w-full mx-auto flex flex-col justify-start items-center content-center">
|
|
3
|
+
<p class="title3-bold mb-10 w-full text-start">Details Submitted Successfully</p>
|
|
4
|
+
<div class="flex flex-col items-center">
|
|
5
|
+
<SubmittedSuccessfully></SubmittedSuccessfully>
|
|
6
|
+
<div class="py-5 w-full flex flex-col items-center text-center gap-4">
|
|
7
|
+
<div class="flex flex-col items-center">
|
|
8
|
+
<h2 class="title3-bold font-medium mb-4">We'll be in touch</h2>
|
|
9
|
+
<p class="body1 text-fontSecondary-500 mb-9">
|
|
10
|
+
Thank you for letting us know about the collision, we'll review these details and contact you soon
|
|
11
|
+
</p>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="w-full flex flex-col items-center">
|
|
14
|
+
<div
|
|
15
|
+
class="flex items-start flex-nowrap justify-start gap-2"
|
|
16
|
+
v-for="(item, index) in progressList"
|
|
17
|
+
:key="index"
|
|
18
|
+
>
|
|
19
|
+
<div class="flex flex-col items-center relative h-full justify-between">
|
|
20
|
+
<Icon
|
|
21
|
+
:icon="item.checked ? 'mdi:check-circle' : 'mdi:circle-outline'"
|
|
22
|
+
width="29px"
|
|
23
|
+
class="text-primary-500"
|
|
24
|
+
></Icon>
|
|
25
|
+
<div v-if="index !== progressList.length - 1" class="checklist-line"></div>
|
|
26
|
+
</div>
|
|
27
|
+
<span class="text-start body1 max-w-sm">{{ item.text }}</span>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="border w-full rounded-md">
|
|
31
|
+
<a :href="`tel:${config.contact.phone}`" class="w-full hover:bg-slate-100 cursor-pointer p-4 block">
|
|
32
|
+
<div class="body1 flex justify-between h-full items-center">
|
|
33
|
+
<div class="text-start">
|
|
34
|
+
<p>Talk to a person</p>
|
|
35
|
+
<span class="body2 text-fontSecondary-500">{{ config.contact.phone }}</span>
|
|
36
|
+
</div>
|
|
37
|
+
<Icon icon="mdi:chevron-right" height="24px"></Icon>
|
|
38
|
+
</div>
|
|
39
|
+
</a>
|
|
40
|
+
<a :href="`mailto:${config.contact.email}`" class="w-full cursor-pointer hover:bg-slate-100 p-4 block">
|
|
41
|
+
<div class="body1 flex justify-between h-full items-center">
|
|
42
|
+
<div class="text-start">
|
|
43
|
+
<p>Email us</p>
|
|
44
|
+
<span class="body2 text-fontSecondary-500">{{ config.contact.email }}</span>
|
|
45
|
+
</div>
|
|
46
|
+
<Icon icon="mdi:chevron-right" height="24px"></Icon>
|
|
47
|
+
</div>
|
|
48
|
+
</a>
|
|
49
|
+
</div>
|
|
50
|
+
<a
|
|
51
|
+
class="action1-bold text-primary hover:text-primary-400 underline underline-offset-2 cursor-pointer"
|
|
52
|
+
@click.prevent="emit('back')"
|
|
53
|
+
>
|
|
54
|
+
Report another incident
|
|
55
|
+
</a>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</section>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<script setup lang="ts">
|
|
62
|
+
import { Icon } from '@iconify/vue';
|
|
63
|
+
import SubmittedSuccessfully from './illustration/SubmittedSuccessfully.vue';
|
|
64
|
+
import { Ref, inject, onMounted } from 'vue';
|
|
65
|
+
import { config } from 'src/utils/config';
|
|
66
|
+
|
|
67
|
+
const emit = defineEmits<{
|
|
68
|
+
(event: 'back'): void;
|
|
69
|
+
}>();
|
|
70
|
+
|
|
71
|
+
const rootElement = inject<Ref<HTMLDivElement>>(config.value.rootKey);
|
|
72
|
+
|
|
73
|
+
const progressList = [
|
|
74
|
+
{ text: 'We can now review the information to determine the next steps', checked: true },
|
|
75
|
+
{ text: 'We`ve started to generate options for where to recover your vehicle', checked: true },
|
|
76
|
+
{ text: 'Our claims experts will follow up with some detailed questions', checked: false },
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
onMounted(() => {
|
|
80
|
+
if (!rootElement?.value) return;
|
|
81
|
+
rootElement.value.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
82
|
+
});
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<style scoped></style>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<h2 class="title3-bold font-medium mb-4">How to make a claim</h2>
|
|
4
|
+
<p class="body3 text-fontSecondary-500 mb-9">Please select the type of claim you are looking for support with</p>
|
|
5
|
+
<ul role="list" class="flex flex-col gap-y-4">
|
|
6
|
+
<li v-for="card in cards" :key="card.name" class="flex">
|
|
7
|
+
<button class="flex items-start rounded p-4 border border-grey-400 w-full" @click="card.onSelect">
|
|
8
|
+
<div class="flex h-12 w-12 items-center justify-center overflow-hidden">
|
|
9
|
+
<Icon :icon="card.icon" :alt="`${card.name}-icon`" class="h-24 w-24 text-primary" />
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="ml-4">
|
|
13
|
+
<h2 class="body1-bold text-start">{{ card.name }}</h2>
|
|
14
|
+
<p class="body3 text-start text-fontSecondary-500">{{ card.description }}</p>
|
|
15
|
+
</div>
|
|
16
|
+
</button>
|
|
17
|
+
</li>
|
|
18
|
+
</ul>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { ref } from 'vue';
|
|
24
|
+
import { Icon } from '@iconify/vue';
|
|
25
|
+
|
|
26
|
+
const emit = defineEmits<{
|
|
27
|
+
(event: 'select', index: number): void;
|
|
28
|
+
}>();
|
|
29
|
+
|
|
30
|
+
const cards = ref([
|
|
31
|
+
{
|
|
32
|
+
name: 'Accident',
|
|
33
|
+
description: 'Start a Claim for an Accident online',
|
|
34
|
+
icon: 'uil:car',
|
|
35
|
+
onSelect: () => {
|
|
36
|
+
emit('select', 0);
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Windscreen',
|
|
41
|
+
description: 'Claim for Windscreen repair',
|
|
42
|
+
icon: 'mdi:car-windshield-outline',
|
|
43
|
+
onSelect: () => {
|
|
44
|
+
emit('select', 1);
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'Fire, Water, Theft or Vandalism',
|
|
49
|
+
description: 'Claim for another type of incident',
|
|
50
|
+
icon: 'mdi:car-door',
|
|
51
|
+
onSelect: () => {
|
|
52
|
+
emit('select', 2);
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<style scoped></style>
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<main
|
|
3
|
+
class="randomclass w-full h-full mx-auto flex flex-col justify-start items-center content-center"
|
|
4
|
+
id="claims-accident"
|
|
5
|
+
>
|
|
6
|
+
<button :disabled="isLoading" class="w-full flex flex-row mb-10 items-center" @click="emit('back')">
|
|
7
|
+
<Icon icon="mdi-light:chevron-left" height="32" />
|
|
8
|
+
<p class="title3-bold">Accident Support</p>
|
|
9
|
+
</button>
|
|
10
|
+
<section class="flex flex-col items-center w-full mt-6">
|
|
11
|
+
<Collapse></Collapse>
|
|
12
|
+
</section>
|
|
13
|
+
<section class="flex flex-col items-center w-full gap-6 mb-8 mt-6">
|
|
14
|
+
<Accident />
|
|
15
|
+
<h5 class="title4-bold">If you've been in an accident</h5>
|
|
16
|
+
<p class="body1 text-fontSecondary-500">
|
|
17
|
+
Let us know as soon as possible, so we can get you moving again. We've built a helpful tool to make this quick
|
|
18
|
+
and easy to do online
|
|
19
|
+
</p>
|
|
20
|
+
</section>
|
|
21
|
+
<SectionWrapper id="date-picker" class="gap-6" title="Approximately when did the collision occur?">
|
|
22
|
+
<DatePicker v-model="date" :disabled="isLoading"></DatePicker>
|
|
23
|
+
</SectionWrapper>
|
|
24
|
+
<MapSection
|
|
25
|
+
v-if="mapKey"
|
|
26
|
+
v-model="location"
|
|
27
|
+
id="location-selector"
|
|
28
|
+
class="gap-6"
|
|
29
|
+
title="Where did the collision occur?"
|
|
30
|
+
></MapSection>
|
|
31
|
+
<SectionWrapper v-for="value in selectValues" :key="value.key" :id="value.key" class="gap-6">
|
|
32
|
+
<template #header>
|
|
33
|
+
<div class="flex w-full justify-between items-center">
|
|
34
|
+
<h3 class="title4-bold">{{ value.title }}</h3>
|
|
35
|
+
<Icon icon="mdi:info-outline" height="20"></Icon>
|
|
36
|
+
</div>
|
|
37
|
+
</template>
|
|
38
|
+
<SelectButton
|
|
39
|
+
v-model="value.value"
|
|
40
|
+
:disabled="isLoading"
|
|
41
|
+
:options="value.options"
|
|
42
|
+
:button-class="value.customClass"
|
|
43
|
+
></SelectButton>
|
|
44
|
+
</SectionWrapper>
|
|
45
|
+
<ImageSection
|
|
46
|
+
v-model="vehicleImages"
|
|
47
|
+
id="your-vehicle"
|
|
48
|
+
:disabled="isLoading"
|
|
49
|
+
title="Your Vehicle"
|
|
50
|
+
card-title="Add photos of your vehicle"
|
|
51
|
+
card-content="Adding photos and details of the damage to your vehicle helps us to assess it earlier and find the right services for you, ultimately resulting in a more efficient repair"
|
|
52
|
+
icon="mdi:car-door"
|
|
53
|
+
></ImageSection>
|
|
54
|
+
<ImageSection
|
|
55
|
+
v-model="additionalImages"
|
|
56
|
+
id="additional-photos"
|
|
57
|
+
:disabled="isLoading"
|
|
58
|
+
title="Additional Photos"
|
|
59
|
+
card-title="Add additional photos and details"
|
|
60
|
+
card-content="To protect your position, we recommend that you try to collect photos of the scene, damaged property and any additional details that help to 'tell the story' of what happened"
|
|
61
|
+
icon="mdi:image-outline"
|
|
62
|
+
></ImageSection>
|
|
63
|
+
<NoteSection v-model="note" :disabled="isLoading"></NoteSection>
|
|
64
|
+
<SectionWrapper id="contact-time">
|
|
65
|
+
<div>
|
|
66
|
+
<label class="title4-bold">When's the best time to call you?</label>
|
|
67
|
+
<p class="body1 text-fontSecondary500">We'll try to call you at your preferred time</p>
|
|
68
|
+
<fieldset class="mt-5">
|
|
69
|
+
<legend class="sr-only">Notification method</legend>
|
|
70
|
+
<div class="flex flex-col gap-5">
|
|
71
|
+
<div v-for="notificationTime in notificationTimes" :key="notificationTime.id" class="flex items-center">
|
|
72
|
+
<input
|
|
73
|
+
:disabled="isLoading"
|
|
74
|
+
:id="notificationTime.id"
|
|
75
|
+
name="notification-method"
|
|
76
|
+
type="radio"
|
|
77
|
+
:checked="notificationTime.id === selectedNotificationTime"
|
|
78
|
+
class="h-5 w-5 border-primary-500 border-2 text-primary-600 focus:ring-primary-600 focus-within:bg-primary-500 active:bg-primary-500"
|
|
79
|
+
:class="{ '!bg-primary-500': notificationTime.id === selectedNotificationTime }"
|
|
80
|
+
@input="selectedNotificationTime = notificationTime.id"
|
|
81
|
+
/>
|
|
82
|
+
<label :for="notificationTime.id" class="ml-3 block body1-bold">{{ notificationTime.title }}</label>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</fieldset>
|
|
86
|
+
</div>
|
|
87
|
+
</SectionWrapper>
|
|
88
|
+
<SectionWrapper id="almost-there">
|
|
89
|
+
<template #header>
|
|
90
|
+
<h3 class="title2-bold">Almost there...</h3>
|
|
91
|
+
</template>
|
|
92
|
+
<fieldset>
|
|
93
|
+
<legend class="sr-only">I Accept Privacy Policy</legend>
|
|
94
|
+
<div class="space-y-5">
|
|
95
|
+
<div class="relative flex items-start">
|
|
96
|
+
<div class="flex h-6 items-center">
|
|
97
|
+
<input
|
|
98
|
+
v-model="isPrivacyAccepted"
|
|
99
|
+
id="comments"
|
|
100
|
+
:disabled="isLoading"
|
|
101
|
+
name="comments"
|
|
102
|
+
type="checkbox"
|
|
103
|
+
:class="{ '!bg-primary-500': isPrivacyAccepted }"
|
|
104
|
+
class="h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600"
|
|
105
|
+
/>
|
|
106
|
+
</div>
|
|
107
|
+
<div class="ml-3 text-sm leading-6">
|
|
108
|
+
<label for="comments" class="body1 text-fontSecondary500">
|
|
109
|
+
By submitting the details above, I agree to be contacted by the Volvo claims team via email or telephone
|
|
110
|
+
regarding my claim. For more information please see our
|
|
111
|
+
<span class="">Privacy Policy</span>
|
|
112
|
+
</label>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</fieldset>
|
|
117
|
+
</SectionWrapper>
|
|
118
|
+
<div id="almost-there" class="px-8 w-full">
|
|
119
|
+
<Button
|
|
120
|
+
class="bg-primary text-white w-full flex justify-center"
|
|
121
|
+
:loading="isLoading"
|
|
122
|
+
:disabled="isLoading"
|
|
123
|
+
@click="submitResult"
|
|
124
|
+
>
|
|
125
|
+
<div class="flex flex-nowrap gap-2 justify-center items-center w-full">
|
|
126
|
+
<span class="title2-bold">Continue</span>
|
|
127
|
+
<Icon icon="mdi:chevron-right" height="28px"></Icon>
|
|
128
|
+
</div>
|
|
129
|
+
</Button>
|
|
130
|
+
<div
|
|
131
|
+
v-if="errorMessage"
|
|
132
|
+
class="mt-4 w-full border-2 border-negative-500 bg-negative-100 text-negative-500 font-bold rounded p-4"
|
|
133
|
+
>
|
|
134
|
+
{{ errorMessage }}
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</main>
|
|
138
|
+
</template>
|
|
139
|
+
|
|
140
|
+
<script setup lang="ts">
|
|
141
|
+
import Button from 'components/base/Button.vue';
|
|
142
|
+
import Collapse from 'components/base/Collapse.vue';
|
|
143
|
+
import DatePicker from 'components/base/DatePicker.vue';
|
|
144
|
+
import MapSection from './MapSection.vue';
|
|
145
|
+
import SelectButton from 'components/base/SelectButton.vue';
|
|
146
|
+
import Accident from '../../components/illustration/Accident.vue';
|
|
147
|
+
import SectionWrapper from 'components/claims-widget/components/accident/SectionWrapper.vue';
|
|
148
|
+
import ImageSection from 'components/claims-widget/components/accident/ImageSection.vue';
|
|
149
|
+
import NoteSection from 'components/claims-widget/components/accident/NoteSection.vue';
|
|
150
|
+
|
|
151
|
+
import { Icon } from '@iconify/vue';
|
|
152
|
+
import { ref } from 'vue';
|
|
153
|
+
import { ILocationInfo } from 'src/utils/map';
|
|
154
|
+
import { config } from 'src/utils/config';
|
|
155
|
+
import { ApiPaths, request } from 'src/utils/request';
|
|
156
|
+
|
|
157
|
+
const emit = defineEmits<{
|
|
158
|
+
(event: 'back'): void;
|
|
159
|
+
(event: 'next'): void;
|
|
160
|
+
}>();
|
|
161
|
+
const mapKey = process.env.VITE_APP_GMAPS_KEY;
|
|
162
|
+
const errorMessage = ref('');
|
|
163
|
+
const isLoading = ref(false);
|
|
164
|
+
const isPrivacyAccepted = ref(false);
|
|
165
|
+
|
|
166
|
+
const date = ref('');
|
|
167
|
+
const note = ref('');
|
|
168
|
+
const location = ref<ILocationInfo>();
|
|
169
|
+
const selectedNotificationTime = ref('morning');
|
|
170
|
+
const additionalImages = ref<string[]>([]);
|
|
171
|
+
const vehicleImages = ref<string[]>([]);
|
|
172
|
+
|
|
173
|
+
const selectValues = ref([
|
|
174
|
+
{
|
|
175
|
+
options: [
|
|
176
|
+
{ label: 'My Vehicle Is Safe To Drive', value: true },
|
|
177
|
+
{ label: 'No, I Will need Recovery', value: false },
|
|
178
|
+
],
|
|
179
|
+
value: false,
|
|
180
|
+
key: 'vehicleRoadWorthy',
|
|
181
|
+
customClass: 'w-full col-span-full sm:col-auto',
|
|
182
|
+
title: 'Is your vehicle roadworthy?',
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
options: [
|
|
186
|
+
{ label: 'Yes', value: true },
|
|
187
|
+
{ label: 'No', value: false },
|
|
188
|
+
],
|
|
189
|
+
value: false,
|
|
190
|
+
key: 'driver',
|
|
191
|
+
title: 'Were you the driver?',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
options: [
|
|
195
|
+
{ label: 'Yes', value: true },
|
|
196
|
+
{ label: 'No', value: false },
|
|
197
|
+
],
|
|
198
|
+
value: false,
|
|
199
|
+
key: 'injured',
|
|
200
|
+
title: 'Were you injured?',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
options: [
|
|
204
|
+
{ label: 'Yes', value: true },
|
|
205
|
+
{ label: 'No', value: false },
|
|
206
|
+
],
|
|
207
|
+
value: false,
|
|
208
|
+
key: 'thirdPartiesInvolved',
|
|
209
|
+
title: 'Were any other third parties involved?',
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
options: [
|
|
213
|
+
{ label: 'Yes', value: true },
|
|
214
|
+
{ label: 'No', value: false },
|
|
215
|
+
],
|
|
216
|
+
value: false,
|
|
217
|
+
key: 'witnessesPresent',
|
|
218
|
+
title: 'Were any witnesses present?',
|
|
219
|
+
},
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
const notificationTimes = [
|
|
223
|
+
{ id: 'morning', title: 'Morning' },
|
|
224
|
+
{ id: 'afternoon', title: 'Afternoon' },
|
|
225
|
+
{ id: 'evening', title: 'Evening' },
|
|
226
|
+
{ id: 'anytime', title: 'Call anytime' },
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
async function submitResult() {
|
|
230
|
+
if (!isPrivacyAccepted.value) {
|
|
231
|
+
errorMessage.value = 'You must accept the privacy policy before proceeding!';
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (!location.value?.formatted_address) {
|
|
235
|
+
errorMessage.value = 'Please provide provide your location!';
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
errorMessage.value = '';
|
|
239
|
+
isLoading.value = true;
|
|
240
|
+
|
|
241
|
+
const result = {
|
|
242
|
+
notificationTime: selectedNotificationTime.value,
|
|
243
|
+
...(Object.fromEntries(selectValues.value.map(({ value, key }) => [key, value])) as {
|
|
244
|
+
vehicleRoadWorthy: boolean;
|
|
245
|
+
driver: boolean;
|
|
246
|
+
injured: boolean;
|
|
247
|
+
thirdPartiesInvolved: boolean;
|
|
248
|
+
witnessesPresent: boolean;
|
|
249
|
+
}),
|
|
250
|
+
date: date.value,
|
|
251
|
+
location: location.value,
|
|
252
|
+
vehicleImages: vehicleImages.value,
|
|
253
|
+
additionalImages: additionalImages.value,
|
|
254
|
+
note: note.value,
|
|
255
|
+
user: config.value.user,
|
|
256
|
+
insurance: config.value.insurance,
|
|
257
|
+
incidentType: 'Collision',
|
|
258
|
+
};
|
|
259
|
+
isLoading.value = true;
|
|
260
|
+
const [, error] = await request.post(ApiPaths.submission, result);
|
|
261
|
+
if (error) {
|
|
262
|
+
errorMessage.value = error.message;
|
|
263
|
+
}
|
|
264
|
+
isLoading.value = false;
|
|
265
|
+
emit('next');
|
|
266
|
+
}
|
|
267
|
+
</script>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<SectionWrapper>
|
|
3
|
+
<template #header>
|
|
4
|
+
<div class="w-full flex justify-between items-center">
|
|
5
|
+
<h3 class="title4-bold">{{ title }}</h3>
|
|
6
|
+
<Button
|
|
7
|
+
v-if="previewImages?.length"
|
|
8
|
+
@click="openVehicleImageUpload"
|
|
9
|
+
:disabled="disabled"
|
|
10
|
+
class="!w-6 !h-6 !p-2 !rounded-full items-center justify-center flex"
|
|
11
|
+
>
|
|
12
|
+
<Icon icon="mdi:pencil"></Icon>
|
|
13
|
+
</Button>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
<ActionCard
|
|
17
|
+
v-if="!previewImages?.length"
|
|
18
|
+
:title="cardTitle"
|
|
19
|
+
:icon="icon"
|
|
20
|
+
:content="cardContent"
|
|
21
|
+
:disabled="disabled"
|
|
22
|
+
action="Add photos"
|
|
23
|
+
@action="openVehicleImageUpload"
|
|
24
|
+
></ActionCard>
|
|
25
|
+
<div
|
|
26
|
+
v-else
|
|
27
|
+
class="grid grid-cols-[repeat(auto-fill,_minmax(80px,_1fr))] sm:grid-cols-[repeat(auto-fill,_minmax(120px,_1fr))] gap-4 w-full"
|
|
28
|
+
>
|
|
29
|
+
<div class="w-full h-full" v-for="(image, index) in previewImages" :key="image">
|
|
30
|
+
<img
|
|
31
|
+
:src="image"
|
|
32
|
+
height="80"
|
|
33
|
+
:alt="`vehicle-damage${index}`"
|
|
34
|
+
class="rounded aspect-square object-cover w-full sm:h-28"
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<ImageUpload
|
|
39
|
+
v-model="isImageUploadOpen"
|
|
40
|
+
:title="cardTitle"
|
|
41
|
+
:info="cardContent"
|
|
42
|
+
@imagesAdded="saveimages"
|
|
43
|
+
></ImageUpload>
|
|
44
|
+
</SectionWrapper>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<script setup lang="ts">
|
|
48
|
+
import Button from 'components/base/Button.vue';
|
|
49
|
+
import ActionCard from 'components/base/ActionCard.vue';
|
|
50
|
+
import ImageUpload from 'components/base/uploader/ImageUpload.vue';
|
|
51
|
+
import SectionWrapper from './SectionWrapper.vue';
|
|
52
|
+
|
|
53
|
+
import { Icon } from '@iconify/vue';
|
|
54
|
+
import { ref } from 'vue';
|
|
55
|
+
import { useVModel } from '@vueuse/core';
|
|
56
|
+
|
|
57
|
+
const props = defineProps<{
|
|
58
|
+
title: string;
|
|
59
|
+
cardTitle: string;
|
|
60
|
+
cardContent: string;
|
|
61
|
+
icon: string;
|
|
62
|
+
modelValue: string[];
|
|
63
|
+
disabled?: boolean;
|
|
64
|
+
}>();
|
|
65
|
+
|
|
66
|
+
const emit = defineEmits<{
|
|
67
|
+
(e: 'update:modelValue', images: string[]): void;
|
|
68
|
+
}>();
|
|
69
|
+
|
|
70
|
+
const isImageUploadOpen = ref(false);
|
|
71
|
+
const previewImages = useVModel(props, 'modelValue', emit);
|
|
72
|
+
|
|
73
|
+
function openVehicleImageUpload() {
|
|
74
|
+
isImageUploadOpen.value = true;
|
|
75
|
+
}
|
|
76
|
+
function saveimages(images: string[]) {
|
|
77
|
+
isImageUploadOpen.value = false;
|
|
78
|
+
previewImages.value = images;
|
|
79
|
+
}
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<style scoped></style>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section class="flex flex-col items-start w-full gap-3 mb-8">
|
|
3
|
+
<slot name="header">
|
|
4
|
+
<div class="w-full flex justify-between items-center">
|
|
5
|
+
<h3 class="title4-bold">{{ title }}</h3>
|
|
6
|
+
<div v-if="location?.latitude" class="flex items-center gap-2">
|
|
7
|
+
<Button @click="toggleMap(true)" class="!w-6 !h-6 !p-2 !rounded-full items-center justify-center flex">
|
|
8
|
+
<Icon icon="mdi:pencil"></Icon>
|
|
9
|
+
</Button>
|
|
10
|
+
<Button
|
|
11
|
+
@click="isOpenDeleteModal = true"
|
|
12
|
+
class="!w-6 !h-6 !p-2 !rounded-full items-center justify-center flex"
|
|
13
|
+
>
|
|
14
|
+
<Icon icon="mdi:trash-can-outline"></Icon>
|
|
15
|
+
</Button>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</slot>
|
|
19
|
+
<div class="flex flex-row flex-nowrap w-full justify-start gap-5">
|
|
20
|
+
<GoogleMap v-model="location" :is-open="isMapOpen" @update:is-open="toggleMap"></GoogleMap>
|
|
21
|
+
</div>
|
|
22
|
+
<Modal v-if="isOpenDeleteModal" v-model="isOpenDeleteModal">
|
|
23
|
+
<template #header><p class="font-bold">Are you sure you want to delete this location?</p> </template>
|
|
24
|
+
<div class="w-full h-full flex flex-col gap-4 items-center">
|
|
25
|
+
<p>This action cannot be undone</p>
|
|
26
|
+
</div>
|
|
27
|
+
<template #footer>
|
|
28
|
+
<div class="w-full flex justify-center">
|
|
29
|
+
<Button class="bg-primary text-white px-12" @click="deleteLocation">
|
|
30
|
+
<div class="flex flex-nowrap gap-2 justify-center items-center">
|
|
31
|
+
<span class="title2-bold">Delete</span>
|
|
32
|
+
</div>
|
|
33
|
+
</Button>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
</Modal>
|
|
37
|
+
</section>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<script lang="ts" setup>
|
|
41
|
+
import { computed, defineAsyncComponent, ref } from 'vue';
|
|
42
|
+
import { ILocationInfo } from 'src/utils/map';
|
|
43
|
+
import { Icon } from '@iconify/vue';
|
|
44
|
+
import GoogleMap from 'components/base/GoogleMap.vue';
|
|
45
|
+
import Button from 'components/base/Button.vue';
|
|
46
|
+
|
|
47
|
+
const Modal = defineAsyncComponent(() => import('components/base/Modal.vue'));
|
|
48
|
+
const props = defineProps<{
|
|
49
|
+
modelValue?: ILocationInfo;
|
|
50
|
+
title?: string;
|
|
51
|
+
}>();
|
|
52
|
+
|
|
53
|
+
const emit = defineEmits<{
|
|
54
|
+
(e: 'update:modelValue', value: ILocationInfo | undefined): void;
|
|
55
|
+
}>();
|
|
56
|
+
|
|
57
|
+
const location = computed<ILocationInfo | undefined>({
|
|
58
|
+
get: () => props.modelValue,
|
|
59
|
+
set: (value: ILocationInfo | undefined) => emit('update:modelValue', value),
|
|
60
|
+
});
|
|
61
|
+
const isMapOpen = ref(false);
|
|
62
|
+
const isOpenDeleteModal = ref(false);
|
|
63
|
+
|
|
64
|
+
function toggleMap(value: boolean) {
|
|
65
|
+
isMapOpen.value = value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function deleteLocation() {
|
|
69
|
+
location.value = undefined;
|
|
70
|
+
isOpenDeleteModal.value = false;
|
|
71
|
+
}
|
|
72
|
+
</script>
|