project-booster-vue 10.16.4 → 10.17.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.
Files changed (41) hide show
  1. package/package.json +1 -1
  2. package/src/components/question/configurations-import/ConfigurationsImport.ts +1 -0
  3. package/src/components/rework/navigation/MPbNavigation.vue +1 -0
  4. package/src/components/rework/question/configurations-import/MPbConfigurationsImport.vue +147 -194
  5. package/src/components/rework/question/configurations-import/default-payload.json +3 -15
  6. package/src/components/rework/question/dimensions-input/DimensionsInput.ts +28 -0
  7. package/src/components/rework/question/dimensions-input/MPbDimensionsInput.stories.mdx +230 -0
  8. package/src/components/rework/question/dimensions-input/MPbDimensionsInput.vue +330 -0
  9. package/src/components/rework/question/dimensions-input/default-payload.json +19 -0
  10. package/src/components/rework/question/list-select/MPbListSelect-Answers-Multiple.stories.mdx +123 -0
  11. package/src/components/rework/question/list-select/MPbListSelect-Answers-NextStep.stories.mdx +89 -0
  12. package/src/components/rework/question/list-select/MPbListSelect-Answers-ShowMore.stories.mdx +204 -0
  13. package/src/components/rework/question/list-select/MPbListSelect-Answers-Single.stories.mdx +112 -0
  14. package/src/components/rework/question/list-select/MPbListSelect-Answers-Skippable.stories.mdx +140 -0
  15. package/src/components/rework/question/list-select/MPbListSelect.stories.mdx +132 -0
  16. package/src/components/rework/question/list-select/MPbListSelect.vue +381 -0
  17. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-101-sandbox-1-snap.png +0 -0
  18. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-features-answers-multiple-showcase-feature-multiple-1-snap.png +0 -0
  19. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-features-answers-next-step-showcase-feature-next-step-1-snap.png +0 -0
  20. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-features-answers-show-more-showcase-feature-show-more-1-snap.png +0 -0
  21. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-features-answers-show-more-showcase-show-more-color-and-position-properties-1-snap.png +0 -0
  22. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-features-answers-single-showcase-feature-single-1-snap.png +0 -0
  23. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-features-answers-skippable-showcase-feature-skippable-1-snap.png +0 -0
  24. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-showcase-mono-select-1-snap.png +0 -0
  25. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-showcase-multiselect-1-snap.png +0 -0
  26. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-showcase-multiselect-dynamic-label-1-snap.png +0 -0
  27. package/src/components/rework/question/list-select/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-list-select-/360/237/246/240-showcase-pagination-1-snap.png +0 -0
  28. package/src/components/rework/question/list-select/default-payload.json +43 -0
  29. package/src/components/rework/question/list-select/monoselect-payload.json +49 -0
  30. package/src/components/rework/question/list-select/multiselect-dynamic-label-payload.json +53 -0
  31. package/src/components/rework/question/list-select/multiselect-payload.json +51 -0
  32. package/src/components/rework/question/list-select/pagination-payload.json +71 -0
  33. package/src/components/rework/restitution/MPbRestitutionList.vue +1 -0
  34. package/src/components/rework/restitution/MPbRestitutionListLine.vue +1 -0
  35. package/src/components/rework/styles/global.scss +4 -0
  36. package/src/components/scenario/PbScenario.vue +7 -3
  37. package/src/components/scenario/scenarii/appointment-qualification-bathroom.json +39 -23
  38. package/src/components/scenario/scenarii/appointment-qualification-kitchen.json +100 -24
  39. package/src/components/scenario/scenarii/estimator-attic-insulation.json +6 -6
  40. package/src/components/scenario/scenarii/estimator-bathroom.json +7 -13
  41. package/src/components/scenario/scenarii/estimator-floor.json +59 -43
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-booster-vue",
3
- "version": "10.16.4",
3
+ "version": "10.17.0",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -30,6 +30,7 @@ export interface ConfigurationsImportViewModel {
30
30
  errorText: string;
31
31
  };
32
32
  };
33
+ nextStep: any;
33
34
  }
34
35
 
