project-booster-vue 10.13.1 → 10.13.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.
Files changed (24) hide show
  1. package/package.json +1 -1
  2. package/src/components/question/incremental-amount-input/IncrementalAmount.ts +1 -0
  3. package/src/components/question/space-input/SpaceInput.ts +1 -0
  4. package/src/components/rework/alert/MPbAlert.vue +5 -19
  5. package/src/components/rework/alert/default-payload.json +4 -15
  6. package/src/components/rework/cards/MPbCards.vue +0 -1
  7. package/src/components/rework/exit-options/MPbExitOptions.vue +2 -38
  8. package/src/components/rework/navigation/MPbNavigation.stories.mdx +48 -0
  9. package/src/components/rework/navigation/MPbNavigation.vue +116 -0
  10. package/src/components/rework/navigation/default-payload.json +1 -0
  11. package/src/components/rework/question/MPbQuestion.vue +7 -3
  12. package/src/components/rework/question/city-search/MPbCitySearch.vue +25 -41
  13. package/src/components/rework/question/city-search/default-payload.json +3 -14
  14. package/src/components/rework/question/incremental-amount-input/MPbIncrementalAmountInput.vue +21 -20
  15. package/src/components/rework/question/space-input/MPbSpaceInput.vue +16 -62
  16. package/src/components/rework/question/space-input/default-payload.json +3 -14
  17. package/src/components/rework/restitution/MPbRestitutionList.vue +4 -0
  18. package/src/components/rework/services/navigate.ts +6 -1
  19. package/src/components/rework/styles/global.scss +8 -0
  20. package/src/components/scenario/scenarii/attic-insulation.json +16 -30
  21. package/src/components/scenario/scenarii/estimator-hpwa.json +17 -17
  22. package/src/components/scenario/scenarii/pellet-boiler.json +12 -26
  23. package/src/components/scenario/scenarii/wood-stove.json +14 -30
  24. package/src/types/pb/Scenario.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-booster-vue",
3
- "version": "10.13.1",
3
+ "version": "10.13.2",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -18,6 +18,7 @@ export interface IncrementalAmountViewModel {
18
18
  minValue: number;
19
19
  maxValue: number;
20
20
  defaultValue: number;
21
+ nextStep?: any;
21
22
  }
22
23
 
23
24
  export interface IncrementalAmountPayload {
@@ -28,6 +28,7 @@ export interface SpaceInputViewModel {
28
28
  label: string;
29
29
  conditions: string[];
30
30
  };
31
+ nextStep?: any;
31
32
  }
32
33
 
33
34
  export interface SpaceInputPayload {
@@ -44,24 +44,7 @@
44
44
  </div>
45
45
  </div>
46
46
 
47
- <div class="m-pb-alert__buttons" v-if="payload">
48
- <div v-for="button in payload.callToActions" class="m-pb-alert__buttons__button row-flex">
49
- <m-button
50
- :label="button.label"
51
- @click="callAction(button)"
52
- :theme="button.theme"
53
- :icon="button.icon"
54
- :iconPosition="button.iconPosition"
55
- style="margin-left: 1rem"
56
- :data-cerberus="sanitizeCerberusAttribut('MPB-ALERT', button.label)"
57
- :class="{ 'js-cdl': trackingStatus }"
58
- data-cdl-click-type="cdl_event"
59
- :data-cdl-click-data="
60
- formatEvent({ button_name: button.label, button_location: stepLocation }, EventTypeEnum.BUTTON)
61
- "
62
- />
63
- </div>
64
- </div>
47
+ <m-pb-navigation :payload="payload" :nextButtonAction="payload.viewModel.nextStep" />
65
48
 
66
49
  <m-modal :modalTitle="titleModal" :open="showModal" @update:open="handleCloseModal" class="m-pb-alert__dialog">
67
50
  <template #default>
@@ -87,10 +70,10 @@
87
70
  <script lang="ts" setup>
88
71
  import { MNotification, MButton, MCard, MModal } from '@mozaic-ds/vue-3';
89
72
  import { PayloadAction } from '../types/genericPayload';
90
- import { sanitizeCerberusAttribut } from '@/services/sanitize';
91
73
  import { ref } from 'vue';
92
74
  import { useStore } from 'vuex';
93
75
  import { EventTypeEnum, formatEvent } from '../services/event';
76
+ import MPbNavigation from '../navigation/MPbNavigation.vue';
94
77
 
95
78
  const emit = defineEmits(['go-back', 'step-completed']);
96
79
  const showModal = ref(false);
@@ -108,6 +91,9 @@ const props = defineProps({
108
91
  type: Object,
109
92
  default: () => ({}),
110
93
  },
94
+ /**
95
+ * Show step location
96
+ */
111
97
  stepLocation: {
112
98
  type: String,
113
99
  default: '',
@@ -7,6 +7,9 @@
7
7
  "title": "Envoyez votre plan au plus tard 48h avant le rendez-vous.",
8
8
  "content": "Nous avons besoin d’un plan pour connaitre les mesures et ouvertures de votre salle de bain actuelle. Sans ces informations, nous serons obligés d'annuler le rendez-vous."
9
9
  },
10
+ "nextStep": {
11
+ "code": "TEST"
12
+ },
10
13
  "exitOptions": [
11
14
  {
12
15
  "code": "CARD-1",
@@ -37,19 +40,5 @@
37
40
  }
38
41
  }
39
42
  ]
40
- },
41
- "callToActions": [
42
- {
43
- "label": "Précédent",
44
- "nextStep": "Code",
45
- "theme": "bordered-primary-02",
46
- "icon": "ArrowBack48"
47
- },
48
- {
49
- "label": "Etape suivante",
50
- "nextStep": "Code",
51
- "icon": "ArrowNext48",
52
- "iconPosition": "right"
53
- }
54
- ]
43
+ }
55
44
  }
