project-booster-vue 10.6.1 → 10.7.0
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/package.json +1 -1
- package/src/components/rework/exit-options/MPbExitOptions.vue +32 -5
- package/src/components/rework/timify/MPbTimify.stories.mdx +63 -0
- package/src/components/rework/timify/MPbTimify.vue +78 -0
- package/src/components/rework/timify/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-rework-alert-m-pb-alert-/360/237/246/240-101-sandbox-1-snap.png +0 -0
- package/src/components/rework/timify/default-payload.json +6 -0
- package/src/components/scenario/PbScenario.vue +2 -0
- package/src/services/api/timifyApi.ts +33 -0
- package/src/stores/modules/timifyStore.ts +87 -0
- package/src/stores/store.ts +2 -0
- package/src/types/pb/Timify.ts +15 -0
package/package.json
CHANGED
|
@@ -83,17 +83,17 @@
|
|
|
83
83
|
|
|
84
84
|
<script lang="ts" setup>
|
|
85
85
|
import { MButton } from '@mozaic-ds/vue-3';
|
|
86
|
-
import { PropType, ref, defineEmits, defineProps } from 'vue';
|
|
86
|
+
import { PropType, ref, defineEmits, defineProps, computed, ComputedRef } from 'vue';
|
|
87
87
|
import { PayloadAction } from '../types/genericPayload';
|
|
88
88
|
import { areConditionsValid } from '../../../services/scenarioConditionals';
|
|
89
89
|
import { sanitizeCerberusAttribut } from '@/services/sanitize';
|
|
90
90
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
91
91
|
import { useStore } from 'vuex';
|
|
92
92
|
import { callAction } from '../services/navigate';
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
import cloneDeep from 'lodash.clonedeep';
|
|
94
|
+
import DEFAULT_PAYLOAD from './default-payload.json';
|
|
95
|
+
import merge from 'lodash.merge';
|
|
96
|
+
import { decorate } from '@/services/decorate';
|
|
97
97
|
|
|
98
98
|
const props = defineProps({
|
|
99
99
|
/**
|
|
@@ -121,6 +121,33 @@ const props = defineProps({
|
|
|
121
121
|
},
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
+
const store = useStore();
|
|
125
|
+
|
|
126
|
+
const computedPayload = computed(() => {
|
|
127
|
+
const tempPayload = cloneDeep(DEFAULT_PAYLOAD);
|
|
128
|
+
return merge(tempPayload, props.payload);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const computeDefaultValue = (
|
|
132
|
+
runtimeOptions: any,
|
|
133
|
+
answers: Map<string, ScenarioStepAnswer[]>,
|
|
134
|
+
computedPayload: ComputedRef<any>,
|
|
135
|
+
) => {
|
|
136
|
+
let message;
|
|
137
|
+
if (computedPayload?.value?.value) {
|
|
138
|
+
message = decorate(
|
|
139
|
+
answers,
|
|
140
|
+
runtimeOptions,
|
|
141
|
+
computedPayload?.value?.value?.message,
|
|
142
|
+
computedPayload?.value?.defaultDecoratorValue ?? '',
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return message;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const emit = defineEmits(['go-back', 'step-completed']);
|
|
149
|
+
const message = ref(computeDefaultValue(props.runtimeOptions, props.answers!, computedPayload));
|
|
150
|
+
|
|
124
151
|
/**
|
|
125
152
|
* Send action to completed step
|
|
126
153
|
* @param action
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Anchor, Story, Preview, Meta, Props, ArgsTable, Source, Canvas } from '@storybook/addon-docs';
|
|
2
|
+
import DEFAULT_PAYLOAD from './default-payload';
|
|
3
|
+
import { nestedAppDecorator } from '../../../../.storybook/nested-app-decorator';
|
|
4
|
+
import MPbTimify from './MPbTimify';
|
|
5
|
+
import inhabitantsStore from '../../../stores/modules/inhabitantsStore';
|
|
6
|
+
import timifyStore from '../../../stores/modules/timifyStore';
|
|
7
|
+
|
|
8
|
+
<Meta
|
|
9
|
+
title="Project Booster/Rework/Timify/MPbTimify 🦠"
|
|
10
|
+
component={MPbTimify}
|
|
11
|
+
argTypes={{
|
|
12
|
+
payload: {
|
|
13
|
+
table: {
|
|
14
|
+
defaultValue: {
|
|
15
|
+
summary: 'object',
|
|
16
|
+
detail: JSON.stringify(DEFAULT_PAYLOAD, null, ' '),
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
control: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
}}
|
|
24
|
+
parameters={{
|
|
25
|
+
layout: 'fullscreen',
|
|
26
|
+
}}
|
|
27
|
+
decorators={[
|
|
28
|
+
nestedAppDecorator(
|
|
29
|
+
{
|
|
30
|
+
modules: {
|
|
31
|
+
inhabitants: inhabitantsStore,
|
|
32
|
+
timify: timifyStore,
|
|
33
|
+
},
|
|
34
|
+
mutations: {},
|
|
35
|
+
actions: {},
|
|
36
|
+
},
|
|
37
|
+
[],
|
|
38
|
+
),
|
|
39
|
+
]}
|
|
40
|
+
/>
|
|
41
|
+
|
|
42
|
+
# 🦠 `MPbTimify` - Component
|
|
43
|
+
|
|
44
|
+
The `MPbTimify` component to display information that user needed.
|
|
45
|
+
|
|
46
|
+
export const TemplateSandbox = (args, { argTypes }) => ({
|
|
47
|
+
props: Object.keys(argTypes),
|
|
48
|
+
components: { MPbTimify },
|
|
49
|
+
setup() {
|
|
50
|
+
return { args };
|
|
51
|
+
},
|
|
52
|
+
template: `<m-pb-timify
|
|
53
|
+
:payload="args.payload"
|
|
54
|
+
/>`,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
## showCase
|
|
58
|
+
|
|
59
|
+
<Canvas>
|
|
60
|
+
<Story inline={false} height="862px" name="101 Sandbox" args={{ payload: DEFAULT_PAYLOAD }}>
|
|
61
|
+
{TemplateSandbox.bind({})}
|
|
62
|
+
</Story>
|
|
63
|
+
</Canvas>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="m-pb-timify">
|
|
3
|
+
<div class="m-pb-timify__iframe" v-if="!showClicRDV">
|
|
4
|
+
<iframe :src="iframeUri" frameborder="0"></iframe>
|
|
5
|
+
</div>
|
|
6
|
+
<pb-appointment-form v-else :payload="payload"></pb-appointment-form>
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script lang="ts" setup>
|
|
11
|
+
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
12
|
+
import { PropType, computed, onBeforeMount } from 'vue';
|
|
13
|
+
import { ref } from 'vue';
|
|
14
|
+
import { useStore } from 'vuex';
|
|
15
|
+
import PbAppointmentForm from '@/components/appointment/PbAppointmentForm.vue';
|
|
16
|
+
|
|
17
|
+
const props = defineProps({
|
|
18
|
+
/**
|
|
19
|
+
* The component view model and business data as an object. The provided prop
|
|
20
|
+
* is merged with the default payload value so only overriden values will change
|
|
21
|
+
* from the default ones.
|
|
22
|
+
*/
|
|
23
|
+
payload: {
|
|
24
|
+
type: Object,
|
|
25
|
+
default: () => ({}),
|
|
26
|
+
},
|
|
27
|
+
/**
|
|
28
|
+
* The previous answers to inject
|
|
29
|
+
*/
|
|
30
|
+
answers: {
|
|
31
|
+
type: Object as PropType<Map<string, ScenarioStepAnswer[]>>,
|
|
32
|
+
default: () => new Map<string, ScenarioStepAnswer[]>(),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const iframeUri = ref('https://book.timify.com/services?');
|
|
37
|
+
const store = useStore();
|
|
38
|
+
const showClicRDV = computed(() => store.getters['timify/showClicRDV']);
|
|
39
|
+
const getShowServices = computed(() => store.getters['timify/getShowServices']);
|
|
40
|
+
const getAccountId = computed(() => store.getters['timify/getAccountId']);
|
|
41
|
+
const currentUser = store.getters['inhabitants/getCurrentInhabitant'];
|
|
42
|
+
const projectId = store.getters['appointmentQualification/getCurrentAppointmentQualification'];
|
|
43
|
+
|
|
44
|
+
onBeforeMount(() => {
|
|
45
|
+
store.dispatch('timify/loadTimify', {
|
|
46
|
+
payload: props.payload.viewModel.appointmentCategory,
|
|
47
|
+
storeId: store.getters.metadata.storeId || '',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
store.dispatch('timify/loadCollaboratorUri', {
|
|
51
|
+
projectId,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const collaboratorUri = store.getters['timify/getCollaboratorUri'];
|
|
55
|
+
|
|
56
|
+
iframeUri.value += `accountId=${getAccountId}&showServices=${getShowServices}`;
|
|
57
|
+
iframeUri.value += `&guestFirstName=${currentUser.firstname}&guestLastName=${currentUser.lastname}&guestEmail=${currentUser.email}&guestPhone=${currentUser.phone}`;
|
|
58
|
+
iframeUri.value += `&externalCustomerField[inhabitantProjectId]=${projectId}&externalCustomerField[collaboratorLink]=${collaboratorUri}&hideCloseButton=true`;
|
|
59
|
+
});
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<style lang="scss">
|
|
63
|
+
@import 'pb-variables';
|
|
64
|
+
@import '../styles/global.scss';
|
|
65
|
+
|
|
66
|
+
.m-pb-timify {
|
|
67
|
+
width: calc(100% - $mu250);
|
|
68
|
+
margin: $mu200 auto $mu250 auto;
|
|
69
|
+
padding: 0 $mu125;
|
|
70
|
+
|
|
71
|
+
&__iframe {
|
|
72
|
+
iframe {
|
|
73
|
+
width: 100%;
|
|
74
|
+
height: 100vh;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
</style>
|
|
@@ -149,6 +149,7 @@ import MPbNameInput from '../rework/question/name-input/MPbNameInput.vue';
|
|
|
149
149
|
import MPbExitOptions from '../rework/exit-options/MPbExitOptions.vue';
|
|
150
150
|
import MPbUploadDocument from '../rework/question/upload-document/MPbUploadDocument.vue';
|
|
151
151
|
import MPbMediaUpload from '../rework/media/upload/MPbMediaUpload.vue';
|
|
152
|
+
import MPbTimify from '../rework/timify/MPbTimify.vue';
|
|
152
153
|
|
|
153
154
|
import { areConditionsValid } from '../../services/scenarioConditionals';
|
|
154
155
|
import {
|
|
@@ -204,6 +205,7 @@ export default defineComponent({
|
|
|
204
205
|
MPbUploadDocument,
|
|
205
206
|
MPbConfigurationsImport,
|
|
206
207
|
MPbMediaUpload,
|
|
208
|
+
MPbTimify,
|
|
207
209
|
},
|
|
208
210
|
|
|
209
211
|
props: {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { escape } from '../../services/htmlEscape';
|
|
3
|
+
|
|
4
|
+
export const clientApi = axios.create({
|
|
5
|
+
baseURL: '/project-booster/api',
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
if ((<any>window).config) {
|
|
9
|
+
clientApi.defaults.baseURL = (<any>window).config.VUE_APP_DEFAULT_BASE_URL;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get timify object with appointmentCategory && storeId
|
|
14
|
+
* @param appointmentCategory
|
|
15
|
+
* @param storeId
|
|
16
|
+
* @returns
|
|
17
|
+
*/
|
|
18
|
+
export const getTimifyObject = async (appointmentCategory: string, storeId: string) => {
|
|
19
|
+
try {
|
|
20
|
+
const response = await clientApi.get(
|
|
21
|
+
`/appointment-qualifications/is-timify-enabled?${
|
|
22
|
+
storeId ? '?storeId=' + storeId : ''
|
|
23
|
+
}&appointmentCategory=${appointmentCategory}`,
|
|
24
|
+
);
|
|
25
|
+
return JSON.parse(
|
|
26
|
+
JSON.stringify(response.data).replace(/:"([^"]+)"/g, (match, $1) => {
|
|
27
|
+
return `: "${escape($1)}"`;
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ActionContext } from 'vuex';
|
|
2
|
+
import { State } from '@/stores/state';
|
|
3
|
+
import { getTimifyObject } from '@/services/api/timifyApi';
|
|
4
|
+
import { TimifyServices, TimifyState } from '@/types/pb/Timify';
|
|
5
|
+
|
|
6
|
+
type TimifyContext = ActionContext<TimifyState, State>;
|
|
7
|
+
|
|
8
|
+
enum callboratorUris {
|
|
9
|
+
prod = 'https://collaborators.pb-prod-adeo-disp.tech.adeo.cloud/index.html/projects/',
|
|
10
|
+
prep = 'https://collaborators.pb-preprod-adeo-disp.tech.adeo.cloud/index.html/projects/',
|
|
11
|
+
dev = 'https://collaborators.pb-dev-adeo-disp.tech.adeo.cloud/index.html/projects/',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
namespaced: true,
|
|
16
|
+
state: {
|
|
17
|
+
showServices: [],
|
|
18
|
+
accountId: '',
|
|
19
|
+
collaboratorUri: '',
|
|
20
|
+
showClicRDV: false,
|
|
21
|
+
},
|
|
22
|
+
getters: {
|
|
23
|
+
getShowServices(state: TimifyState) {
|
|
24
|
+
return state.showServices;
|
|
25
|
+
},
|
|
26
|
+
getAccountId(state: TimifyState) {
|
|
27
|
+
return state.accountId;
|
|
28
|
+
},
|
|
29
|
+
getCollaboratorUri(state: TimifyState) {
|
|
30
|
+
return state.collaboratorUri;
|
|
31
|
+
},
|
|
32
|
+
getShowClicRDV(state: TimifyState) {
|
|
33
|
+
return state.showClicRDV;
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
mutations: {
|
|
37
|
+
setShowServices(state: TimifyState, services: string[]) {
|
|
38
|
+
state.showServices = services;
|
|
39
|
+
},
|
|
40
|
+
setAccountId(state: TimifyState, accountId: string) {
|
|
41
|
+
state.accountId = accountId;
|
|
42
|
+
},
|
|
43
|
+
setCollaboratorUri(state: TimifyState, collaboratorUri: string) {
|
|
44
|
+
state.collaboratorUri = collaboratorUri;
|
|
45
|
+
},
|
|
46
|
+
setShowClicRDV(state: TimifyState, showClicRDV: boolean) {
|
|
47
|
+
state.showClicRDV = showClicRDV;
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
actions: {
|
|
51
|
+
async loadTimify(
|
|
52
|
+
{ commit, state }: TimifyContext,
|
|
53
|
+
{ appointmentCategory, storeId }: { appointmentCategory: string; storeId: string },
|
|
54
|
+
) {
|
|
55
|
+
const timify = await getTimifyObject(appointmentCategory, storeId);
|
|
56
|
+
|
|
57
|
+
if (timify) {
|
|
58
|
+
if (timify.services.length) {
|
|
59
|
+
const servicesIds = timify.services.map((service: TimifyServices) => {
|
|
60
|
+
return service.id;
|
|
61
|
+
});
|
|
62
|
+
commit('setShowServices', servicesIds.toString());
|
|
63
|
+
} else {
|
|
64
|
+
commit('setShowClicRDV', true);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (timify.company) {
|
|
68
|
+
const accountId = timify.company.id;
|
|
69
|
+
commit('setAccountId', accountId);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
commit('setShowClicRDV', true);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
async loadCollaboratorUri({ commit, state }: TimifyContext, { projectId }: { projectId: string }) {
|
|
76
|
+
const baseurl = window.location.host;
|
|
77
|
+
|
|
78
|
+
if (baseurl.includes('prep')) {
|
|
79
|
+
commit('setCollaboratorUri', callboratorUris.prep + projectId);
|
|
80
|
+
} else if (baseurl.includes('uat') || baseurl.includes('localhost')) {
|
|
81
|
+
commit('setCollaboratorUri', callboratorUris.dev + projectId);
|
|
82
|
+
} else {
|
|
83
|
+
commit('setCollaboratorUri', callboratorUris.prod + projectId);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
};
|
package/src/stores/store.ts
CHANGED
|
@@ -9,6 +9,7 @@ import documentsStore from './modules/documentsStore';
|
|
|
9
9
|
import consentStore from './modules/consentStore';
|
|
10
10
|
import productsStore from './modules/productsStore';
|
|
11
11
|
import trezorStore from './modules/trezorStore';
|
|
12
|
+
import timifyStore from './modules/timifyStore';
|
|
12
13
|
import cloneDeep from 'lodash.clonedeep';
|
|
13
14
|
import { State } from '@/stores/state';
|
|
14
15
|
import { ActionContext } from 'vuex';
|
|
@@ -28,6 +29,7 @@ export default {
|
|
|
28
29
|
consent: consentStore,
|
|
29
30
|
products: productsStore,
|
|
30
31
|
trezor: trezorStore,
|
|
32
|
+
timify: timifyStore,
|
|
31
33
|
},
|
|
32
34
|
mutations: {
|
|
33
35
|
eventBusSendEvent(state: State, { code, payload }: { code: string; payload: any }) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface TimifyState {
|
|
2
|
+
showServices: string[];
|
|
3
|
+
accountId: string;
|
|
4
|
+
collaboratorUri: string;
|
|
5
|
+
showClicRDV: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface TimifyServices {
|
|
9
|
+
id: string;
|
|
10
|
+
categoryId: string;
|
|
11
|
+
externalId: string;
|
|
12
|
+
globalId: string;
|
|
13
|
+
name: string;
|
|
14
|
+
isBookable: boolean;
|
|
15
|
+
}
|