project-booster-vue 10.0.0-beta.2 → 10.0.1
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/products/MPbProducts.vue +7 -5
- package/src/components/rework/question/MPbQuestion.vue +62 -26
- package/src/components/rework/question/space-input/MPbSpaceInput.vue +1 -1
- package/src/components/rework/question/upload-document/MPbUploadDocument.vue +2 -3
- package/src/components/scenario/PbScenario-Estimator-Solar-Panel.stories.mdx +245 -0
- package/src/components/scenario/scenarii/appointment-qualification-bathroom.json +139 -239
- package/src/components/scenario/scenarii/solar-panel.json +644 -0
package/package.json
CHANGED
|
@@ -100,11 +100,13 @@ const props = defineProps({
|
|
|
100
100
|
* onMounted load product and load this
|
|
101
101
|
*/
|
|
102
102
|
onMounted(() => {
|
|
103
|
-
store.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
if (store.hasModule('products/loadProduct')) {
|
|
104
|
+
store.dispatch('products/loadProduct', {
|
|
105
|
+
payload: props.payload.viewModel.defaultProduct,
|
|
106
|
+
storeId: metadata && metadata.storeId ? metadata.storeId : '',
|
|
107
|
+
});
|
|
108
|
+
product.value = store.getters['products/getCurrentProduct'];
|
|
109
|
+
}
|
|
108
110
|
});
|
|
109
111
|
|
|
110
112
|
/**
|
|
@@ -123,6 +123,26 @@
|
|
|
123
123
|
/>
|
|
124
124
|
</m-flex>
|
|
125
125
|
</m-flexy>
|
|
126
|
+
|
|
127
|
+
<!-- Help link/modal -->
|
|
128
|
+
<m-flex class="pb-question__help" v-if="payload.helpArea" direction="column">
|
|
129
|
+
<div v-for="helpItem in payload.helpArea" :key="helpItem.type">
|
|
130
|
+
<div v-if="helpItem.type === 'text'">
|
|
131
|
+
<p class="pb-question__help__text">{{ helpItem.label }}</p>
|
|
132
|
+
</div>
|
|
133
|
+
<div v-if="helpItem.type === 'link'">
|
|
134
|
+
<m-link
|
|
135
|
+
class="pb-question__help__link"
|
|
136
|
+
:label="helpItem.label"
|
|
137
|
+
width="full"
|
|
138
|
+
size="l"
|
|
139
|
+
theme="primary"
|
|
140
|
+
@click="handleHelpClick(helpItem.action)"
|
|
141
|
+
/>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</m-flex>
|
|
145
|
+
|
|
126
146
|
<m-notification class="pb-question__notifications" :type="notification.type" v-if="notification">
|
|
127
147
|
<template #default>
|
|
128
148
|
<strong style="font-size: 16px; line-height: 20px">{{ notification.title }}</strong>
|
|
@@ -180,6 +200,7 @@
|
|
|
180
200
|
></m-link>
|
|
181
201
|
</div>
|
|
182
202
|
</div>
|
|
203
|
+
|
|
183
204
|
<pb-sticky-footer
|
|
184
205
|
ref="pbStickyFooter"
|
|
185
206
|
class="pb-question__sticky-footer"
|
|
@@ -202,7 +223,7 @@
|
|
|
202
223
|
>
|
|
203
224
|
</m-button>
|
|
204
225
|
</div>
|
|
205
|
-
<div class="pb-question__actions-container__column" v-if="!skippables">
|
|
226
|
+
<div class="pb-question__actions-container__column" v-if="!skippables || hasAnswersSelected">
|
|
206
227
|
<m-button
|
|
207
228
|
class="pb-question__actions-buttons-button"
|
|
208
229
|
size="m"
|
|
@@ -211,9 +232,10 @@
|
|
|
211
232
|
iconPosition="right"
|
|
212
233
|
label="Etape suivante"
|
|
213
234
|
@click="validMultiSelect(payload?.multiSelect?.actions?.VALIDATE)"
|
|
235
|
+
:disabled="!hasAnswersSelected"
|
|
214
236
|
/>
|
|
215
237
|
</div>
|
|
216
|
-
<div v-else class="pb-question__actions-container__column">
|
|
238
|
+
<div v-else-if="skippables && !hasAnswersSelected" class="pb-question__actions-container__column">
|
|
217
239
|
<m-button
|
|
218
240
|
v-for="button in skippables"
|
|
219
241
|
:key="button?.label"
|
|
@@ -246,24 +268,6 @@
|
|
|
246
268
|
</m-flexy-col>
|
|
247
269
|
</m-flexy>
|
|
248
270
|
</m-container>
|
|
249
|
-
<div class="pb-question__padding-bottom" v-if="!payload.helpArea" />
|
|
250
|
-
<m-flex class="pb-question__help" v-if="payload.helpArea" direction="column">
|
|
251
|
-
<div v-for="helpItem in payload.helpArea" :key="helpItem.type">
|
|
252
|
-
<div v-if="helpItem.type === 'text'">
|
|
253
|
-
<p class="pb-question__help__text">{{ helpItem.label }}</p>
|
|
254
|
-
</div>
|
|
255
|
-
<div v-if="helpItem.type === 'link'">
|
|
256
|
-
<m-link
|
|
257
|
-
class="pb-question__help__link"
|
|
258
|
-
:label="helpItem.label"
|
|
259
|
-
width="full"
|
|
260
|
-
size="l"
|
|
261
|
-
theme="primary"
|
|
262
|
-
@click="handleHelpClick(helpItem.action)"
|
|
263
|
-
/>
|
|
264
|
-
</div>
|
|
265
|
-
</div>
|
|
266
|
-
</m-flex>
|
|
267
271
|
|
|
268
272
|
<m-modal
|
|
269
273
|
:modalTitle="notification?.modal?.title"
|
|
@@ -282,6 +286,7 @@
|
|
|
282
286
|
:modalTitle="helpDialog?.viewModelDialog.headerTitle"
|
|
283
287
|
:open="displayDialogHelp"
|
|
284
288
|
@update:open="displayDialogHelp = false"
|
|
289
|
+
class="mc-modal--overflow"
|
|
285
290
|
v-if="helpDialog"
|
|
286
291
|
>
|
|
287
292
|
<template #default>
|
|
@@ -531,7 +536,7 @@ export default defineComponent({
|
|
|
531
536
|
this.updateSelectedAnswers();
|
|
532
537
|
this.updatePbQuestionActionsButtonsSizeHeight();
|
|
533
538
|
this.progressBar = this.payload.viewModel?.progressBar || false;
|
|
534
|
-
this.widthXlSize = this.payload.viewModel?.widthXlSize ||
|
|
539
|
+
this.widthXlSize = this.payload.viewModel?.widthXlSize || true;
|
|
535
540
|
this.notification = this.payload.viewModel.notification || undefined;
|
|
536
541
|
},
|
|
537
542
|
|
|
@@ -1062,7 +1067,7 @@ $answers-apparition-duration: '0.5s';
|
|
|
1062
1067
|
display: flex;
|
|
1063
1068
|
flex-wrap: wrap;
|
|
1064
1069
|
justify-content: flex-start;
|
|
1065
|
-
margin: 0 auto
|
|
1070
|
+
margin: 0 auto;
|
|
1066
1071
|
max-width: 1024px;
|
|
1067
1072
|
width: 100%;
|
|
1068
1073
|
|
|
@@ -1186,11 +1191,36 @@ $answers-apparition-duration: '0.5s';
|
|
|
1186
1191
|
}
|
|
1187
1192
|
|
|
1188
1193
|
&__column {
|
|
1189
|
-
width:
|
|
1194
|
+
width: 100%;
|
|
1195
|
+
|
|
1196
|
+
& > button {
|
|
1197
|
+
width: 100%;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
1201
|
+
width: 50%;
|
|
1202
|
+
|
|
1203
|
+
& > button {
|
|
1204
|
+
width: auto;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1190
1207
|
|
|
1191
1208
|
&:last-child {
|
|
1192
1209
|
display: flex;
|
|
1193
|
-
|
|
1210
|
+
margin-bottom: $mu050;
|
|
1211
|
+
|
|
1212
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
1213
|
+
justify-content: flex-end !important;
|
|
1214
|
+
order: 2;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
&:first-child {
|
|
1219
|
+
order: 2;
|
|
1220
|
+
|
|
1221
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
1222
|
+
order: 1;
|
|
1223
|
+
}
|
|
1194
1224
|
}
|
|
1195
1225
|
}
|
|
1196
1226
|
|
|
@@ -1360,11 +1390,11 @@ $answers-apparition-duration: '0.5s';
|
|
|
1360
1390
|
}
|
|
1361
1391
|
|
|
1362
1392
|
&__help {
|
|
1363
|
-
margin-bottom: $
|
|
1393
|
+
margin-bottom: $mu100;
|
|
1364
1394
|
|
|
1365
1395
|
@include set-from-screen($responsive-breakpoint) {
|
|
1366
1396
|
max-width: 554px;
|
|
1367
|
-
|
|
1397
|
+
padding: $mu100;
|
|
1368
1398
|
text-align: left;
|
|
1369
1399
|
}
|
|
1370
1400
|
|
|
@@ -1385,6 +1415,11 @@ $answers-apparition-duration: '0.5s';
|
|
|
1385
1415
|
width: calc(100% - 30px);
|
|
1386
1416
|
margin: auto;
|
|
1387
1417
|
margin-top: $mu200;
|
|
1418
|
+
|
|
1419
|
+
a,
|
|
1420
|
+
button {
|
|
1421
|
+
width: 100%;
|
|
1422
|
+
}
|
|
1388
1423
|
}
|
|
1389
1424
|
|
|
1390
1425
|
&__modal-link {
|
|
@@ -1430,6 +1465,7 @@ $responsive-breakpoint: 'm';
|
|
|
1430
1465
|
background-repeat: no-repeat;
|
|
1431
1466
|
background-size: 100% auto;
|
|
1432
1467
|
padding: 120px 0;
|
|
1468
|
+
margin-bottom: 50px;
|
|
1433
1469
|
}
|
|
1434
1470
|
}
|
|
1435
1471
|
|
|
@@ -89,15 +89,14 @@
|
|
|
89
89
|
</div>
|
|
90
90
|
|
|
91
91
|
<div class="pb-upload-document__buttons row-flex" v-if="payload.multiSelect">
|
|
92
|
-
<div class="pb-upload-document__buttons__button" v-for="button in payload.multiSelect.actions">
|
|
93
|
-
<m-button label="Précédent" @click="$emit('go-back')" theme="bordered-neutral" icon="ArrowBack48" />
|
|
94
|
-
</div>
|
|
95
92
|
<div class="pb-upload-document__buttons__button" v-for="button in payload.multiSelect.actions">
|
|
96
93
|
<m-button
|
|
97
94
|
:label="button.label"
|
|
98
95
|
@click="validMultiSelect(button)"
|
|
99
96
|
:theme="button.theme"
|
|
100
97
|
:icon="button.icon"
|
|
98
|
+
size="m"
|
|
99
|
+
size-from-l="l"
|
|
101
100
|
:iconPosition="button.iconPosition"
|
|
102
101
|
/>
|
|
103
102
|
</div>
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { nestedAppDecorator } from '../../../.storybook/nested-app-decorator';
|
|
2
|
+
import { Anchor, Story, Preview, Meta, Props, ArgsTable, Source, Canvas } from '@storybook/addon-docs';
|
|
3
|
+
import PbScenario from './PbScenario';
|
|
4
|
+
import estimatesStore from '../../stores/modules/estimatesStore';
|
|
5
|
+
import DEFAULT_PAYLOAD from './scenarii/solar-panel.json';
|
|
6
|
+
import { TemplateSandbox } from './PbScenario.stories.mdx';
|
|
7
|
+
import simpleScenarioSchema from './Simple-scenario.svg';
|
|
8
|
+
|
|
9
|
+
<Meta
|
|
10
|
+
title="Project Booster/Scenario/PbScenario 🦠/Test (locally)/Solar Panel"
|
|
11
|
+
component={PbScenario}
|
|
12
|
+
argTypes={{
|
|
13
|
+
scenarios: {
|
|
14
|
+
table: {
|
|
15
|
+
defaultValue: {
|
|
16
|
+
summary: 'object',
|
|
17
|
+
detail: JSON.stringify(DEFAULT_PAYLOAD, null, ' '),
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
control: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
onScenarioCompleted: {
|
|
25
|
+
action: 'Scenario completed',
|
|
26
|
+
table: { disable: true },
|
|
27
|
+
},
|
|
28
|
+
onScenarioEvent: {
|
|
29
|
+
action: 'Scenario event occured',
|
|
30
|
+
table: { disable: true },
|
|
31
|
+
},
|
|
32
|
+
}}
|
|
33
|
+
decorators={[
|
|
34
|
+
nestedAppDecorator(
|
|
35
|
+
{
|
|
36
|
+
modules: {
|
|
37
|
+
estimates: estimatesStore,
|
|
38
|
+
},
|
|
39
|
+
actions: {
|
|
40
|
+
sendEventToBus({}, payload) {
|
|
41
|
+
console.log('Event sent to bus', payload);
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
[{ path: '/steps/:stepCode/previous/:answers', component: PbScenario }],
|
|
46
|
+
),
|
|
47
|
+
]}
|
|
48
|
+
parameters={{
|
|
49
|
+
layout: 'fullscreen',
|
|
50
|
+
}}
|
|
51
|
+
/>
|
|
52
|
+
|
|
53
|
+
<Anchor storyId="project-booster-scenario-pbscenario-features-conditional--101-simple-scenario" />
|
|
54
|
+
|
|
55
|
+
# Features - PbScenario
|
|
56
|
+
|
|
57
|
+
## Scenarios and steps management
|
|
58
|
+
|
|
59
|
+
The scenario component allows to manage **scenarios** and **steps** :
|
|
60
|
+
|
|
61
|
+
- a **scenario** is a sequence of steps,
|
|
62
|
+
- a **step** is one interaction from the user perspective.
|
|
63
|
+
|
|
64
|
+
## Simple scenario
|
|
65
|
+
|
|
66
|
+
The scenario component will use the bounded scenarios object containing all the scenarios and steps:
|
|
67
|
+
|
|
68
|
+
<details>
|
|
69
|
+
<summary class="css-1p8ieni">
|
|
70
|
+
Show/Hide <strong>scenario code</strong>:
|
|
71
|
+
</summary>
|
|
72
|
+
<Source language="json" code={JSON.stringify(DEFAULT_PAYLOAD, null, ' ')} />
|
|
73
|
+
</details>
|
|
74
|
+
|
|
75
|
+
A scenario object is composed of a map of steps. A step can be a standard step or a nested scenario.
|
|
76
|
+
|
|
77
|
+
This simple scenario contains:
|
|
78
|
+
|
|
79
|
+
- the `__START__` scenario which is used by the component to know where to find the main scenario, its presence is mandatory,
|
|
80
|
+
- the `MAIN_SCENARIO` (name it as you want) definition, pointing to its first step `MAIN_SCENARIO--STEP_1`,
|
|
81
|
+
- the `MAIN_SCENARIO--STEP_1` (name it as you want) step with the component `PbCard` used for this step and the next
|
|
82
|
+
step `MAIN_SCENARIO--STEP_2` (name it as you want) to reach when completed,
|
|
83
|
+
- the `MAIN_SCENARIO--STEP_2` (name it as you want) step with the component `PbCard` used for this step and the next
|
|
84
|
+
step `__END__` to reach when completed,
|
|
85
|
+
- the `__END__` step with the component `PbCard` used for this step which indicates to the
|
|
86
|
+
component that the main scenario is completed, its presence is mandatory to address properly the nested scenario feature.
|
|
87
|
+
|
|
88
|
+
NB: **`__START__`** and **`__END__`** are mandatory step codes to allow the component to work properly, **DO NOT RENAME THEM**. The `__END__`
|
|
89
|
+
can display a component.
|
|
90
|
+
|
|
91
|
+
<img src={simpleScenarioSchema} />
|
|
92
|
+
|
|
93
|
+
<Canvas>
|
|
94
|
+
<Story
|
|
95
|
+
name="Solar Panel"
|
|
96
|
+
inline={false}
|
|
97
|
+
height="758px"
|
|
98
|
+
args={{ scenarios: DEFAULT_PAYLOAD, minHeight: 'auto' }}
|
|
99
|
+
parameters={{ storyshots: { disable: true } }}
|
|
100
|
+
>
|
|
101
|
+
{TemplateSandbox.bind({})}
|
|
102
|
+
</Story>
|
|
103
|
+
</Canvas>
|
|
104
|
+
|
|
105
|
+
## Focus on scenario definition
|
|
106
|
+
|
|
107
|
+
Here is the scenario definition:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"SCENARIO_CODE": {
|
|
112
|
+
"code": "SCENARIO_CODE",
|
|
113
|
+
"type": "SCENARIO",
|
|
114
|
+
"stepCode": "FIRST_STEP_CODE",
|
|
115
|
+
"meta": {
|
|
116
|
+
"your-stuff": "here"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
where:
|
|
123
|
+
|
|
124
|
+
| | |
|
|
125
|
+
| --------------- | -------------------------------------------------------------------------------------------------- |
|
|
126
|
+
| `SCENARIO_CODE` | the scenario code uniquely identifying it in the scenario map, |
|
|
127
|
+
| `code` | the same as above, the data is duplicated inside the object to simplify steps/scenarios management |
|
|
128
|
+
| `type` | the type of step, (could be `STEP`, `SCENARIO`) |
|
|
129
|
+
| `stepCode` | the first step of the scenario |
|
|
130
|
+
| `meta` | data needed by the scenario host |
|
|
131
|
+
|
|
132
|
+
## Focus on step definition
|
|
133
|
+
|
|
134
|
+
### Mandatory properties
|
|
135
|
+
|
|
136
|
+
Here is the smallest step definition (it can be extended with other properties):
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"STEP_CODE": {
|
|
141
|
+
"code": "STEP_CODE",
|
|
142
|
+
"type": "STEP",
|
|
143
|
+
"component": "PbComponentForStepScreen",
|
|
144
|
+
"payload": {}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
| | |
|
|
150
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
151
|
+
| `STEP_CODE` | the step code uniquely identifying it in the scenario map |
|
|
152
|
+
| `type` | the type of step, (could be `STEP` or `SCENARIO`) |
|
|
153
|
+
| `component` | the component that will be used to materialize the step on the screen. See _Step component_ section below for more information |
|
|
154
|
+
| `payload` | the payload containing specific business data for the step |
|
|
155
|
+
|
|
156
|
+
### Step component
|
|
157
|
+
|
|
158
|
+
The step is associated with a component. This is the component which will be displayed for the step.
|
|
159
|
+
A `payload` property is also available to provide:
|
|
160
|
+
|
|
161
|
+
- the **business data** needed to address the business use case (ex: the answers of a question),
|
|
162
|
+
- the `viewModel` property which contains the component **view model** (ie. the data used to customise the component: label, images, ...).
|
|
163
|
+
|
|
164
|
+
The `payload` property is not mandatory as the component does not always need customisation data.
|
|
165
|
+
|
|
166
|
+
Here is a step definition with the component definition:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"STEP_CODE": {
|
|
171
|
+
"code": "STEP_CODE",
|
|
172
|
+
"type": "STEP",
|
|
173
|
+
"component": "PbComponentForStepScreen",
|
|
174
|
+
"payload": {}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### Step components API
|
|
180
|
+
|
|
181
|
+
The components API consists of :
|
|
182
|
+
|
|
183
|
+
- the `payload` provided by the `PbScenario` component which contains business data and view model,
|
|
184
|
+
- the `step-completed` event emitted by the component itself when he has finished its job.
|
|
185
|
+
|
|
186
|
+
##### Payload bound property
|
|
187
|
+
|
|
188
|
+
The `payload` property bound to the component will contain all the data needed by the component to do its job.
|
|
189
|
+
|
|
190
|
+
This is not mandatory as the component may be self sufficient to execute its tasks.
|
|
191
|
+
|
|
192
|
+
##### step-completed event
|
|
193
|
+
|
|
194
|
+
The `step-completed` event is raised when the component has finished its job. It contains:
|
|
195
|
+
|
|
196
|
+
- the `answers` property containing the result of the component job,
|
|
197
|
+
- the `nextStep` property containing a step to override the default `nextStep` defined on the current step.
|
|
198
|
+
|
|
199
|
+
## Going to next step
|
|
200
|
+
|
|
201
|
+
After the user completes the task provided by the component, the component will emit the `step-completed` event.
|
|
202
|
+
|
|
203
|
+
The `step-completed` event payload will contain the `answers` resulting from the user interactions and an optional
|
|
204
|
+
`nextStep`:
|
|
205
|
+
|
|
206
|
+
- If a `nextStep` is provided by the component, the scenario will use this as a next step.
|
|
207
|
+
- If no `nextStep` is provided by the component, the scenario component will look for the `nextStep` property of
|
|
208
|
+
the current step,
|
|
209
|
+
- If no `nextStep` is provided/found, the current scenario will be considered as finished and the scenario component
|
|
210
|
+
will try to resume the parent scenario.
|
|
211
|
+
|
|
212
|
+
The `nextStep` object only contains a `code` property valued with the code of the targeted next step.
|
|
213
|
+
If the code is `null`, it will react as if the `nextStep` is not provided (the current scenario will be considered
|
|
214
|
+
as finished and the scenario component will try to resume the parent scenario, if there is no scenario to resume,
|
|
215
|
+
the scenario will go to the `__END__`).
|
|
216
|
+
|
|
217
|
+
Next step example to navigate to a step or a nested scenario:
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"nextStep": {
|
|
222
|
+
"code": "NEXT_STEP_OR_SCENARIO_CODE"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Next step example to navigate to finish the current (nested) scenario:
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"nextStep": {
|
|
232
|
+
"code": null
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Next step example to navigate to end the main scenario:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"nextStep": {
|
|
242
|
+
"code": "__END__"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|