@@ -90,7 +90,6 @@
90
90
  {{ imageTitle }}
91
91
  </div>
92
92
  </div>
93
- <div class="pb-card__image__checkbox" :class="{ active: selected }"></div>
94
93
  </div>
95
94
  <m-pb-card-selection-indicator :selectable="selectable" :selected="selected" />
96
95
  <m-pb-card-type-indicator v-if="typeIcon" :type-icon="typeIcon" />
@@ -72,44 +72,7 @@
72
72
  </div>
73
73
  </div>
74
74
 
75
- <div class="m-pb-exit-options__buttons" v-if="payload.viewModel.nextStep">
76
- <div class="m-pb-exit-options__buttons__button">
77
- <m-button
78
- v-if="payload.viewModel.backButton.nextStep"
79
- :label="payload.viewModel.backButton.label"
80
- :theme="payload.viewModel.backButton.theme"
81
- @click="goToNavigation(payload.viewModel.backButton.nextStep)"
82
- :data-cerberus="sanitizeCerberusAttribut('MPB-EXIT-OPTIONS', payload.viewModel.backButton.label)"
83
- icon="ArrowBack48"
84
- :class="{ 'js-cdl': trackingStatus }"
85
- data-cdl-click-type="cdl_event"
86
- :data-cdl-click-data="
87
- formatEvent(
88
- { button_name: payload?.viewModel?.backButton?.label || 'Précédent', button_location: stepLocation },
89
- EventTypeEnum.BUTTON,
90
- )
91
- "
92
- />
93
- </div>
94
-
95
- <div class="m-pb-exit-options__buttons__button">
96
- <m-button
97
- :label="payload.viewModel.nextStep.label"
98
- :data-cerberus="sanitizeCerberusAttribut('MPB-EXIT-OPTIONS', 'NEXT')"
99
- @click="goToNavigation(payload.viewModel.nextStep, payload.viewModel.nextStep.label)"
100
- icon="ArrowNext48"
101
- iconPosition="right"
102
- :class="{ 'js-cdl': trackingStatus }"
103
- data-cdl-click-type="cdl_event"
104
- :data-cdl-click-data="
105
- formatEvent(
106
- { button_name: payload?.viewModel?.nextStep?.label || 'Étape suivante', button_location: stepLocation },
107
- EventTypeEnum.BUTTON,
108
- )
109
- "
110
- />
111
- </div>
112
- </div>
75
+ <m-pb-navigation :nextButtonAction="payload.viewModel.nextStep" />
113
76
  </div>
114
77
  </template>
115
78
 
@@ -127,6 +90,7 @@ import DEFAULT_PAYLOAD from './default-payload.json';
127
90
  import merge from 'lodash.merge';
128
91
  import { decorate } from '@/services/decorate';
129
92
  import { formatEvent, EventTypeEnum } from '../services/event';
93
+ import MPbNavigation from '../navigation/MPbNavigation.vue';
130
94
 
131
95
  const props = defineProps({
132
96
  /**
@@ -0,0 +1,48 @@
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 MPbNavigation from './MPbNavigation';
5
+
6
+ <Meta
7
+ title="Project Booster/Rework/Navigation/MPbNavigation 🦠"
8
+ component={MPbNavigation}
9
+ argTypes={{
10
+ payload: {
11
+ table: {
12
+ defaultValue: {
13
+ summary: 'object',
14
+ detail: JSON.stringify(DEFAULT_PAYLOAD, null, ' '),
15
+ },
16
+ },
17
+ control: {
18
+ type: 'object',
19
+ },
20
+ },
21
+ }}
22
+ parameters={{
23
+ layout: 'fullscreen',
24
+ }}
25
+ />
26
+
27
+ # 🦠 `MPbNavigation` - Component
28
+
29
+ The `MPbNavigation` component to display information that user needed.
30
+
31
+ export const TemplateSandbox = (args, { argTypes }) => ({
32
+ props: Object.keys(argTypes),
33
+ components: { MPbNavigation },
34
+ setup() {
35
+ return { args };
36
+ },
37
+ template: `<div class="row-flex align-center justify-center" style="height:100vh;"><div style="width:720px; margin:auto;"><m-pb-navigation
38
+ :payload="args.payload"
39
+ /></div></div>`,
40
+ });
41
+
42
+ ## showCase
43
+
44
+ <Canvas>
45
+ <Story inline={false} height="862px" name="101 Sandbox" args={{ payload: DEFAULT_PAYLOAD }}>
46
+ {TemplateSandbox.bind({})}
47
+ </Story>
48
+ </Canvas>
@@ -0,0 +1,116 @@
1
+ <template>
2
+ <div class="m-pb-navigation row-flex justify-between">
3
+ <div class="m-pb-navigation__left">
4
+ <m-button
5
+ :label="backButtonLabel"
6
+ @click.prevent="$emit('go-back')"
7
+ theme="bordered-primary-02"
8
+ icon="ArrowBack48"
9
+ :data-cerberus="sanitizeCerberusAttribut('MPB-NAVIGATION', backButtonLabel)"
10
+ :class="{ 'js-cdl': trackingStatus }"
11
+ data-cdl-click-type="cdl_event"
12
+ :data-cdl-click-data="
13
+ formatEvent({ button_name: backButtonLabel, button_location: stepLocation }, EventTypeEnum.BUTTON)
14
+ "
15
+ />
16
+ </div>
17
+ <div class="m-pb-navigation__right">
18
+ <m-button
19
+ :label="nextButtonLabel"
20
+ @click.prevent="
21
+ $emit('next-step', {
22
+ answers,
23
+ nextStep: payload.viewModel.nextStep,
24
+ })
25
+ "
26
+ icon="ArrowNext48"
27
+ iconPosition="right"
28
+ :data-cerberus="sanitizeCerberusAttribut('MPB-NAVIGATION', nextButtonLabel)"
29
+ :class="{ 'js-cdl': trackingStatus }"
30
+ data-cdl-click-type="cdl_event"
31
+ :disabled="disabledNextButton"
32
+ :data-cdl-click-data="
33
+ formatEvent({ button_name: nextButtonLabel, button_location: stepLocation }, EventTypeEnum.BUTTON)
34
+ "
35
+ />
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <script lang="ts" setup>
41
+ import { PropType, defineEmits, defineProps } from 'vue';
42
+ import { EventTypeEnum, formatEvent } from '../services/event';
43
+ import { MButton } from '@mozaic-ds/vue-3';
44
+ import { sanitizeCerberusAttribut } from '@/services/sanitize';
45
+ import { ScenarioStepAnswer } from '@/types/pb/Scenario';
46
+ import { PayloadAction } from '../types/genericPayload';
47
+
48
+ const $emit = defineEmits(['go-back', 'next-step']);
49
+
50
+ const props = defineProps({
51
+ payload: {
52
+ type: Object,
53
+ default: () => ({}),
54
+ },
55
+ /**
56
+ * Define step location
57
+ */
58
+ stepLocation: {
59
+ type: String,
60
+ default: '',
61
+ },
62
+ /**
63
+ * The previous answers to inject
64
+ */
65
+ answers: {
66
+ type: Object as PropType<Map<string, ScenarioStepAnswer[]>>,
67
+ default: () => new Map<string, ScenarioStepAnswer[]>(),
68
+ },
69
+ /**
70
+ * Define the location of the step in the scenario.
71
+ */
72
+ trackingStatus: {
73
+ type: Boolean,
74
+ default: false,
75
+ },
76
+ /**
77
+ * Back button label
78
+ */
79
+ backButtonLabel: {
80
+ type: String,
81
+ default: 'Précédent',
82
+ },
83
+ /**
84
+ * Next button label
85
+ */
86
+ nextButtonLabel: {
87
+ type: String,
88
+ default: 'Étape suivante',
89
+ },
90
+ /**
91
+ * Next button action
92
+ */
93
+ nextButtonAction: {
94
+ type: Object as PropType<PayloadAction>,
95
+ default: {
96
+ code: '',
97
+ },
98
+ },
99
+ /**
100
+ * Enable/Disabled next button
101
+ */
102
+ disabledNextButton: {
103
+ type: Boolean,
104
+ default: false,
105
+ },
106
+ });
107
+ </script>
108
+
109
+ <style lang="scss">
110
+ @import 'pb-variables';
111
+ @import '../styles/global.scss';
112
+
113
+ .m-pb-navigation {
114
+ margin-top: $mu250;
115
+ }
116
+ </style>
@@ -228,7 +228,6 @@
228
228
  ></m-link>