35
36
  export interface ConfigurationsImportPayload {
@@ -140,6 +140,7 @@ $responsive-breakpoint: 'm';
140
140
 
141
141
  .m-pb-navigation {
142
142
  margin-top: $mu250;
143
+ width: 100%;
143
144
 
144
145
  .m-pb-navigation__left,
145
146
  .m-pb-navigation__right {
@@ -67,24 +67,14 @@
67
67
  ></m-link>
68
68
  </div>
69
69
 
70
- <div class="pb-configurations-import__buttons row-flex" v-if="payload.callToActions">
71
- <div class="pb-configurations-import__buttons__button" v-for="button in payload.callToActions">
72
- <m-button
73
- :class="{ 'js-cdl': trackingStatus }"
74
- :label="button.label"
75
- @click="callAction(button.nextStep)"
76
- :theme="button.theme"
77
- :data-cdl-click="
78
- JSON.stringify([
79
- [
80
- 'cdl_event',
81
- formatEvent({ button_name: button.label, button_location: stepLocation }, EventTypeEnum.BUTTON),
82
- ],
83
- ])
84
- "
85
- />
86
- </div>
87
- </div>
70
+ <m-pb-navigation
71
+ :answers="answers"
72
+ :payload="payload"
73
+ :trackingStatus="trackingStatus"
74
+ @go-back="$emit('go-back')"
75
+ @next-step="callAction(payload?.viewModel?.nextStep)"
76
+ :step-number="stepNumber"
77
+ />
88
78
  </m-container>
89
79
  </div>
90
80
  <pb-configurations-search
@@ -112,16 +102,12 @@
112
102
  </div>
113
103
  </template>
114
104
 
115
- <script lang="ts">
116
- import { defineComponent, computed, ref, PropType } from 'vue';
105
+ <script lang="ts" setup>
106
+ import { computed, ref, PropType } from 'vue';
117
107
  import { useStore } from 'vuex';
118
108
  import PbConfigurationsSearch from '../../../../components/configurations/search/PbConfigurationsSearch.vue';
119
- import PbStickyFooter from '../../../../components/sticky-footer/PbStickyFooter.vue';
120
- import MButton from '../../../../components/mozaic/buttons/MButton.vue';
121
109
  import MContainer from '../../../../components/mozaic/grid/MContainer.vue';
122
110
  import MFlexy from '../../../../components/mozaic/grid/MFlexy.vue';
123
- import MFlexyCol from '../../../../components/mozaic/grid/MFlexyCol.vue';
124
- import MFlex from '../../../../components/mozaic/flex/MFlex.vue';
125
111
  import MLink from '../../../../components/mozaic/link/MLink.vue';
126
112
  import MNotification from '../../../../components/mozaic/notifications/MNotification.vue';
127
113
  import PbCard from '../../../../components/cards/PbCard.vue';
@@ -137,182 +123,149 @@ import { Configuration } from '@/types/pb/Configuration';
137
123
  import { decorate } from '@/services/decorate';
138
124
  import { PayloadAction } from '../../types/genericPayload';
139
125
  import { EventTypeEnum, formatEvent } from '../../services/event';
140
-
141
- const BACK_ICON =
142
- 'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
143
- const INFO_ICON =
144
- 'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Notification_Information_24px.svg';
145
- const ADD_ICON = 'https://storage.googleapis.com/project-booster-media/common/icons/plus--title-offset.jpg';
146
-
147
- export default defineComponent({
148
- name: 'pbConfigurationsImport',
149
- components: {
150
- PbCard,
151
- MButton,
152
- MContainer,
153
- MFlexyCol,
154
- MFlexy,
155
- MFlex,
156
- MLink,
157
- MNotification,
158
- PbConfigurationsSearch,
159
- PbStickyFooter,
126
+ import MPbNavigation from '../../navigation/MPbNavigation.vue';
127
+
128
+ const emit: any = defineEmits();
129
+
130
+ const props = defineProps({
131
+ /**
132
+ * The component view model and business data as an object. The provided props
133
+ * is merged with the default payload value so only overridden values will change
134
+ * from the default ones.
135
+ */
136
+ payload: {
137
+ type: Object as PropType<ConfigurationsImportPayload>,
138
+ default: () => null,
139
+ required: true,
160
140
  },
161
- props: {
162
- /**
163
- * The component view model and business data as an object. The provided props
164
- * is merged with the default payload value so only overridden values will change
165
- * from the default ones.
166
- */
167
- payload: {
168
- type: Object as PropType<ConfigurationsImportPayload>,
169
- default: () => null,
170
- required: true,
171
- },
172
- /**
173
- * The options provided at runtime to customize component behaviour
174
- */
175
- runtimeOptions: {
176
- type: Object,
177
- default: () => ({}),
178
- },
179
- /**
180
- * Flag indicating whether the back button should be displayed
181
- */
182
- showBackButton: {
183
- type: Boolean,
184
- default: true,
185
- },
186
- /**
187
- * Name for the event to send when the question is answered
188
- */
189
- completedEventName: {
190
- type: String,
191
- default: 'step-completed',
192
- },
193
- /**
194
- * The previous answers to inject
195
- */
196
- answers: {
197
- type: Object as PropType<Map<string, ScenarioStepAnswer[]>>,
198
- default: () => new Map<string, ScenarioStepAnswer[]>(),
199
- },
200
- /**
201
- * Define the offset for question sticky bottom elements.
202
- *
203
- * _Use any value for the [`top` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/top)_
204
- */
205
- stickyBottomOffset: {
206
- type: String,
207
- default: '0px',
208
- },
209
- /**
210
- * Step location
211
- */
212
- stepLocation: {
213
- type: String,
214
- default: '',
215
- },
216
- /**
217
- * Define the location of the step in the scenario.
218
- */
219
- trackingStatus: {
220
- type: Boolean,
221
- default: false,
222
- },
141
+ /**
142
+ * The options provided at runtime to customize component behaviour
143
+ */
144
+ runtimeOptions: {
145
+ type: Object,
146
+ default: () => ({}),
223
147
  },
148
+ /**
149
+ * Flag indicating whether the back button should be displayed
150
+ */
151
+ showBackButton: {
152
+ type: Boolean,
153
+ default: true,
154
+ },
155
+ /**
156
+ * Name for the event to send when the question is answered
157
+ */
158
+ completedEventName: {
159
+ type: String,
160
+ default: 'step-completed',
161
+ },
162
+ /**
163
+ * The previous answers to inject
164
+ */
165
+ answers: {
166
+ type: Object as PropType<Map<string, ScenarioStepAnswer[]>>,
167
+ default: () => new Map<string, ScenarioStepAnswer[]>(),
168
+ },
169
+ /**
170
+ * Define the offset for question sticky bottom elements.
171
+ *
172
+ * _Use any value for the [`top` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/top)_
173
+ */
174
+ stickyBottomOffset: {
175
+ type: String,
176
+ default: '0px',
177
+ },
178
+ /**
179
+ * Step location
180
+ */
181
+ stepLocation: {
182
+ type: String,
183
+ default: '',
184
+ },
185
+ /**
186
+ * Define the location of the step in the scenario.
187
+ */
188
+ trackingStatus: {
189
+ type: Boolean,
190
+ default: false,
191
+ },
192
+ /**
193
+ * Current step number
194
+ */
195
+ stepNumber: {
196
+ type: Number,
197
+ default: 0,
198
+ },
199
+ });
224
200
 
225
- setup(props, { emit }) {
226
- const store = useStore();
227
- const projectId = computed(() => store.getters['configurations/getCurrentProjectId']);
228
- const selectedConfigurations = computed(() => store.getters['configurations/getConfigurations']);
229
- const showImportConfigurationDialog = ref(false);
230
- const configurationImportSuccess = ref(false);
231
- const configurationImportError = ref(false);
232
-
233
- const navigateTo = (viewModel: ConfigurationsImportViewModel) => {
234
- if (viewModel.backLink) {
235
- (<any>window).location = decorate(props.answers, props.runtimeOptions, viewModel.backLink);
236
- } else {
237
- /**
238
- * Emitted when go back link is clicked
239
- * @event go-back
240
- */
241
- emit('go-back');
242
- }
243
- };
201
+ const store = useStore();
202
+ const projectId = computed(() => store.getters['configurations/getCurrentProjectId']);
203
+ const selectedConfigurations = computed(() => store.getters['configurations/getConfigurations']);
204
+ const showImportConfigurationDialog = ref(false);
205
+ const configurationImportSuccess = ref(false);
206
+ const configurationImportError = ref(false);
207
+
208
+ const navigateTo = (viewModel: ConfigurationsImportViewModel) => {
209
+ if (viewModel.backLink) {
210
+ (<any>window).location = decorate(props.answers, props.runtimeOptions, viewModel.backLink);
211
+ } else {
212
+ /**
213
+ * Emitted when go back link is clicked
214
+ * @event go-back
215
+ */
216
+ emit('go-back');
217
+ }
218
+ };
244
219
 
245
- const displayConfigurationDialog = () => {
246
- showImportConfigurationDialog.value = true;
247
- };
220
+ const displayConfigurationDialog = () => {
221
+ showImportConfigurationDialog.value = true;
222
+ };
248
223
 
249
- const importConfiguration = async (configuration: Configuration) => {
250
- showImportConfigurationDialog.value = false;
251
- await store.dispatch('configurations/importConfiguration', configuration);
252
- await store.dispatch('configurations/searchConfigurations', projectId.value);
224
+ const importConfiguration = async (configuration: Configuration) => {
225
+ showImportConfigurationDialog.value = false;
226
+ await store.dispatch('configurations/importConfiguration', configuration);
227
+ await store.dispatch('configurations/searchConfigurations', projectId.value);
253
228
 
254
- if (store.getters['configurations/getConfigurationImportSuccess']) {
255
- configurationImportSuccess.value = true;
256
- } else if (store.getters['configurations/getConfigurationImportError']) {
257
- configurationImportError.value = true;
258
- }
259
- };
260
-
261
- const formatDate = (date: string) => {
262
- return format(new Date(date), 'dd/MM/yyyy');
263
- };
264
-
265
- const emitRefreshConfigurationEvent = () => {
266
- store.dispatch('configurations/loadConfigurations', { projectId: projectId.value });
267
- };
268
-
269
- const skipQuestion = (button: ConfigurationsImportSkippable) => {
270
- store.dispatch('sendEventToBus', { code: 'SKIP-IMPORT-SIMULATIONS', payload: { projectId: projectId.value } });
271
- emit(props.completedEventName, {
272
- answers: {},
273
- nextStep: button.nextStep,
274
- });
275
- };
276
-
277
- const validMultiSelect = (multiSelectOptions: ConfigurationsImportMultiSelectAction) => {
278
- emit(props.completedEventName, {
279
- answers: selectedConfigurations.value,
280
- nextStep: multiSelectOptions.nextStep,
281
- });
282
- };
283
-
284
- const callAction = (action: PayloadAction) => {
285
- if (action.code != '__BACK__') {
286
- emit('step-completed', {
287
- answers: [],
288
- nextStep: action,
289
- });
290
- } else {
291
- emit('go-back');
292
- }
293
- };
294
-
295
- return {
296
- ADD_ICON,
297
- BACK_ICON,
298
- INFO_ICON,
299
- navigateTo,
300
- displayConfigurationDialog,
301
- importConfiguration,
302
- formatDate,
303
- emitRefreshConfigurationEvent,
304
- skipQuestion,
305
- validMultiSelect,
306
- showImportConfigurationDialog,
307
- selectedConfigurations,
308
- configurationImportSuccess,
309
- configurationImportError,
310
- callAction,
311
- EventTypeEnum,
312
- formatEvent,
313
- };
314
- },
315
- });
229
+ if (store.getters['configurations/getConfigurationImportSuccess']) {
230
+ configurationImportSuccess.value = true;
231
+ } else if (store.getters['configurations/getConfigurationImportError']) {
232
+ configurationImportError.value = true;
233
+ }
234
+ };
235
+
236
+ const formatDate = (date: string) => {
237
+ return format(new Date(date), 'dd/MM/yyyy');
238
+ };
239
+
240
+ const emitRefreshConfigurationEvent = () => {
241
+ store.dispatch('configurations/loadConfigurations', { projectId: projectId.value });
242
+ };
243
+
244
+ const skipQuestion = (button: ConfigurationsImportSkippable) => {
245
+ store.dispatch('sendEventToBus', { code: 'SKIP-IMPORT-SIMULATIONS', payload: { projectId: projectId.value } });
246
+ emit(props.completedEventName, {
247
+ answers: {},
248
+ nextStep: button.nextStep,
249
+ });
250
+ };
251
+
252
+ const validMultiSelect = (multiSelectOptions: ConfigurationsImportMultiSelectAction) => {
253
+ emit(props.completedEventName, {
254
+ answers: selectedConfigurations.value,
255
+ nextStep: multiSelectOptions.nextStep,
256
+ });
257
+ };
258
+
259
+ const callAction = (action: PayloadAction) => {
260
+ if (action.code != '__BACK__') {
261
+ emit('step-completed', {
262
+ answers: [],
263
+ nextStep: action,
264
+ });
265
+ } else {
266
+ emit('go-back');
267
+ }
268
+ };
316
269
  </script>
317
270
 
318
271
  <style lang="scss" scoped>
@@ -13,23 +13,11 @@
13
13
  "errorTitle": "Le plan 3D n’a pas pu être importé",
14
14
  "errorText": "Une erreur est survenue"
15
15
  }
16
- }
17
- },
18
- "callToActions": [
19
- {
20
- "label": "Précédent",
21
- "theme": "bordered-primary-02",
22
- "nextStep": {
23
- "code": "__BACK__"
24
- }
25
16
  },
26
- {
27
- "label": "Suivant",
28
- "nextStep": {
29
- "code": "LMFR_BATHROOM_DOWNLOAD"
30
- }
17
+ "nextStep": {
18
+ "code": "LMFR_BATHROOM_DOWNLOAD"
31
19
  }
32
- ],
20
+ },
33
21
  "skippable": [
34
22
  {
35
23
  "isAnswer": true,
@@ -0,0 +1,28 @@
1
+ export interface DimensionsInputValidation {
2
+ lengthMinValue?: number;
3
+ lengthMaxValue?: number;
4
+ widthMinValue?: number;
5
+ widthMaxValue?: number;
6
+ lengthMaxErrorMessage?: string;
7
+ lengthMinErrorMessage?: string;
8
+ widthMaxErrorMessage?: string;
9
+ widthMinErrorMessage?: string;
10
+ requiredErrorMessage?: string;
11
+ thresholdsIncluded?: boolean;
12
+ }
13
+
14
+ export interface DimensionsInputViewModel {
15
+ label?: string;
16
+ image?: string;
17
+ backLabel?: string;
18
+ lengthPlaceholder?: string;
19
+ widthPlaceholder?: string;
20
+ actionLabel?: string;
21
+ validation: DimensionsInputValidation;
22
+ }
23
+
24
+ export interface DimensionsInputPayload {
25
+ viewModel: DimensionsInputViewModel;
26
+ value?: { length: string; width: string };
27
+ defaultDecoratorValue?: string;
28
+ }
@@ -0,0 +1,230 @@
1
+ import { nestedAppDecorator } from '../../../../../.storybook/nested-app-decorator';
2
+ import { ArgsTable, Canvas, Meta, Source, Story } from '@storybook/addon-docs';
3
+ import MPbDimensionsInput from './MPbDimensionsInput';
4
+ import DEFAULT_PAYLOAD from './default-payload.json';
5
+
6
+ <Meta
7
+ title="Project Booster/Rework/Questions/MPbDimensionsInput 🦠"
8
+ component={MPbDimensionsInput}
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
+ 'dynamic event name according to completedEventName prop': {
22
+ table: {
23
+ defaultValue: {
24
+ summary: 'Event payload',
25
+ detail: JSON.stringify({ answers: [{ projectName: 'My project name', optin: false }] }, null, ' '),
26
+ },
27
+ },
28
+ },
29
+ 'onStepCompleted': {
30
+ action: 'Step completed',
31
+ table: { disable: true },
32
+ },
33
+ }}
34
+ decorators={[nestedAppDecorator({}, [])]}
35
+ parameters={{ layout: 'fullscreen' }}
36
+ />
37
+
38
+ # 🦠 `MPbDimensionsInput` - Components
39
+
40
+ [![alt text](https://storage.googleapis.com/project-booster-media/project-booster-vue/project-booster-sources.svg 'Project booster component source code')](https://github.com/adeo/project-booster-vue/tree/master/src/components/question)
41
+
42
+ ---
43
+
44
+ The `MPbDimensionsInput` Vue component allows to fill multiple dimension. It
45
+ is customizable through the payload property. It has the same
46
+ behaviour as the `PbQuestion` component and is designed to work in scenarii.
47
+
48
+ It has a default provided payload, used in the Sandbox below.
49
+
50
+ The input field is automatically focused.
51
+
52
+ The back button will make `vue-router` trigger the history back feature from the browser. It can be hidden with the
53
+ `showBackButton` flag.
54
+
55
+ # `MPbDimensionsInput` - Component props
56
+
57
+ export const TemplateSandbox = (args, { argTypes }) => ({
58
+ props: Object.keys(argTypes),
59
+ components: { MPbDimensionsInput },
60
+ setup() {
61
+ return { args };
62
+ },
63
+ template: `<m-pb-dimensions-input
64
+ style="width:720px; margin:0 auto;"
65
+ :payload="args.payload"
66
+ :show-back-button="args.showBackButton"
67
+ :answers="args.answers"
68
+ :runtime-options="args.runtimeOptions"
69
+ :completed-event-name="args.completedEventName"
70
+ @step-completed="args.onStepCompleted"
71
+ />`,
72
+ });
73
+
74
+ <Canvas>
75
+ <Story name="101 Sandbox" args={{ payload: DEFAULT_PAYLOAD }}>
76
+ {TemplateSandbox.bind({})}
77
+ </Story>
78
+ </Canvas>
79
+
80
+ <ArgsTable story="101 Sandbox" />
81
+
82
+ # `MPbDimensionsInput` - Features
83
+
84
+ ## Customization
85
+
86
+ It is possible to customize the component default behaviour by **overriding** a property in the provided `payload` property.
87
+
88
+ Here is the default payload:
89
+
90
+ <Source language="json" code={JSON.stringify(DEFAULT_PAYLOAD, null, ' ')} />
91
+
92
+ Here is the payload with overridden values:
93
+
94
+ export const overridenLabelsPayload = {
95
+ viewModel: {
96
+ backLabel: 'Retour',
97
+ label: 'Quelles sont les dimensions de cette pièce ?',
98
+ lengthPlaceholder: 'Longueur',
99
+ widthPlaceholder: 'Largeur',
100
+ actionLabel: 'Valider',
101
+ image: 'https://upload.wikimedia.org/wikipedia/commons/f/f8/Lille_vue_gd_place.JPG',
102
+ },
103
+ };
104
+
105
+ <Source language="json" code={JSON.stringify(overridenLabelsPayload, null, ' ')} />
106
+
107
+ <Canvas>
108
+ <Story
109
+ name="Showcase - feature customize"
110
+ parameters={{ controls: { disable: true } }}
111
+ args={{ payload: overridenLabelsPayload }}
112
+ >
113
+ {TemplateSandbox.bind({})}
114
+ </Story>
115
+ </Canvas>
116
+
117
+ ## Value injection from a previous answer with default value fallback
118
+
119
+ It is possible to inject a value for the component from a previous answer. To do so, add a `value` to the component
120
+ `payload`. The value should have the same structure as the component anwser when completed (See event payload in the
121
+ [Sandbox story](#pbamountinput---component-props)) :
122
+
123
+ export const valuePayload = {
124
+ value: {
125
+ length: "${getAnswerValue('LMFR_PREVIOUS_QUESTION', 'pathForLength')}",
126
+ width: "${getAnswerValue('LMFR_PREVIOUS_QUESTION', 'pathForWidth')}",
127
+ },
128
+ };
129
+
130
+ The `getAnswerValue` function allows to retrieve a value from one provided answer. To retrieve a value, the first
131
+ parameter is the answer Id, the second is an optionnal path to extract a spcific value.
132
+
133
+ <Source language="json" code={JSON.stringify(valuePayload, null, ' ')} />
134
+
135
+ A `defaultDecoratorValue` value can be added as a fallback when no previous answer is found. When no default value is provided and no answer
136
+ is found, the component value will be empty :
137
+
138
+ export const valueWithFallbackPayload = {
139
+ defaultDecoratorValue: {
140
+ length: '2',
141
+ width: '2.5',
142
+ },
143
+ value: {
144
+ length: "${getAnswerValue('LMFR_PREVIOUS_QUESTION', 'pathForLength') || defaultValue.length}",
145
+ width: "${getAnswerValue('LMFR_PREVIOUS_QUESTION', 'pathForWidth') || defaultValue.width}",
146
+ },
147
+ };
148
+
149
+ <Source language="json" code={JSON.stringify(valueWithFallbackPayload, null, ' ')} />
150
+
151
+ The `getAnswerValue` function allows to retrieve a value from one provided answer. To retrieve a value, the first
152
+ parameter is the answer's id, the second is an optional path to extract a specific value.
153
+
154
+ It will try to find a value in a previous answer for a question with id `LMFR_PREVIOUS_QUESTION`,
155
+ provided thanks to the `answers` prop. If no value is found, it will use the `defaultDecoratorValue` as a fallback.
156
+
157
+ export const previousAnswers = {
158
+ LMFR_PREVIOUS_QUESTION: [
159
+ {
160
+ pathForLength: '4.56',
161
+ pathForWidth: '7.89',
162
+ },
163
+ ],
164
+ };
165
+
166
+ <Source language="json" code={JSON.stringify(previousAnswers, null, ' ')} />
167
+
168
+ <Canvas>
169
+ <Story
170
+ name="Showcase - Feature previous value from answer"
171
+ parameters={{ controls: { disable: true } }}
172
+ args={{
173
+ payload: valuePayload,
174
+ answers: new Map(Object.entries(previousAnswers)),
175
+ }}
176
+ >
177
+ {TemplateSandbox.bind({})}
178
+ </Story>
179
+ </Canvas>
180
+
181
+ When no answer is found, the default value fallback is used:
182
+
183
+ <Canvas>
184
+ <Story
185
+ name="Showcase - Feature previous value from default"
186
+ parameters={{ controls: { disable: true } }}
187
+ args={{ payload: valueWithFallbackPayload }}
188
+ >
189
+ {TemplateSandbox.bind({})}
190
+ </Story>
191
+ </Canvas>
192
+
193
+ ## Custom validation
194
+
195
+ It is possible to customize the input field validation. To do so, provide a `validation` property to the `viewModel`.
196
+
197
+ The default `validation` object is:
198
+
199
+ <Source language="json" code={JSON.stringify(DEFAULT_PAYLOAD.viewModel.validation, null, ' ')} />
200
+
201
+ It is possible to customize those values:
202
+
203
+ export const customValidation = {
204
+ viewModel: {
205
+ validation: {
206
+ lengthMinValue: 1,
207
+ lengthMaxValue: 10,
208
+ thresholdsIncluded: true,
209
+ widthMinValue: 1,
210
+ widthMaxValue: 10,
211
+ lengthMaxErrorMessage: 'La longueur doit être inférieure à 10m',
212
+ lengthMinErrorMessage: 'La longueur doit être supérieure à 1m',
213
+ widthMaxErrorMessage: 'La largeur doit être inférieure à 10m',
214
+ widthMinErrorMessage: 'La largeur doit être supérieure à 1m',
215
+ notValidNumberMessage: 'Veuillez ne saisir que des chiffres',
216
+ },
217
+ },
218
+ };
219
+
220
+ <Source language="json" code={JSON.stringify(customValidation, null, ' ')} />
221
+
222
+ <Canvas>
223
+ <Story
224
+ name="Showcase - Feature custom validation"
225
+ parameters={{ controls: { disable: true }, storyshots: { disable: true } }}
226
+ args={{ payload: customValidation }}
227
+ >
228
+ {TemplateSandbox.bind({})}
229
+ </Story>
230
+ </Canvas>