project-booster-vue 9.25.0 → 9.28.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/cards/PbCard.vue +14 -2
- package/src/components/question/PbQuestion-Features-Answers-Conditional.stories.mdx +2 -1
- package/src/components/question/PbQuestion-Features-Answers-Modal.stories.mdx +122 -0
- package/src/components/question/PbQuestion.vue +99 -1
- package/src/components/question/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-question-/360/237/246/240-features-answers-conditional-with-modal-1-snap.png +0 -0
- package/src/components/question/city-search/PbCitySearch.vue +56 -14
- package/src/components/question/city-search/default-payload.json +1 -0
- package/src/components/question/space-input/PbSpaceInput.stories.mdx +48 -0
- package/src/components/question/space-input/PbSpaceInput.vue +88 -0
- package/src/components/question/space-input/__snapshots__/storyshots-puppeteer-test-puppeteer-ts-image-storyshots-project-booster-scenario-questions-pb-space-input-/360/237/246/240-showcase-feature-with-modal-1-snap.png +0 -0
- package/src/types/pb/Scenario.ts +7 -0
package/package.json
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
disabled ? 'pb-card--disabled' : ''
|
|
6
6
|
}${flattened ? 'pb-card--no-pointer-events' : ''} ${
|
|
7
7
|
cardMinRatio && cardMinRatio !== 'auto' ? 'm-ratio-container--' + cardMinRatio : ''
|
|
8
|
-
}`"
|
|
8
|
+
}${borderTop ? 'pb-card--border-top' : ''}`"
|
|
9
9
|
:role="!buttonLabel ? 'button' : 'article'"
|
|
10
|
-
:style="`min-height: ${cardMinHeight}`"
|
|
10
|
+
:style="`min-height: ${cardMinHeight}; border-color:${borderTop ? borderTop : null}`"
|
|
11
11
|
@click="handleCardClick"
|
|
12
12
|
>
|
|
13
13
|
<m-flex
|
|
@@ -309,6 +309,13 @@ export default defineComponent({
|
|
|
309
309
|
type: [Boolean, String],
|
|
310
310
|
default: false,
|
|
311
311
|
},
|
|
312
|
+
/**
|
|
313
|
+
* Definies if the card has a border top
|
|
314
|
+
*/
|
|
315
|
+
borderTop: {
|
|
316
|
+
type: String,
|
|
317
|
+
default: null,
|
|
318
|
+
},
|
|
312
319
|
},
|
|
313
320
|
|
|
314
321
|
computed: {
|
|
@@ -361,6 +368,11 @@ $responsive-breakpoint: 's';
|
|
|
361
368
|
overflow: hidden;
|
|
362
369
|
position: relative;
|
|
363
370
|
|
|
371
|
+
&--border-top {
|
|
372
|
+
border-top-style: solid !important;
|
|
373
|
+
border-top-width: 4px !important;
|
|
374
|
+
}
|
|
375
|
+
|
|
364
376
|
&__items-container:empty ~ &__image-container {
|
|
365
377
|
height: 100%;
|
|
366
378
|
|
|
@@ -36,7 +36,8 @@ It is possible to condition the display of certain answers according to previous
|
|
|
36
36
|
|
|
37
37
|
export const conditionalAnswersPayload = {
|
|
38
38
|
viewModel: {
|
|
39
|
-
label: '
|
|
39
|
+
label: 'Quel est votre revenu fiscal de référence annuel de votre foyer fiscal ?',
|
|
40
|
+
subtitle: 'Le revenu fiscal de référence du foyer concerne la somme des revenus des conjoints.',
|
|
40
41
|
answersComponent: 'PbCard',
|
|
41
42
|
},
|
|
42
43
|
answers: {
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { nestedAppDecorator } from '../../../.storybook/nested-app-decorator';
|
|
2
|
+
import { Story, Preview, Meta, Props, ArgsTable, Source, Canvas } from '@storybook/addon-docs';
|
|
3
|
+
import PbQuestion from './PbQuestion';
|
|
4
|
+
import { TemplateSandbox } from './PbQuestion.stories.mdx';
|
|
5
|
+
|
|
6
|
+
<Meta
|
|
7
|
+
title="Project Booster/Scenario/Questions/PbQuestion 🦠/Features/Answers/Conditional"
|
|
8
|
+
component={PbQuestion}
|
|
9
|
+
argTypes={{
|
|
10
|
+
onStepCompleted: {
|
|
11
|
+
action: 'Step completed',
|
|
12
|
+
table: { disable: true },
|
|
13
|
+
},
|
|
14
|
+
}}
|
|
15
|
+
decorators={[
|
|
16
|
+
nestedAppDecorator(
|
|
17
|
+
{
|
|
18
|
+
actions: {
|
|
19
|
+
sendEventToBus({}, payload) {
|
|
20
|
+
console.log('Event sent to bus', payload);
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
[],
|
|
25
|
+
),
|
|
26
|
+
]}
|
|
27
|
+
parameters={{
|
|
28
|
+
layout: 'fullscreen',
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
31
|
+
|
|
32
|
+
# `PbQuestion` - With Modal
|
|
33
|
+
|
|
34
|
+
export const conditionalAnswersPayload = {
|
|
35
|
+
viewModel: {
|
|
36
|
+
label: 'Quel est votre revenu fiscal de référence annuel de votre foyer fiscal ?',
|
|
37
|
+
subtitle: 'Le revenu fiscal de référence du foyer concerne la somme des revenus des conjoints.',
|
|
38
|
+
answersComponent: 'PbCard',
|
|
39
|
+
},
|
|
40
|
+
answers: {
|
|
41
|
+
'ANSWER-1': {
|
|
42
|
+
code: 'ANSWER-1',
|
|
43
|
+
conditions: [
|
|
44
|
+
"isAnswerMatching('QUESTION_1', 'QUESTION_1--ANSWER_1')",
|
|
45
|
+
"isAnswerMatching('QUESTION_2', 'QUESTION_2--ANSWER_1')",
|
|
46
|
+
],
|
|
47
|
+
viewModel: {
|
|
48
|
+
title: '15000 - 20000 €',
|
|
49
|
+
borderColor: 'orange',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
'ANSWER-2': {
|
|
53
|
+
code: 'ANSWER-2',
|
|
54
|
+
conditions: ['runtimeOptions.isElligible'],
|
|
55
|
+
viewModel: {
|
|
56
|
+
title: '20000 - 30000 €',
|
|
57
|
+
borderColor: 'red',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
'ANSWER-3': {
|
|
61
|
+
code: 'ANSWER-3',
|
|
62
|
+
viewModel: {
|
|
63
|
+
title: '30000 - 40000 €',
|
|
64
|
+
borderColor: 'purple',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
'ANSWER-4': {
|
|
68
|
+
code: 'ANSWER-4',
|
|
69
|
+
viewModel: {
|
|
70
|
+
title: 'Plus de 50000 €',
|
|
71
|
+
borderColor: 'yellow',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
helpArea: [
|
|
76
|
+
{
|
|
77
|
+
type: 'text',
|
|
78
|
+
label: 'Besoin d’aide pour trouver votre revenu fiscal de référence ?',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: 'link',
|
|
82
|
+
label: 'Voir l’aide pour trouver votre revenu fiscal',
|
|
83
|
+
action: {
|
|
84
|
+
type: 'MODAL',
|
|
85
|
+
viewModelDialog: {
|
|
86
|
+
headerTitle: 'Ou trouver votre revenu fiscal de référence ?',
|
|
87
|
+
subTitle: 'Sur votre dernier avis d’imposition disponible dans votre espace impots-gouv.fr',
|
|
88
|
+
imgUrl:
|
|
89
|
+
'https://www.lerevenu.com/sites/site/files/styles/img_lg/public/field/image/impots_7.jpg?itok=A2rlQzx3',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
<Source language="json" code={JSON.stringify(conditionalAnswersPayload, null, ' ')} />
|
|
97
|
+
|
|
98
|
+
export const conditionalAnswersAnswers = {
|
|
99
|
+
QUESTION_1: [{ code: 'QUESTION_1--ANSWER_1' }],
|
|
100
|
+
QUESTION_2: [{ code: 'QUESTION_2--ANSWER_1' }],
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const conditionalAnswersRuntimeOptions = {
|
|
104
|
+
isElligible: true,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
<Canvas>
|
|
108
|
+
<Story
|
|
109
|
+
name="With Modal"
|
|
110
|
+
inline={false}
|
|
111
|
+
height="862px"
|
|
112
|
+
parameters={{ controls: { disable: true } }}
|
|
113
|
+
args={{
|
|
114
|
+
payload: conditionalAnswersPayload,
|
|
115
|
+
answers: new Map(Object.entries(conditionalAnswersAnswers)),
|
|
116
|
+
runtimeOptions: conditionalAnswersRuntimeOptions,
|
|
117
|
+
minHeight: 'auto',
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{TemplateSandbox.bind({})}
|
|
121
|
+
</Story>
|
|
122
|
+
</Canvas>
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
:is="payload.viewModel.answersComponent"
|
|
73
73
|
v-if="payload.viewModel.answersComponent !== 'MButton'"
|
|
74
74
|
class="pb-question__answer__component"
|
|
75
|
+
:border-top="answer.viewModel.borderColor || null"
|
|
75
76
|
:image="decorate(answers, runtimeOptions, answer.viewModel.image, payload.defaultDecoratorValue)"
|
|
76
77
|
:image-title="
|
|
77
78
|
decorate(answers, runtimeOptions, answer.viewModel.imageTitle, payload.defaultDecoratorValue)
|
|
@@ -252,7 +253,59 @@
|
|
|
252
253
|
</m-flexy-col>
|
|
253
254
|
</m-flexy>
|
|
254
255
|
</m-container>
|
|
255
|
-
<div class="pb-question__padding-bottom" />
|
|
256
|
+
<div class="pb-question__padding-bottom" v-if="!payload.helpArea" />
|
|
257
|
+
<m-flex
|
|
258
|
+
class="pb-question__help"
|
|
259
|
+
v-if="payload.helpArea"
|
|
260
|
+
direction="column"
|
|
261
|
+
align-items="center"
|
|
262
|
+
justify-content="center"
|
|
263
|
+
>
|
|
264
|
+
<div v-for="helpItem in payload.helpArea" :key="helpItem.type">
|
|
265
|
+
<div v-if="helpItem.type === 'text'">
|
|
266
|
+
<p class="pb-question__help__text">{{ helpItem.label }}</p>
|
|
267
|
+
</div>
|
|
268
|
+
<div v-if="helpItem.type === 'link'">
|
|
269
|
+
<m-link
|
|
270
|
+
class="pb-question__help__link"
|
|
271
|
+
:label="helpItem.label"
|
|
272
|
+
width="full"
|
|
273
|
+
size="l"
|
|
274
|
+
theme="primary"
|
|
275
|
+
@click="handleHelpClick(helpItem.action)"
|
|
276
|
+
/>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</m-flex>
|
|
280
|
+
|
|
281
|
+
<m-dialog
|
|
282
|
+
class="pb-question__dialog-help"
|
|
283
|
+
v-model:show-dialog="displayDialogHelp"
|
|
284
|
+
width="771px"
|
|
285
|
+
height="492px"
|
|
286
|
+
maxHeight="100vh"
|
|
287
|
+
>
|
|
288
|
+
<template #header v-if="helpDialog">
|
|
289
|
+
<div class="pb-question__dialog-help__title">
|
|
290
|
+
<h2>{{ helpDialog.viewModelDialog.headerTitle }}</h2>
|
|
291
|
+
<p>{{ helpDialog.viewModelDialog.subTitle }}</p>
|
|
292
|
+
</div>
|
|
293
|
+
</template>
|
|
294
|
+
<template #body>
|
|
295
|
+
<div class="pb-question__dialog-help__body" v-if="helpDialog">
|
|
296
|
+
<div
|
|
297
|
+
:style="`background-image: url(${helpDialog.viewModelDialog.imgUrl});`"
|
|
298
|
+
class="pb-question__dialog-help__body__image"
|
|
299
|
+
/>
|
|
300
|
+
</div>
|
|
301
|
+
</template>
|
|
302
|
+
<template v-slot:footer>
|
|
303
|
+
<m-flex class="pb-question__dialog-help__footer" align-items="center" justify-content="center">
|
|
304
|
+
<m-button label="Fermer" theme="bordered-neutral" @click.prevent="displayDialogHelp = false"></m-button>
|
|
305
|
+
</m-flex>
|
|
306
|
+
</template>
|
|
307
|
+
</m-dialog>
|
|
308
|
+
|
|
256
309
|
<m-dialog class="pb-question__dialog" v-model:show-dialog="displayDialog">
|
|
257
310
|
<template #header v-if="!displayVideo">
|
|
258
311
|
<span>{{ dialog.headerTitle }}</span>
|
|
@@ -322,6 +375,7 @@ import {
|
|
|
322
375
|
ScenarioStepSkippableOptions,
|
|
323
376
|
ScenarioStepViewModel,
|
|
324
377
|
ScenarioCondition,
|
|
378
|
+
ScenarioStepDialog,
|
|
325
379
|
} from '@/types/pb/Scenario';
|
|
326
380
|
|
|
327
381
|
const BACK_ICON =
|
|
@@ -460,7 +514,9 @@ export default defineComponent({
|
|
|
460
514
|
BACK_ICON,
|
|
461
515
|
INFO_ICON,
|
|
462
516
|
displayDialog: false,
|
|
517
|
+
displayDialogHelp: false,
|
|
463
518
|
dialog: undefined as undefined | ScenarioStepAnswerDialog,
|
|
519
|
+
helpDialog: undefined as undefined | ScenarioStepDialog,
|
|
464
520
|
displayVideo: false,
|
|
465
521
|
pbQuestionActionsButtonsMaxHeight: 0,
|
|
466
522
|
decorate,
|
|
@@ -761,6 +817,19 @@ export default defineComponent({
|
|
|
761
817
|
},
|
|
762
818
|
});
|
|
763
819
|
},
|
|
820
|
+
handleHelpClick(answer: ScenarioStepDialog) {
|
|
821
|
+
this.displayDialogHelp = !this.displayDialogHelp;
|
|
822
|
+
this.helpDialog = answer ?? undefined;
|
|
823
|
+
this.$store.dispatch('sendEventToBus', {
|
|
824
|
+
code: 'LINK-CLICKED',
|
|
825
|
+
payload: {
|
|
826
|
+
context: {
|
|
827
|
+
answer: answer,
|
|
828
|
+
questionId: this.stepName,
|
|
829
|
+
},
|
|
830
|
+
},
|
|
831
|
+
});
|
|
832
|
+
},
|
|
764
833
|
},
|
|
765
834
|
});
|
|
766
835
|
</script>
|
|
@@ -1229,8 +1298,37 @@ $answers-apparition-duration: '0.5s';
|
|
|
1229
1298
|
}
|
|
1230
1299
|
}
|
|
1231
1300
|
|
|
1301
|
+
&__dialog-help {
|
|
1302
|
+
&__title {
|
|
1303
|
+
padding: $mu250 $mu250 0 $mu250;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
&__body {
|
|
1307
|
+
padding: 0 $mu250;
|
|
1308
|
+
@include set-font-scale('05', 'l');
|
|
1309
|
+
&__image {
|
|
1310
|
+
background-size: cover;
|
|
1311
|
+
padding: 120px 0;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
&__footer {
|
|
1316
|
+
padding: $mu100 $mu250 $mu250 $mu250;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1232
1320
|
&__padding-bottom {
|
|
1233
1321
|
height: $mu800;
|
|
1234
1322
|
}
|
|
1323
|
+
|
|
1324
|
+
&__help {
|
|
1325
|
+
margin-bottom: $mu250;
|
|
1326
|
+
&__link,
|
|
1327
|
+
&__text {
|
|
1328
|
+
margin: 0;
|
|
1329
|
+
@include set-font-scale('05', 'l');
|
|
1330
|
+
@include set-font-face('regular');
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1235
1333
|
}
|
|
1236
1334
|
</style>
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
<div class="pb-city-search__title">
|
|
16
16
|
{{ computedPayload.viewModel.label }}
|
|
17
17
|
</div>
|
|
18
|
+
<div v-if="computedPayload.viewModel.subtitle" class="pb-city-search__subtitle">
|
|
19
|
+
{{ computedPayload.viewModel.subtitle }}
|
|
20
|
+
</div>
|
|
18
21
|
<div class="pb-city-search__form">
|
|
19
22
|
<m-flex class="pb-city-search__header" ref="pbCitySearchHeader" direction="column">
|
|
20
23
|
<m-flex
|
|
@@ -178,6 +181,7 @@ export default defineComponent({
|
|
|
178
181
|
name: string;
|
|
179
182
|
region: string;
|
|
180
183
|
inseeCode: string;
|
|
184
|
+
postalCode: string;
|
|
181
185
|
} | null,
|
|
182
186
|
searchKeywordBackup: undefined as string | undefined,
|
|
183
187
|
displaySuggestions: false,
|
|
@@ -218,6 +222,12 @@ export default defineComponent({
|
|
|
218
222
|
this?.computedPayload?.value?.city?.inseeCode,
|
|
219
223
|
this?.computedPayload?.defaultDecoratorValue,
|
|
220
224
|
),
|
|
225
|
+
postalCode: decorate(
|
|
226
|
+
this.answers,
|
|
227
|
+
this.runtimeOptions,
|
|
228
|
+
this?.computedPayload?.value?.city?.postalCode,
|
|
229
|
+
this?.computedPayload?.defaultDecoratorValue,
|
|
230
|
+
),
|
|
221
231
|
};
|
|
222
232
|
this.searchKeyword = this?.selectedCity?.name;
|
|
223
233
|
this.forceHideSuggestions = true;
|
|
@@ -301,7 +311,6 @@ export default defineComponent({
|
|
|
301
311
|
this.focused = false;
|
|
302
312
|
this.forceHideSuggestions = true;
|
|
303
313
|
this.searchKeywordBackup = this.searchKeyword;
|
|
304
|
-
this.searchKeyword = suggestion.terms[0].value;
|
|
305
314
|
this.getPlaceDetails(suggestion.place_id);
|
|
306
315
|
setTimeout(() => {
|
|
307
316
|
this.autoFocused = true;
|
|
@@ -320,22 +329,23 @@ export default defineComponent({
|
|
|
320
329
|
const selectedCity = results[0];
|
|
321
330
|
this.suggestions = null;
|
|
322
331
|
|
|
323
|
-
const placeData = await
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
},
|
|
331
|
-
});
|
|
332
|
-
const selectedCityCode = placeData.data[0].code;
|
|
332
|
+
const placeData = await this.getPlaceFromGeoGouvAPI(
|
|
333
|
+
selectedCity.geometry.location.lat(),
|
|
334
|
+
selectedCity.geometry.location.lng(),
|
|
335
|
+
);
|
|
336
|
+
const postalCode =
|
|
337
|
+
results[0].address_components.filter((field) => field.types.includes('postal_code'))[0]?.short_name ||
|
|
338
|
+
placeData.postalCode;
|
|
333
339
|
|
|
334
340
|
this.selectedCity = {
|
|
335
|
-
inseeCode:
|
|
336
|
-
|
|
341
|
+
inseeCode: placeData.inseeCode,
|
|
342
|
+
postalCode: postalCode,
|
|
343
|
+
name: placeData.name,
|
|
337
344
|
region: selectedCity.address_components[2].short_name,
|
|
338
345
|
};
|
|
346
|
+
|
|
347
|
+
this.searchKeyword =
|
|
348
|
+
this.selectedCity.postalCode + ' ' + this.selectedCity.name + ', ' + this.selectedCity.region;
|
|
339
349
|
this.$forceUpdate();
|
|
340
350
|
}
|
|
341
351
|
});
|
|
@@ -356,6 +366,23 @@ export default defineComponent({
|
|
|
356
366
|
],
|
|
357
367
|
});
|
|
358
368
|
},
|
|
369
|
+
async getPlaceFromGeoGouvAPI(lat: number, lng: number) {
|
|
370
|
+
const placeData = await axios.get('https://geo.api.gouv.fr/communes', {
|
|
371
|
+
params: {
|
|
372
|
+
lat: lat,
|
|
373
|
+
lon: lng,
|
|
374
|
+
fields: 'nom,code,codesPostaux',
|
|
375
|
+
format: 'json',
|
|
376
|
+
geometry: 'centre',
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
return {
|
|
381
|
+
inseeCode: placeData.data[0].code,
|
|
382
|
+
postalCode: placeData.data[0].codesPostaux[0],
|
|
383
|
+
name: placeData.data[0].nom,
|
|
384
|
+
};
|
|
385
|
+
},
|
|
359
386
|
},
|
|
360
387
|
});
|
|
361
388
|
</script>
|
|
@@ -422,12 +449,27 @@ $responsive-breakpoint: 'm';
|
|
|
422
449
|
@include set-from-screen($responsive-breakpoint) {
|
|
423
450
|
@include set-font-scale('08', 'm');
|
|
424
451
|
|
|
425
|
-
padding: $
|
|
452
|
+
padding: $mu100 $mu100 $mu100 $mu100;
|
|
426
453
|
text-align: center;
|
|
427
454
|
width: auto;
|
|
428
455
|
}
|
|
429
456
|
}
|
|
430
457
|
|
|
458
|
+
&__subtitle {
|
|
459
|
+
@include set-font-scale('06', 's');
|
|
460
|
+
|
|
461
|
+
color: $color-grey-600;
|
|
462
|
+
padding-bottom: $mu100;
|
|
463
|
+
|
|
464
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
465
|
+
@include set-font-scale('06', 'm');
|
|
466
|
+
|
|
467
|
+
padding-bottom: $mu100;
|
|
468
|
+
text-align: center;
|
|
469
|
+
width: 100%;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
431
473
|
&__image {
|
|
432
474
|
margin: 0 auto;
|
|
433
475
|
padding-bottom: $mu200;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"viewModel": {
|
|
3
3
|
"backLabel": "Question précédente",
|
|
4
4
|
"label": "Dans quelle commune se situe votre projet ?",
|
|
5
|
+
"subtitle": "Cette information nous aide à identifier les aides dont vous pourriez profiter",
|
|
5
6
|
"placeholder": "Commune",
|
|
6
7
|
"actionLabel": "Continuer",
|
|
7
8
|
"image": "https://storage.googleapis.com/project-booster-media/new-house/Estimation%20Construction%20Neuve%20-%20Localisation.png"
|
|
@@ -247,3 +247,51 @@ export const customFooter = {
|
|
|
247
247
|
{TemplateSandbox.bind({})}
|
|
248
248
|
</Story>
|
|
249
249
|
</Canvas>
|
|
250
|
+
|
|
251
|
+
## With modal support
|
|
252
|
+
|
|
253
|
+
export const withModal = {
|
|
254
|
+
viewModel: {
|
|
255
|
+
validation: {
|
|
256
|
+
maxValue: 10001,
|
|
257
|
+
maxErrorMessage: 'La surface doit être comprise entre 100m² et 10 000m²',
|
|
258
|
+
minValue: 99,
|
|
259
|
+
minErrorMessage: 'La surface doit être comprise entre 100m² et 10 000m²',
|
|
260
|
+
},
|
|
261
|
+
backLabel: 'Question précédente',
|
|
262
|
+
label: 'Quelle est votre surface ?',
|
|
263
|
+
placeholder: 'Votre surface',
|
|
264
|
+
actionLabel: 'Continuer',
|
|
265
|
+
image: null,
|
|
266
|
+
},
|
|
267
|
+
helpArea: [
|
|
268
|
+
{
|
|
269
|
+
type: 'text',
|
|
270
|
+
label: 'Besoin d’aide pour calculer la surface ?',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
type: 'link',
|
|
274
|
+
label: 'Voir le guide pour calculer sa surface',
|
|
275
|
+
action: {
|
|
276
|
+
type: 'MODAL',
|
|
277
|
+
dialogViewModel: {
|
|
278
|
+
headerTitle: 'Pour calculer la surface chauffée c’est facile.',
|
|
279
|
+
htmlContent:
|
|
280
|
+
'<p>Pour calculer la surface chauffée c’est facile.</p><p> Il suffit de déduire de <strong>la surface habitable</strong> de votre habitation, <strong>les surfaces des pièces non chauffées</strong> par la pompe à chaleur. </p><p> Les pièces non chauffées peuvent être des pièces annexes (buanderie, véranda, …) ou de pièces chauffées par un autre mode de chauffage (radiateurs électriques par exemple). </p><p> <strong>Attention :</strong> le garage et le grenier ne sont pas pris en compte dans la surface habitable de base, il ne faut donc pas les déduire </p>',
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
<Source language="json" code={JSON.stringify(withModal, null, ' ')} />
|
|
288
|
+
|
|
289
|
+
<Canvas>
|
|
290
|
+
<Story
|
|
291
|
+
name="Showcase - Feature with modal"
|
|
292
|
+
parameters={{ controls: { disable: true } }}
|
|
293
|
+
args={{ payload: withModal }}
|
|
294
|
+
>
|
|
295
|
+
{TemplateSandbox.bind({})}
|
|
296
|
+
</Story>
|
|
297
|
+
</Canvas>
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
@click.once="$emit('go-back')"
|
|
13
13
|
/>
|
|
14
14
|
</m-flex>
|
|
15
|
+
|
|
15
16
|
<form
|
|
16
17
|
class="pb-space-input__form-container"
|
|
17
18
|
ref="pbSpaceInputFormContainerObserver"
|
|
@@ -57,6 +58,30 @@
|
|
|
57
58
|
</m-flexy-col>
|
|
58
59
|
</m-flex>
|
|
59
60
|
|
|
61
|
+
<m-flex
|
|
62
|
+
class="pb-space-input__help"
|
|
63
|
+
v-if="computedPayload.helpArea"
|
|
64
|
+
direction="column"
|
|
65
|
+
align-items="center"
|
|
66
|
+
justify-content="center"
|
|
67
|
+
>
|
|
68
|
+
<div v-for="helpItem in computedPayload.helpArea" :key="helpItem.type">
|
|
69
|
+
<div v-if="helpItem.type === 'text'">
|
|
70
|
+
<p class="pb-space-input__help__text">{{ helpItem.label }}</p>
|
|
71
|
+
</div>
|
|
72
|
+
<div v-if="helpItem.type === 'link'">
|
|
73
|
+
<m-link
|
|
74
|
+
class="pb-space-input__help__link"
|
|
75
|
+
:label="helpItem.label"
|
|
76
|
+
width="full"
|
|
77
|
+
size="l"
|
|
78
|
+
theme="primary"
|
|
79
|
+
@click="handleShowModal(helpItem.action.dialogViewModel)"
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</m-flex>
|
|
84
|
+
|
|
60
85
|
<m-flex class="pb-space-input__buttons-container" direction="column" align-items="center">
|
|
61
86
|
<m-button
|
|
62
87
|
class="pb-space-input__button"
|
|
@@ -77,6 +102,30 @@
|
|
|
77
102
|
</m-flex>
|
|
78
103
|
</m-flex>
|
|
79
104
|
</form>
|
|
105
|
+
|
|
106
|
+
<m-dialog
|
|
107
|
+
class="pb-space-input__dialog"
|
|
108
|
+
:show-dialog="showModal"
|
|
109
|
+
width="680px"
|
|
110
|
+
height="520px"
|
|
111
|
+
maxHeight="100vh"
|
|
112
|
+
@update:show-dialog="handleShowModal"
|
|
113
|
+
v-if="computedPayload.helpArea"
|
|
114
|
+
>
|
|
115
|
+
<template v-slot:header>
|
|
116
|
+
<div class="pb-space-input__dialog__title">
|
|
117
|
+
<h2>{{ contentModal.headerTitle }}</h2>
|
|
118
|
+
</div>
|
|
119
|
+
</template>
|
|
120
|
+
<template v-slot:body>
|
|
121
|
+
<div class="pb-space-input__dialog__body" v-html="contentModal.htmlContent"></div>
|
|
122
|
+
</template>
|
|
123
|
+
<template v-slot:footer>
|
|
124
|
+
<m-flex class="pb-space-input__dialog__footer" align-items="center" justify-content="center">
|
|
125
|
+
<m-button label="Fermer" theme="bordered-neutral" @click.prevent="handleShowModal"></m-button>
|
|
126
|
+
</m-flex>
|
|
127
|
+
</template>
|
|
128
|
+
</m-dialog>
|
|
80
129
|
</m-flex>
|
|
81
130
|
</template>
|
|
82
131
|
|
|
@@ -93,6 +142,7 @@ import MLink from '../../mozaic/link/MLink.vue';
|
|
|
93
142
|
import MTextInput from '../../mozaic/text-input/MTextInput.vue';
|
|
94
143
|
import MFlexyCol from '../../mozaic/grid/MFlexyCol.vue';
|
|
95
144
|
import MIcon from '../../mozaic/icon/MIcon.vue';
|
|
145
|
+
import MDialog from '../../mozaic/dialog/MDialog.vue';
|
|
96
146
|
import DEFAULT_PAYLOAD from './default-payload.json';
|
|
97
147
|
import { SpaceInputPayload } from '@/components/question/space-input/SpaceInput';
|
|
98
148
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
@@ -145,6 +195,7 @@ export default defineComponent({
|
|
|
145
195
|
MFlexyCol,
|
|
146
196
|
MTextInput,
|
|
147
197
|
MIcon,
|
|
198
|
+
MDialog,
|
|
148
199
|
},
|
|
149
200
|
|
|
150
201
|
props: {
|
|
@@ -194,9 +245,19 @@ export default defineComponent({
|
|
|
194
245
|
return merge(tempPayload, props.payload);
|
|
195
246
|
});
|
|
196
247
|
const pbSpaceInputTextInput = ref<HTMLElement>();
|
|
248
|
+
const showModal = ref(false);
|
|
249
|
+
const contentModal = ref({});
|
|
197
250
|
|
|
198
251
|
const space = computeDefaultValue(props.runtimeOptions, props.answers!, computedPayload);
|
|
199
252
|
|
|
253
|
+
const handleShowModal = ({ headerTitle, htmlContent }: { headerTitle: string; htmlContent: string }) => {
|
|
254
|
+
showModal.value = !showModal.value;
|
|
255
|
+
|
|
256
|
+
if (headerTitle && htmlContent) {
|
|
257
|
+
contentModal.value = { headerTitle, htmlContent };
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
200
261
|
const validationSchema = initValidation(componentId, computedPayload);
|
|
201
262
|
|
|
202
263
|
const { handleSubmit } = useForm({ validationSchema: validationSchema.value });
|
|
@@ -250,6 +311,9 @@ export default defineComponent({
|
|
|
250
311
|
handleFormSubmit,
|
|
251
312
|
isShowingFooter,
|
|
252
313
|
skipQuestion,
|
|
314
|
+
showModal,
|
|
315
|
+
handleShowModal,
|
|
316
|
+
contentModal,
|
|
253
317
|
};
|
|
254
318
|
},
|
|
255
319
|
});
|
|
@@ -382,5 +446,29 @@ $responsive-breakpoint: 'm';
|
|
|
382
446
|
&__link {
|
|
383
447
|
margin-top: $mu250;
|
|
384
448
|
}
|
|
449
|
+
|
|
450
|
+
&__dialog {
|
|
451
|
+
&__title {
|
|
452
|
+
padding: $mu250 $mu250 0 $mu250;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
&__body {
|
|
456
|
+
padding: 0 $mu250;
|
|
457
|
+
@include set-font-scale('05', 'l');
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
&__footer {
|
|
461
|
+
padding: $mu100 $mu250 $mu250 $mu250;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
&__help {
|
|
466
|
+
margin-bottom: $mu250;
|
|
467
|
+
|
|
468
|
+
&__link,
|
|
469
|
+
&__text {
|
|
470
|
+
margin: 0;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
385
473
|
}
|
|
386
474
|
</style>
|
package/src/types/pb/Scenario.ts
CHANGED
|
@@ -74,6 +74,13 @@ export interface ScenarioStepAnswer {
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
export interface ScenarioStepDialog {
|
|
78
|
+
viewModelDialog: {
|
|
79
|
+
headerTitle: string;
|
|
80
|
+
imageUrl?: string;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
77
84
|
export interface ScenarioStepAnswers {
|
|
78
85
|
answers: ScenarioStepAnswer[];
|
|
79
86
|
nextStep?: ScenarioStepNextStep;
|