229
229
  </div>
230
230
  </div>
231
-
232
231
  <pb-sticky-footer
233
232
  ref="pbStickyFooter"
234
233
  class="pb-question__sticky-footer"
@@ -237,7 +236,12 @@
237
236
  :intersection-observer-delay="250"
238
237
  >
239
238
  <transition-group name="pb-question__actions--animated" mode="out-in">
240
- <div ref="pbQuestionActionsButtonsValidate" class="pb-question__actions-container row-flex" key="validate">
239
+ <div
240
+ ref="pbQuestionActionsButtonsValidate"
241
+ class="pb-question__actions-container row-flex"
242
+ key="validate"
243
+ v-if="!payload.viewModel.disableNavigation"
244
+ >
241
245
  <div class="pb-question__actions-container__column">
242
246
  <m-button
243
247
  label="Précédent"
@@ -434,7 +438,6 @@
434
438
 
435
439
  <script lang="ts" setup>
436
440
  import { PropType, ref, computed, watch, onMounted, defineEmits } from 'vue';
437
- import { sanitizeCerberusAttribut } from '@/services/sanitize';
438
441
  import { MButton } from '@mozaic-ds/vue-3';
439
442
  import MFlexy from '../../mozaic/grid/MFlexy.vue';
440
443
  import MFlexyCol from '../../mozaic/grid/MFlexyCol.vue';
@@ -460,6 +463,7 @@ import {
460
463
  import { useStore } from 'vuex';
461
464
  import { EventTypeEnum, formatEvent } from '../services/event';
462
465
  import { callAction } from '../services/navigate';
466
+ import { sanitizeCerberusAttribut } from '@/services/sanitize';
463
467
 
464
468
  const BACK_ICON =
465
469
  'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
@@ -79,38 +79,16 @@
79
79
  Votre construction sera réalisée dans la commune de&nbsp;<strong>{{ selectedCity.name }}</strong>,&nbsp;<strong>{{ selectedCity.region }}</strong>.
80
80
  </span>
81
81
  </div>
82
- <!-- <div class="pb-city-search__buttons-container" direction="column">
83
- <m-button
84
- :disabled="!selectedCity"
85
- class="pb-city-search__button"
86
- :label="computedPayload.viewModel.actionLabel"
87
- size="l"
88
- @click="handleFormValidation"
89
- :data-cerberus="sanitizeCerberusAttribut('MPB-CITY-SEARCH', 'BUTTON')"
90
- />
91
- </div> -->
92
-
93
- <div class="pb-city-search__buttons-container row-flex align-center" v-if="payload">
94
- <div
95
- v-for="button in payload.viewModel.callToActions"
96
- class="pb-city-search__buttons-container__button row-flex"
97
- >
98
- <m-button
99
- :label="button.label"
100
- @click="callAction(button)"
101
- :theme="button.theme"
102
- :icon="button.icon"
103
- :iconPosition="button.iconPosition"
104
- style="margin-left: 1rem"
105
- :data-cerberus="sanitizeCerberusAttribut('MPB-SPACE-INPUT', button.label)"
106
- class="js-cdl"
107
- data-cdl-click-type="cdl_event"
108
- :data-cdl-click-data="
109
- formatEvent({ button_name: button.label, button_location: stepLocation }, EventTypeEnum.BUTTON)
110
- "
111
- />
112
- </div>
113
- </div>
82
+
83
+ <m-pb-navigation
84
+ :trackingStatus="trackingStatus"
85
+ :answers="answers"
86
+ :payload="payload"
87
+ :nextButtonAction="payload.viewModel.nextStep"
88
+ :disabledNextButton="!selectedCity"
89
+ @go-back="$emit('go-back')"
90
+ @next-step="nextStep"
91
+ />
114
92
  </div>
115
93
  </form>
116
94
  </template>
@@ -132,6 +110,8 @@ import { ScenarioStepAnswer } from '@/types/pb/Scenario';
132
110
  import { MButton, MLink } from '@mozaic-ds/vue-3';
133
111
  import { EventTypeEnum, formatEvent } from '../../services/event';
134
112
  import { PayloadAction } from '../../types/genericPayload';
113
+ import MPbNavigation from '../../navigation/MPbNavigation.vue';
114
+ import { callAction } from '../../services/navigate';
135
115
 
136
116
  const BACK_ICON =
137
117
  'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
@@ -144,6 +124,7 @@ export default defineComponent({
144
124
  MButton,
145
125
  MLink,
146
126
  MTextInput,
127
+ MPbNavigation,
147
128
  },
148
129
 
149
130
  props: {
@@ -184,10 +165,20 @@ export default defineComponent({
184
165
  type: Object as PropType<Map<string, ScenarioStepAnswer[]>>,
185
166
  default: () => new Map<string, ScenarioStepAnswer[]>(),
186
167
  },
168
+ /**
169
+ * Step location
170
+ */
187
171
  stepLocation: {
188
172
  type: String,
189
173
  default: '',
190
174
  },
175
+ /**
176
+ * Define the location of the step in the scenario.
177
+ */
178
+ trackingStatus: {
179
+ type: Boolean,
180
+ default: false,
181
+ },
191
182
  },
192
183
 
193
184
  data: () => ({
@@ -421,15 +412,8 @@ export default defineComponent({
421
412
  selectedCityToKeyword(): string {
422
413
  return this.selectedCity?.postalCode + ' ' + this.selectedCity?.name + ', ' + this.selectedCity?.region;
423
414
  },
424
- callAction(button: PayloadAction) {
425
- if (button.nextStep.code != '__BACK__') {
426
- this.$emit('step-completed', {
427
- answers: null,
428
- nextStep: button.code,
429
- });
430
- } else {
431
- this.$emit('go-back');
432
- }
415
+ nextStep({ answers, nextStep }: { answers: any; nextStep: any }) {
416
+ callAction(nextStep, answers, this.$emit);
433
417
  },
434
418
  sanitizeCerberusAttribut,
435
419
  formatEvent,
@@ -5,19 +5,8 @@
5
5
  "subtitle": "Cette information nous aide à identifier les aides dont vous pourriez profiter",
6
6
  "placeholder": "Code postal, ville",
7
7
  "actionLabel": "Étape suivante",
8
- "callToActions": [
9
- {
10
- "label": "Précédent",
11
- "nextStep": "Code",
12
- "theme": "bordered-primary-02",
13
- "icon": "ArrowBack48"
14
- },
15
- {
16
- "label": "Etape suivante",
17
- "nextStep": "Code",
18
- "icon": "ArrowNext48",
19
- "iconPosition": "right"
20
- }
21
- ]
8
+ "nextStep": {
9
+ "code": "CODE"
10
+ }
22
11
  }
23
12
  }
@@ -19,24 +19,13 @@
19
19
  />
20
20
  </div>
21
21
 
22
- <div class="pb-incremental-amount-input__buttons-container">
23
- <div class="pb-incremental-amount-input__buttons-container__left">
24
- <m-button
25
- label="Précédent"
26
- theme="bordered-neutral"
27
- class="pb-city-search__button"
28
- size="m"
29
- size-from-l="l"
30
- @click="$emit('go-back')"
31
- v-if="!payload.viewModel.hideBackButton"
32
- icon="ArrowBack48"
33
- >
34
- </m-button>
35
- </div>
36
- <div class="pb-incremental-amount-input__buttons-container__right">
37
- <m-button class="pb-city-search__button" :label="computedPayload.viewModel.actionLabel" size="m" />
38
- </div>
39
- </div>
22
+ <m-pb-navigation
23
+ :payload="payload"
24
+ :nextButtonAction="payload.viewModel.nextStep"
25
+ @go-back="$emit('go-back')"
26
+ @next-step="nextStep"
27
+ :answers="answers"
28
+ />
40
29
  </form>
41
30
  </div>
42
31
  </template>
@@ -45,14 +34,14 @@
45
34
  import { IncrementalAmountPayload } from '@/components/question/incremental-amount-input/IncrementalAmount';
46
35
  import { decorate } from '@/services/decorate';
47
36
  import { ScenarioStepAnswer } from '@/types/pb/Scenario';
48
- import { MButton } from '@mozaic-ds/vue-3';
49
37
  import cloneDeep from 'lodash.clonedeep';
50
38
  import merge from 'lodash.merge';
51
39
  import { ComputedRef, PropType, computed, onMounted, ref } from 'vue';
52
- import MFlex from '../../../mozaic/flex/MFlex.vue';
53
40
  import MQuantitySelector from '../../../mozaic/quantityselector/MQuantitySelector.vue';
54
41
  import { EmitEventName } from '../../services/emit';
55
42
  import DEFAULT_PAYLOAD from './default-payload.json';
43
+ import MPbNavigation from '../../navigation/MPbNavigation.vue';
44
+ import { callAction } from '../../services/navigate';
56
45
 
57
46
  const BACK_ICON =
58
47
  'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
@@ -168,6 +157,18 @@ const handleQuantitySelector = (value: number): void => {
168
157
  quantitySelector = value;
169
158
  };
170
159
 
160
+ const nextStep = ({ answers, nextStep }: { answers: any; nextStep: any }) => {
161
+ callAction(
162
+ nextStep,
163
+ [
164
+ {
165
+ value: quantitySelector,
166
+ },
167
+ ],
168
+ $emit,
169
+ );
170
+ };
171
+
171
172
  onMounted(() => {
172
173
  setTimeout(() => {
173
174
  pbIncrementalAmountInput.value?.focus();
@@ -59,39 +59,16 @@
59
59
  </div>
60
60
  </div>
61
61
 
62
- <div class="pb-space-input__buttons-container row-flex align-center" v-if="payload">
63
- <div
64
- class="pb-space-input__buttons-container__button row-flex"
65
- v-for="button in payload.viewModel.callToActions"
66
- :key="button.label"
67
- >
68
- <m-button
69
- :label="button.label"
70
- @click="callAction(button)"
71
- :disabled="button.nextStep === '__BACK__' ? false : disabledNextStep"
72
- :theme="button.theme"
73
- :icon="button.icon"
74
- :iconPosition="button.iconPosition"
75
- style="margin-left: 1rem"
76
- :data-cerberus="sanitizeCerberusAttribut('MPB-SPACE', button.label)"
77
- class="js-cdl"
78
- data-cdl-click-type="cdl_event"
79
- :data-cdl-click-data="
80
- formatEvent({ button_name: button.label, button_location: stepLocation }, EventTypeEnum.BUTTON)
81
- "
82
- />
83
- <m-link
84
- v-if="payload.skippable"
85
- class="pb-space-input__link"
86
- :label="payload.skippable.label"
87
- :theme="payload.skippable.theme"
88
- width="full"
89
- size="l"
90
- @click="skipQuestion"
91
- :data-cerberus="sanitizeCerberusAttribut('PB-SPACE-INPUT-SKIP', payload?.skippable?.label || '')"
92
- />
93
- </div>
94
- </div>
62
+ <m-pb-navigation
63
+ :payload="payload"
64
+ :answers="answers"
65
+ :disabledNextButton="disabledNextStep"
66
+ :stepLocation="stepLocation"
67
+ :nextButtonAction="payload.viewModel.nextStep"
68
+ :trackingStatus="true"
69
+ @go-back="$emit('go-back')"
70
+ @next-step="nextStep"
71
+ />
95
72
  </div>
96
73
  </form>
97
74
 
@@ -126,9 +103,9 @@ import { useForm } from 'vee-validate';
126
103
  import * as yup from 'yup';
127
104
  import MIcon from '../../../mozaic/icon/MIcon.vue';
128
105
  import { EmitEventName } from '../../services/emit';
129
- import { PayloadAction } from '../../types/genericPayload';
130
- import { EventTypeEnum, formatEvent } from '../../services/event';
131
106
  import DEFAULT_PAYLOAD from './default-payload.json';
107
+ import MPbNavigation from '../../navigation/MPbNavigation.vue';
108
+ import { callAction } from '../../services/navigate';
132
109
 
133
110
  const INFO_ICON =
134
111
  'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Notification_Information_24px.svg';
@@ -241,38 +218,15 @@ const handleFormSubmit = handleSubmit((values) => {
241
218
  ],
242
219
  });
243
220
  });
244
- const skipQuestion = () => {
245
- $emit(props.completedEventName, {
246
- answers: props.payload?.skippable?.isAnswer
247
- ? props.payload?.skippable?.defaultAnswer
248
- ? [props.payload?.skippable?.defaultAnswer]
249
- : []
250
- : null,
251
- nextStep: props.payload?.skippable?.nextStep,
252
- });
253
- };
254
-
255
- /**
256
- * Send action to completed step
257
- * @param action
258
- */
259
- const callAction = (button: PayloadAction) => {
260
- if (button.nextStep != '__BACK__') {
261
- $emit(props.completedEventName, {
262
- answers: {
263
- space: space.value,
264
- nextStep: button.code,
265
- },
266
- });
267
- } else {
268
- $emit('go-back');
269
- }
270
- };
271
221
 
272
222
  const isShowingFooter = computed(() => {
273
223
  return computedPayload.value.viewModel.footer;
274
224
  });
275
225
 
226
+ const nextStep = ({ answers, nextStep }: { answers: any; nextStep: any }) => {
227
+ callAction(nextStep, answers, $emit);
228
+ };
229
+
276
230
  onMounted(() => {
277
231
  setTimeout(() => {
278
232
  const pbSpaceInputTextInput: any = document.querySelector('.js-space-input');
@@ -12,19 +12,8 @@
12
12
  "actionLabel": "Continuer",
13
13
  "unitLabel": "m²",
14
14
  "image": null,
15
- "callToActions": [
16
- {
17
- "label": "Précédent",
18
- "nextStep": "__BACK__",
19
- "theme": "bordered-primary-02",
20
- "icon": "ArrowBack48"
21
- },
22
- {
23
- "label": "Etape suivante",
24
- "nextStep": "Code",
25
- "icon": "ArrowNext48",
26
- "iconPosition": "right"
27
- }
28
- ]
15
+ "nextStep": {
16
+ "code": "Code"
17
+ }
29
18
  }
30
19
  }
@@ -380,6 +380,10 @@ $responsive-breakpoint: 'm';
380
380
  margin: 0 auto;
381
381
  }
382
382
 
383
+ &__call {
384
+ margin-left: $mu050;
385
+ }
386
+
383
387
  &__save,
384
388
  &__call {
385
389
  width: 100%;
@@ -1,3 +1,4 @@
1
+ import { ScenarioStepAnswer } from '@/types/pb/Scenario';
1
2
  import { PayloadAction } from '../types/genericPayload';
2
3
 
3
4
  /**
@@ -6,7 +7,11 @@ import { PayloadAction } from '../types/genericPayload';
6
7
  * @param answers
7
8
  * @param $emit
8
9
  */
9
- export const callAction = (action: PayloadAction, answers: any[], $emit: any): void => {
10
+ export const callAction = (
11
+ action: PayloadAction,
12
+ answers: Map<string, ScenarioStepAnswer[]> | any,
13
+ $emit: any,
14
+ ): void => {
10
15
  if (action.code != '__BACK__') {
11
16
  $emit('step-completed', {
12
17
  answers,
@@ -28,6 +28,14 @@
28
28
  &.justify-end{
29
29
  justify-content: flex-end;
30
30
  }
31
+
32
+ &.justify-stretch{
33
+ justify-content: stretch;
34
+ }
35
+
36
+ &.justify-between{
37
+ justify-content: space-between;
38
+ }
31
39
  }
32
40
 
33
41
  .column-1of3{
@@ -59,7 +59,8 @@
59
59
  "payload": {
60
60
  "viewModel": {
61
61
  "label": "Pour aller plus loin dans votre projet de combles aménageables",
62
- "answersComponent": "MPbCard"
62
+ "answersComponent": "MPbCard",
63
+ "disableNavigation": true
63
64
  },
64
65
  "answers": {
65
66
  "ATTIC_INSULATION_DISCOVER_PRODUCTS": {
@@ -125,9 +126,7 @@
125
126
  "notification": {
126
127
  "type": "info",
127
128
  "title": "Nous attirons votre attention !",
128
- "content": "Nous ne réalisons pas de projets d’isolation de murs par l’extérieur dans les appartements. Nous vous invitons à vous rapporcher de votre copropriété pour poursuivre les démarches de rénovation énergétique.",
129
- "buttonText": "Voir d'autres solutions pour isoler vos murs extérieurs",
130
- "buttonHref": "https://www.leroymerlin.fr/produits/materiaux/isolation/isolation-par-exterieur/"
129
+ "content": "Nous ne réalisons pas de projets d’isolation de murs par l’extérieur dans les appartements. Nous vous invitons à vous rapporcher de votre copropriété pour poursuivre les démarches de rénovation énergétique."
131
130
  }
132
131
  }
133
132
  }
@@ -264,11 +263,11 @@
264
263
  "label": "Où ce situe le logement ?",
265
264
  "subtitle": "Cette information nous aide à identifier les aides dont vous pourriez profiter",
266
265
  "placeholder": "Code postal, Ville",
267
- "actionLabel": "Continuer"
266
+ "actionLabel": "Continuer",
267
+ "nextStep": {
268
+ "code": "LMFR_ATTIC_INSULATION_QUESTION_SITUATION"
269
+ }
268
270
  }
269
- },
270
- "nextStep": {
271
- "code": "LMFR_ATTIC_INSULATION_QUESTION_SITUATION"
272
271
  }
273
272
  },
274
273
  "LMFR_ATTIC_INSULATION_QUESTION_SITUATION": {
@@ -390,11 +389,11 @@
390
389
  "image": "https://storage.googleapis.com/project-booster-media/energyrenovation/number_of_inhabitants.png",
391
390
  "minValue": 1,
392
391
  "maxValue": 20,
393
- "defaultValue": 1
392
+ "defaultValue": 1,
393
+ "nextStep": {
394
+ "code": "LMFR_ATTIC_INSULATION_QUESTION_INCOME"
395
+ }
394
396
  }
395
- },
396
- "nextStep": {
397
- "code": "LMFR_ATTIC_INSULATION_QUESTION_INCOME"
398
397
  }
399
398
  },
400
399
  "LMFR_ATTIC_INSULATION_QUESTION_INCOME": {
@@ -2070,20 +2069,9 @@
2070
2069
  "label": "Quelle est la surface de combles perdus à isoler ?",
2071
2070
  "unitLabel": "m²",
2072
2071
  "placeholder": "Surface",
2073
- "callToActions": [
2074
- {
2075
- "label": "Précédent",
2076
- "nextStep": "__BACK__",
2077
- "theme": "bordered-primary-02",
2078
- "icon": "ArrowBack48"
2079
- },
2080
- {
2081
- "label": "Etape suivante",
2082
- "nextStep": "LMFR_ATTIC_INSULATION_QUESTION_INCOME",
2083
- "icon": "ArrowNext48",
2084
- "iconPosition": "right"
2085
- }
2086
- ]
2072
+ "nextStep": {
2073
+ "code": "LMFR_ATTIC_INSULATION_QUESTION_INCOME"
2074
+ }
2087
2075
  },
2088
2076
  "helpArea": [
2089
2077
  {
@@ -2098,9 +2086,6 @@
2098
2086
  }
2099
2087
  }
2100
2088
  ]
2101
- },
2102
- "nextStep": {
2103
- "code": "LMFR_ATTIC_INSULATION_QUESTION_INCOME"
2104
2089
  }
2105
2090
  },
2106
2091
 
@@ -2416,7 +2401,8 @@
2416
2401
  "payload": {
2417
2402
  "viewModel": {
2418
2403
  "label": "Pour aller plus loin dans votre projet",
2419
- "answersComponent": "MPbCard"
2404
+ "answersComponent": "MPbCard",
2405
+ "disableNavigation": true
2420
2406
  },
2421
2407
  "answers": {
2422
2408
  "DISCOVER_OUR_HEATERS": {
@@ -78,9 +78,7 @@
78
78
  "notification": {
79
79
  "type": "info",
80
80
  "title": "Nous attirons votre attention !",
81
- "content": "Nous ne réalisons pas de projets d’isolation de murs par l’extérieur dans les appartements. Nous vous invitons à vous rapporcher de votre copropriété pour poursuivre les démarches de rénovation énergétique.",
82
- "buttonText": "Voir d'autres solutions pour isoler vos murs extérieurs",
83
- "buttonHref": "https://www.leroymerlin.fr/produits/materiaux/isolation/isolation-par-exterieur/"
81
+ "content": "Nous ne réalisons pas de projets d’isolation de murs par l’extérieur dans les appartements. Nous vous invitons à vous rapporcher de votre copropriété pour poursuivre les démarches de rénovation énergétique."
84
82
  }
85
83
  }
86
84
  }
@@ -162,7 +160,8 @@
162
160
  "payload": {
163
161
  "viewModel": {
164
162
  "label": "Pour aller plus loin dans votre projet",
165
- "answersComponent": "MPbCard"
163
+ "answersComponent": "MPbCard",
164
+ "disableNavigation": true
166
165
  },
167
166
  "answers": {
168
167
  "DISCOVER_HEAT_PUMPS": {
@@ -298,11 +297,11 @@
298
297
  "subtitle": "Cette information nous aide à identifier les aides dont vous pourriez profiter",
299
298
  "placeholder": "Code postal, Ville",
300
299
  "image": "https://storage.googleapis.com/project-booster-media/new-house/Estimation%20Construction%20Neuve%20-%20Localisation.png",
301
- "actionLabel": "Continuer"
300
+ "actionLabel": "Continuer",
301
+ "nextStep": {
302
+ "code": "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_SITUATION"
303
+ }
302
304
  }
303
- },
304
- "nextStep": {
305
- "code": "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_SITUATION"
306
305
  }
307
306
  },
308
307
  "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_SITUATION": {
@@ -421,11 +420,11 @@
421
420
  "image": "https://storage.googleapis.com/project-booster-media/energyrenovation/number_of_inhabitants.png",
422
421
  "minValue": 1,
423
422
  "maxValue": 20,
424
- "defaultValue": 1
423
+ "defaultValue": 1,
424
+ "nextStep": {
425
+ "code": "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_INCOME"
426
+ }
425
427
  }
426
- },
427
- "nextStep": {
428
- "code": "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_INCOME"
429
428
  }
430
429
  },
431
430
  "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_INCOME": {
@@ -2101,7 +2100,10 @@
2101
2100
  "label": "Quelle surface sera chauffée par la pompe à chaleur ?",
2102
2101
  "unitLabel": "m²",
2103
2102
  "placeholder": "Surface",
2104
- "actionLabel": "Continuer"
2103
+ "actionLabel": "Continuer",
2104
+ "nextStep": {
2105
+ "code": "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_REPLACEMENT"
2106
+ }
2105
2107
  },
2106
2108
  "helpArea": [
2107
2109
  {
@@ -2116,9 +2118,6 @@
2116
2118
  }
2117
2119
  }
2118
2120
  ]
2119
- },
2120
- "nextStep": {
2121
- "code": "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_REPLACEMENT"
2122
2121
  }
2123
2122
  },
2124
2123
  "LMFR_HEAT_PUMP_AIR_WATER_QUESTION_REPLACEMENT": {
@@ -2626,7 +2625,8 @@
2626
2625
  "payload": {
2627
2626
  "viewModel": {
2628
2627
  "label": "Pour aller plus loin dans votre projet",
2629
- "answersComponent": "MPbCard"
2628
+ "answersComponent": "MPbCard",
2629
+ "disableNavigation": true
2630
2630
  },
2631
2631
  "answers": {
2632
2632
  "DISCOVER_OUR_HEATERS": {
@@ -162,9 +162,7 @@
162
162
  "notification": {
163
163
  "type": "info",
164
164
  "title": "Nous attirons votre attention !",
165
- "content": "Nous ne réalisons pas de projets d’isolation de murs par l’extérieur dans les appartements. Nous vous invitons à vous rapporcher de votre copropriété pour poursuivre les démarches de rénovation énergétique.",
166
- "buttonText": "Voir d'autres solutions pour isoler vos murs extérieurs",
167
- "buttonHref": "https://www.leroymerlin.fr/produits/materiaux/isolation/isolation-par-exterieur/"
165
+ "content": "Nous ne réalisons pas de projets d’isolation de murs par l’extérieur dans les appartements. Nous vous invitons à vous rapporcher de votre copropriété pour poursuivre les démarches de rénovation énergétique."
168
166
  }
169
167
  }
170
168
  }
@@ -334,24 +332,10 @@
334
332
  "label": "Dans quelle ville aura lieu les travaux ?",
335
333
  "placeholder": "Code postal, Ville",
336
334
  "actionLabel": "Continuer",
337
- "callToActions": [
338
- {
339
- "label": "Précédent",
340
- "nextStep": "__BACK__",
341
- "theme": "bordered-primary-02",
342
- "icon": "ArrowBack48"
343
- },
344
- {
345
- "label": "Etape suivante",
346
- "nextStep": "LMFR_PELLET_BOILER_QUESTION_INHABITANTS_COUNT",
347
- "icon": "ArrowNext48",
348
- "iconPosition": "right"
349
- }
350
- ]
335
+ "nextStep": {
336
+ "code": "LMFR_PELLET_BOILER_QUESTION_INHABITANTS_COUNT"
337
+ }
351
338
  }
352
- },
353
- "nextStep": {
354
- "code": "LMFR_PELLET_BOILER_QUESTION_INHABITANTS_COUNT"
355
339
  }
356
340
  },
357
341
  "LMFR_PELLET_BOILER_QUESTION_INHABITANTS_COUNT": {
@@ -379,11 +363,11 @@
379
363
  "image": "https://storage.googleapis.com/project-booster-media/energyrenovation/number_of_inhabitants.png",
380
364
  "minValue": 1,
381
365
  "maxValue": 20,
382
- "defaultValue": 1
366
+ "defaultValue": 1,
367
+ "nextStep": {
368
+ "code": "LMFR_PELLET_BOILER_QUESTION_INCOME"
369
+ }
383
370
  }
384
- },
385
- "nextStep": {
386
- "code": "LMFR_PELLET_BOILER_QUESTION_INCOME"
387
371
  }
388
372
  },
389
373
  "LMFR_PELLET_BOILER_QUESTION_INCOME": {
@@ -2257,7 +2241,8 @@
2257
2241
  "payload": {
2258
2242
  "viewModel": {
2259
2243
  "label": "Pour aller plus loin dans votre projet",
2260
- "answersComponent": "MPbCard"
2244
+ "answersComponent": "MPbCard",
2245
+ "disableNavigation": true
2261
2246
  },
2262
2247
  "answers": {
2263
2248
  "DISCOVER_OUR_HEATERS": {
@@ -2295,7 +2280,8 @@
2295
2280
  "payload": {
2296
2281
  "viewModel": {
2297
2282
  "label": "Pour aller plus loin dans votre projet",
2298
- "answersComponent": "MPbCard"
2283
+ "answersComponent": "MPbCard",
2284
+ "disableNavigation": true
2299
2285
  },
2300
2286
  "answers": {
2301
2287
  "DISCOVER_OUR_HEATERS": {
@@ -27,8 +27,7 @@
27
27
  "viewModel": {
28
28
  "label": "Estimer votre projet de rénovation énergétique en 2 minutes",
29
29
  "defaultProduct": {
30
- "designation": "Installation d'un poêle à bois",
31
- "photo": "https://storage.googleapis.com/project-booster-media/energyrenovation/default_wood_stove.jpg"
30
+ "designation": "Installation d'un poêle à bois"
32
31
  }
33
32
  },
34
33
  "callToActions": [
@@ -37,7 +36,7 @@
37
36
  "label": "Continuer",
38
37
  "action": {
39
38
  "type": "STEP",
40
- "code": "LMFR_WOOD_STOVE_QUESTION_HOUSING_TYPE"
39
+ "code": "LMFR_WOOD_STOVE_QUESTION_SITUATION"
41
40
  },
42
41
  "bordered": false
43
42
  }
@@ -79,9 +78,7 @@
79
78
  "notification": {
80
79
  "type": "info",
81
80
  "title": "Nous attirons votre attention !",
82
- "content": "Nous ne réalisons pas de projets d’isolation de murs par l’extérieur dans les appartements. Nous vous invitons à vous rapporcher de votre copropriété pour poursuivre les démarches de rénovation énergétique.",
83
- "buttonText": "Voir d'autres solutions pour isoler vos murs extérieurs",
84
- "buttonHref": "https://www.leroymerlin.fr/produits/materiaux/isolation/isolation-par-exterieur/"
81
+ "content": "Nous ne réalisons pas de projets d’isolation de murs par l’extérieur dans les appartements. Nous vous invitons à vous rapporcher de votre copropriété pour poursuivre les démarches de rénovation énergétique."
85
82
  }
86
83
  }
87
84
  }
@@ -315,24 +312,10 @@
315
312
  "subtitle": "Cette information nous aide à identifier les aides dont vous pourriez profiter",
316
313
  "placeholder": "Code postal, Ville",
317
314
  "actionLabel": "Continuer",
318
- "callToActions": [
319
- {
320
- "label": "Précédent",
321
- "nextStep": "__BACK__",
322
- "theme": "bordered-primary-02",
323
- "icon": "ArrowBack48"
324
- },
325
- {
326
- "label": "Etape suivante",
327
- "nextStep": "LMFR_WOOD_STOVE_QUESTION_SITUATION",
328
- "icon": "ArrowNext48",
329
- "iconPosition": "right"
330
- }
331
- ]
315
+ "nextStep": {
316
+ "code": "LMFR_WOOD_STOVE_QUESTION_SITUATION"
317
+ }
332
318
  }
333
- },
334
- "nextStep": {
335
- "code": "LMFR_WOOD_STOVE_QUESTION_SITUATION"
336
319
  }
337
320
  },
338
321
  "LMFR_WOOD_STOVE_QUESTION_SITUATION": {
@@ -451,11 +434,11 @@
451
434
  "image": "https://storage.googleapis.com/project-booster-media/energyrenovation/number_of_inhabitants.png",
452
435
  "minValue": 1,
453
436
  "maxValue": 20,
454
- "defaultValue": 1
437
+ "defaultValue": 1,
438
+ "nextStep": {
439
+ "code": "LMFR_WOOD_STOVE_QUESTION_INCOME"
440
+ }
455
441
  }
456
- },
457
- "nextStep": {
458
- "code": "LMFR_WOOD_STOVE_QUESTION_INCOME"
459
442
  }
460
443
  },
461
444
  "LMFR_WOOD_STOVE_QUESTION_INCOME": {
@@ -2652,15 +2635,16 @@
2652
2635
  "beforeContent": {
2653
2636
  "display": true,
2654
2637
  "component": "MPbProgress",
2655
- "totalStep": 14,
2656
- "currentStep": 1,
2638
+ "totalStep": 2,
2639
+ "currentStep": 2,
2657
2640
  "sizeXlWidth": true
2658
2641
  }
2659
2642
  },
2660
2643
  "payload": {
2661
2644
  "viewModel": {
2662
2645
  "label": "Pour aller plus loin dans votre projet",
2663
- "answersComponent": "MPbCard"
2646
+ "answersComponent": "MPbCard",
2647
+ "disableNavigation": true
2664
2648
  },
2665
2649
  "answers": {
2666
2650
  "DISCOVER_OUR_HEATERS": {
@@ -173,6 +173,7 @@ export interface ScenarioStepViewModel {
173
173
  forceBackButton?: string;
174
174
  forceOneCardPerLineOnMobile?: boolean;
175
175
  alwaysDisplaySkippable?: boolean;
176
+ disableNavigation?: boolean;
176
177
  decoratorStripe?: {
177
178
  length: string;
178
179
  };