project-booster-vue 9.1.0 → 9.2.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.
- package/package.json +15 -15
- package/src/components/media/upload/PbMediaUpload.vue +3 -0
- package/src/components/projects/project-hub/PbProjectHub-Features-Documents&Media.stories.mdx +7 -1
- package/src/components/projects/project-hub/PbProjectHub.stories.mdx +28 -19
- package/src/components/projects/project-hub/PbProjectHub.vue +92 -87
- package/src/components/question/PbQuestion.vue +18 -6
- package/src/components/question/upload-document/PbUploadDocument-Features-ShowMore.stories.json +8 -3
- package/src/components/question/upload-document/PbUploadDocument-Features-StartOpen.stories.json +8 -3
- package/src/components/question/upload-document/PbUploadDocument.vue +0 -3
- package/src/components/question/upload-document/default-payload.json +8 -3
- package/src/components/question/upload-document/pictures-payload.json +6 -3
- package/src/components/scenario/PbScenario.vue +9 -17
- package/src/components/scenario/scenarii/appointment-qualification-kitchen.json +13 -5
- package/src/components/tasks/contentul-preview/ContenfulPlanner.ts +1 -1
- package/src/components/tasks/details/PbTaskDetails.vue +2 -2
- package/src/services/api/appointmentQualificationsApi.ts +1 -5
- package/src/services/scenarioConditionals.ts +1 -1
- package/src/types/pb/Scenario.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "project-booster-vue",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.2.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"serve": "vue-cli-service serve",
|
|
@@ -81,21 +81,21 @@
|
|
|
81
81
|
"@mswjs/interceptors": "0.12.7",
|
|
82
82
|
"@semantic-release/changelog": "5.0.1",
|
|
83
83
|
"@semantic-release/git": "9.0.0",
|
|
84
|
-
"@storybook/addon-a11y": "6.4.
|
|
85
|
-
"@storybook/addon-essentials": "6.4.
|
|
84
|
+
"@storybook/addon-a11y": "6.4.21",
|
|
85
|
+
"@storybook/addon-essentials": "6.4.21",
|
|
86
86
|
"@storybook/addon-knobs": "6.3.1",
|
|
87
|
-
"@storybook/addon-links": "6.4.
|
|
87
|
+
"@storybook/addon-links": "6.4.21",
|
|
88
88
|
"@storybook/addon-postcss": "2.0.0",
|
|
89
|
-
"@storybook/addon-storyshots": "6.4.
|
|
90
|
-
"@storybook/addon-storyshots-puppeteer": "6.4.
|
|
91
|
-
"@storybook/addon-storysource": "6.4.
|
|
92
|
-
"@storybook/addons": "6.4.
|
|
93
|
-
"@storybook/builder-webpack5": "6.4.
|
|
94
|
-
"@storybook/manager-webpack5": "6.4.
|
|
95
|
-
"@storybook/source-loader": "6.4.
|
|
89
|
+
"@storybook/addon-storyshots": "6.4.21",
|
|
90
|
+
"@storybook/addon-storyshots-puppeteer": "6.4.21",
|
|
91
|
+
"@storybook/addon-storysource": "6.4.21",
|
|
92
|
+
"@storybook/addons": "6.4.21",
|
|
93
|
+
"@storybook/builder-webpack5": "6.4.21",
|
|
94
|
+
"@storybook/manager-webpack5": "6.4.21",
|
|
95
|
+
"@storybook/source-loader": "6.4.21",
|
|
96
96
|
"@storybook/storybook-deployer": "2.8.11",
|
|
97
|
-
"@storybook/theming": "6.4.
|
|
98
|
-
"@storybook/vue3": "6.4.
|
|
97
|
+
"@storybook/theming": "6.4.21",
|
|
98
|
+
"@storybook/vue3": "6.4.21",
|
|
99
99
|
"@testing-library/jest-dom": "5.16.2",
|
|
100
100
|
"@testing-library/vue": "6.5.1",
|
|
101
101
|
"@types/axios": "0.14.0",
|
|
@@ -147,13 +147,13 @@
|
|
|
147
147
|
"eslint-plugin-import": "2.25.4",
|
|
148
148
|
"eslint-plugin-mdx": "1.16.0",
|
|
149
149
|
"eslint-plugin-prettier": "4.0.0",
|
|
150
|
-
"eslint-plugin-storybook": "0.5.
|
|
150
|
+
"eslint-plugin-storybook": "0.5.8",
|
|
151
151
|
"eslint-plugin-vue": "7.11.1",
|
|
152
152
|
"fluent-json-schema": "3.0.1",
|
|
153
153
|
"husky": "6.0.0",
|
|
154
154
|
"jest": "26.6.3",
|
|
155
155
|
"msw": "0.39.1",
|
|
156
|
-
"msw-storybook-addon": "1.6.
|
|
156
|
+
"msw-storybook-addon": "1.6.3",
|
|
157
157
|
"mutationobserver-shim": "0.3.7",
|
|
158
158
|
"postcss": "8.3.11",
|
|
159
159
|
"postcss-loader": "4.2.0",
|
|
@@ -407,6 +407,9 @@ export default defineComponent({
|
|
|
407
407
|
|
|
408
408
|
async upload() {
|
|
409
409
|
if (!this.disabled && !this.isMediaUploaded) {
|
|
410
|
+
if (this.selectedType === null) {
|
|
411
|
+
this.selectedType = this.payload.viewModel.dialog.defaultMediaType;
|
|
412
|
+
}
|
|
410
413
|
await this.$store.dispatch(this.storePrefix + 'uploadFile', {
|
|
411
414
|
formData: this.formData,
|
|
412
415
|
fileName: this.fileName,
|
package/src/components/projects/project-hub/PbProjectHub-Features-Documents&Media.stories.mdx
CHANGED
|
@@ -54,9 +54,11 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
54
54
|
store.dispatch('projects/loadProject', '001');
|
|
55
55
|
}
|
|
56
56
|
if (store.getters['media/getCurrentProjectId'] !== '001') {
|
|
57
|
+
store.dispatch('media/updateContext', { type: 'MEDIA' });
|
|
57
58
|
store.dispatch('media/loadMedia', '001');
|
|
58
59
|
}
|
|
59
60
|
if (store.getters['documents/getCurrentProjectId'] !== '001') {
|
|
61
|
+
store.dispatch('documents/updateContext', { type: 'DOCUMENTS' });
|
|
60
62
|
store.dispatch('documents/loadMedia', '001');
|
|
61
63
|
}
|
|
62
64
|
next();
|
|
@@ -72,6 +74,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
72
74
|
uploadPayload: MEDIA_UPLOAD_PAYLOAD,
|
|
73
75
|
},
|
|
74
76
|
beforeEnter: async (to, from, next, store) => {
|
|
77
|
+
store.dispatch('media/updateContext', { type: 'MEDIA' });
|
|
75
78
|
if (store.getters['projects/getCurrentProjectId'] !== '001') {
|
|
76
79
|
store.dispatch('projects/loadProject', '001');
|
|
77
80
|
}
|
|
@@ -91,6 +94,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
91
94
|
uploadPayload: MEDIA_UPLOAD_PAYLOAD,
|
|
92
95
|
},
|
|
93
96
|
beforeEnter: async (to, from, next, store) => {
|
|
97
|
+
store.dispatch('media/updateContext', { type: 'MEDIA' });
|
|
94
98
|
if (store.getters['projects/getCurrentProjectId'] !== '001') {
|
|
95
99
|
store.dispatch('projects/loadProject', '001');
|
|
96
100
|
}
|
|
@@ -114,6 +118,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
114
118
|
uploadPayload: DOCUMENT_UPLOAD_PAYLOAD,
|
|
115
119
|
},
|
|
116
120
|
beforeEnter: async (to, from, next, store) => {
|
|
121
|
+
store.dispatch('documents/updateContext', { type: 'DOCUMENTS' });
|
|
117
122
|
if (store.getters['projects/getCurrentProjectId'] !== '001') {
|
|
118
123
|
store.dispatch('projects/loadProject', '001');
|
|
119
124
|
}
|
|
@@ -134,6 +139,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
134
139
|
uploadPayload: DOCUMENT_UPLOAD_PAYLOAD,
|
|
135
140
|
},
|
|
136
141
|
beforeEnter: async (to, from, next, store) => {
|
|
142
|
+
store.dispatch('documents/updateContext', { type: 'DOCUMENTS' });
|
|
137
143
|
if (store.getters['projects/getCurrentProjectId'] !== '001') {
|
|
138
144
|
store.dispatch('projects/loadProject', '001');
|
|
139
145
|
}
|
|
@@ -148,7 +154,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
148
154
|
},
|
|
149
155
|
]),
|
|
150
156
|
]}
|
|
151
|
-
|
|
157
|
+
/>
|
|
152
158
|
|
|
153
159
|
# 🦠 `PbProjectHub` - Component
|
|
154
160
|
|
|
@@ -97,9 +97,11 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
97
97
|
store.dispatch('estimates/loadEstimates', projectId);
|
|
98
98
|
}
|
|
99
99
|
if (store.getters['media/getCurrentProjectId'] !== projectId) {
|
|
100
|
+
store.dispatch('media/updateContext', { type: 'MEDIA' });
|
|
100
101
|
store.dispatch('media/loadMedia', projectId);
|
|
101
102
|
}
|
|
102
103
|
if (store.getters['documents/getCurrentProjectId'] !== projectId) {
|
|
104
|
+
store.dispatch('documents/updateContext', { type: 'DOCUMENTS' });
|
|
103
105
|
store.dispatch('documents/loadMedia', projectId);
|
|
104
106
|
}
|
|
105
107
|
if (store.getters['projects/getCurrentProjectId'] !== projectId) {
|
|
@@ -125,6 +127,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
125
127
|
beforeEnter: async (to, from, next, store) => {
|
|
126
128
|
store.dispatch('media/updateCurrentMedia', null);
|
|
127
129
|
const projectId = to.params.projectId;
|
|
130
|
+
store.dispatch('media/updateContext', { type: 'MEDIA' });
|
|
128
131
|
if (store.getters['projects/getCurrentProjectId'] !== projectId) {
|
|
129
132
|
store.dispatch('projects/loadProject', projectId);
|
|
130
133
|
}
|
|
@@ -141,6 +144,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
141
144
|
beforeEnter: async (to, from, next, store) => {
|
|
142
145
|
const projectId = to.params.projectId;
|
|
143
146
|
const mediaId = to.params.inspirationId;
|
|
147
|
+
store.dispatch('media/updateContext', { type: 'MEDIA' });
|
|
144
148
|
if (store.getters['projects/getCurrentProjectId'] !== projectId) {
|
|
145
149
|
store.dispatch('projects/loadProject', projectId);
|
|
146
150
|
}
|
|
@@ -164,6 +168,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
164
168
|
uploadPayload: DOCUMENT_UPLOAD_PAYLOAD,
|
|
165
169
|
},
|
|
166
170
|
beforeEnter: async (to, from, next, store) => {
|
|
171
|
+
store.dispatch('documents/updateContext', { type: 'DOCUMENTS' });
|
|
167
172
|
store.dispatch('documents/updateCurrentMedia', null);
|
|
168
173
|
const projectId = to.params.projectId;
|
|
169
174
|
if (store.getters['projects/getCurrentProjectId'] !== projectId) {
|
|
@@ -188,6 +193,7 @@ import DOCUMENT_UPLOAD_PAYLOAD from '../../media/upload/document-upload-payload.
|
|
|
188
193
|
beforeEnter: async (to, from, next, store) => {
|
|
189
194
|
const projectId = to.params.projectId;
|
|
190
195
|
const mediaId = to.params.documentId;
|
|
196
|
+
store.dispatch('documents/updateContext', { type: 'DOCUMENTS' });
|
|
191
197
|
if (store.getters['projects/getCurrentProjectId'] !== projectId) {
|
|
192
198
|
store.dispatch('projects/loadProject', projectId);
|
|
193
199
|
}
|
|
@@ -245,31 +251,34 @@ The `PbProjectHub` component to access your project.
|
|
|
245
251
|
rest.get('/api/estimates', getEstimatesByProjectIdResolver),
|
|
246
252
|
rest.post('/api/estimates', successResolver),
|
|
247
253
|
rest.get(
|
|
248
|
-
'/inhabitant-projects/:inhabitantProjectId/simulations',
|
|
254
|
+
'/api/inhabitant-projects/:inhabitantProjectId/simulations',
|
|
249
255
|
getConfigurationsWithUpdatedPricesByProjectIdResolver,
|
|
250
256
|
),
|
|
251
|
-
rest.get('
|
|
257
|
+
rest.get('//apisimulations', getConfigurationsByProjectIdResolver),
|
|
252
258
|
rest.get(
|
|
253
259
|
'https://storage.googleapis.com/pb-dev-adeo-disp-project-tools/:id.json',
|
|
254
260
|
getToolsByProjectTypeResolver,
|
|
255
261
|
),
|
|
256
|
-
rest.get('/project-types/:projectTypeId/products-feature-flag', getEnabledProductsFeatureFlagResolver),
|
|
257
|
-
rest.get('/media', getAllMediaPaginationResolver),
|
|
258
|
-
rest.get('/media/:mediaId', getMediumByIdResolver),
|
|
259
|
-
rest.get('/media/:mediaId/thumbnail', getMediaThumbnailResolver),
|
|
260
|
-
rest.get('/media/:mediaId/file', getMediaFileResolver),
|
|
261
|
-
rest.post('/media', uploadMediaResolver),
|
|
262
|
-
rest.patch('/media/:mediaId', getMediumByIdResolver),
|
|
263
|
-
rest.delete('/media/:mediaId', successResolver),
|
|
264
|
-
rest.patch('/media/:mediaId', notContentResolver),
|
|
265
|
-
rest.get('/inhabitant-projects/:projectId/documents/', getDocumentsByInhabitantProjectIdResolver),
|
|
266
|
-
rest.get('/inhabitant-projects/:projectId/documents/:documentId', getDocumentByIdResolver),
|
|
267
|
-
rest.delete('/inhabitant-projects/:projectId/documents/:documentId', successResolver),
|
|
268
|
-
rest.get(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
rest.get('/inhabitant-
|
|
262
|
+
rest.get('/api/project-types/:projectTypeId/products-feature-flag', getEnabledProductsFeatureFlagResolver),
|
|
263
|
+
rest.get('/api/media', getAllMediaPaginationResolver),
|
|
264
|
+
rest.get('/api/media/:mediaId', getMediumByIdResolver),
|
|
265
|
+
rest.get('/api/media/:mediaId/thumbnail', getMediaThumbnailResolver),
|
|
266
|
+
rest.get('/api/media/:mediaId/file', getMediaFileResolver),
|
|
267
|
+
rest.post('/api/media', uploadMediaResolver),
|
|
268
|
+
rest.patch('/api/media/:mediaId', getMediumByIdResolver),
|
|
269
|
+
rest.delete('/api/media/:mediaId', successResolver),
|
|
270
|
+
rest.patch('/api/media/:mediaId', notContentResolver),
|
|
271
|
+
rest.get('/api/inhabitant-projects/:projectId/documents/', getDocumentsByInhabitantProjectIdResolver),
|
|
272
|
+
rest.get('/api/inhabitant-projects/:projectId/documents/:documentId', getDocumentByIdResolver),
|
|
273
|
+
rest.delete('/api/inhabitant-projects/:projectId/documents/:documentId', successResolver),
|
|
274
|
+
rest.get(
|
|
275
|
+
'/api/inhabitant-projects/:projectId/documents/:documentId/thumbnail',
|
|
276
|
+
getDocumentsImageThumbnailResolver,
|
|
277
|
+
),
|
|
278
|
+
rest.get('/api/inhabitant-projects/:projectId/documents/:documentId/file', getDocumentsImageFileResolver),
|
|
279
|
+
rest.post('/api/inhabitant-projects/:projectId/documents', uploadDocumentResolver),
|
|
280
|
+
rest.get('/api/inhabitant-projects/:projectId/attributes', getProjectAttributesByIdResolver),
|
|
281
|
+
rest.get('/api/inhabitant-api/users/:buId/:inhabitantId', getInhabitantByIdResolver),
|
|
273
282
|
],
|
|
274
283
|
storyshots: { disable: true },
|
|
275
284
|
}}
|
|
@@ -81,35 +81,61 @@
|
|
|
81
81
|
/>
|
|
82
82
|
</m-flex>
|
|
83
83
|
</m-flex>
|
|
84
|
-
<m-flex
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
84
|
+
<m-flex v-if="isDocumentsDisplayed" class="pb-project-hub__section" direction="column" full-width>
|
|
85
|
+
<div class="pb-project-hub__section-header">
|
|
86
|
+
<div class="pb-project-hub__section-title">{{ titleDocument }}</div>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="pb-project-hub__section-content">
|
|
89
|
+
<m-flex
|
|
90
|
+
class="pb-project-hub__section-content--loading"
|
|
91
|
+
v-if="isLoadingDocuments"
|
|
92
|
+
direction="column"
|
|
93
|
+
align-items="center"
|
|
94
|
+
justify-content="center"
|
|
95
|
+
align-content="center"
|
|
96
|
+
>
|
|
97
|
+
<pb-animable-loader class="pb-project-hub__section-content--loading-loader" />
|
|
98
|
+
<div class="pb-project-hub__section-content--loading-label">Chargement...</div>
|
|
99
|
+
</m-flex>
|
|
100
|
+
<m-container
|
|
101
|
+
class="pb-project-hub__section-content-cards-container"
|
|
102
|
+
fluid
|
|
103
|
+
v-if="displayedDocuments && displayedDocuments.length > 0"
|
|
104
|
+
>
|
|
105
|
+
<m-flexy class="pb-project-hub__section-content-cards-flexy">
|
|
106
|
+
<m-flexy-col
|
|
107
|
+
class="pb-project-hub__section-content-card-flexy"
|
|
108
|
+
v-for="document in displayedDocuments"
|
|
109
|
+
:key="document.id"
|
|
110
|
+
width="full"
|
|
111
|
+
width-from-m="1of3"
|
|
112
|
+
>
|
|
113
|
+
<div class="pb-project-hub__section-content-card-container">
|
|
114
|
+
<pb-card
|
|
115
|
+
@cardClick="handleDocumentClick(document.id)"
|
|
116
|
+
class="pb-project-hub__section-content-card"
|
|
117
|
+
:image="documentThumbnailUrl.replace('@@PB_MEDIA_ID_FILLER@@', document.id)"
|
|
118
|
+
:text="document.title ? document.title : 'Image sans nom'"
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
</m-flexy-col>
|
|
122
|
+
</m-flexy>
|
|
123
|
+
<m-link
|
|
124
|
+
class="pb-project-hub__section-content-link"
|
|
125
|
+
label="Gérer vos documents"
|
|
126
|
+
@click="$router.push({ name: 'PbDocuments' })"
|
|
127
|
+
/>
|
|
128
|
+
</m-container>
|
|
129
|
+
<pb-empty-state
|
|
130
|
+
v-else
|
|
131
|
+
:title="!readOnly ? 'Centraliser vos documents' : ''"
|
|
132
|
+
:subtitle="!readOnly ? '' : 'Aucune information renseignée'"
|
|
133
|
+
image="https://storage.googleapis.com/project-booster-media/media/empty-media.png"
|
|
134
|
+
:button-label="!readOnly ? 'Ajouter des documents' : ''"
|
|
135
|
+
@button-click="handleClickDocumentEmptyState"
|
|
136
|
+
:disabled="readOnly"
|
|
137
|
+
/>
|
|
138
|
+
</div>
|
|
113
139
|
</m-flex>
|
|
114
140
|
<m-flex
|
|
115
141
|
v-if="isEstimatesDisplayed"
|
|
@@ -360,7 +386,7 @@
|
|
|
360
386
|
</m-flexy>
|
|
361
387
|
<m-link
|
|
362
388
|
class="pb-project-hub__section-content-link"
|
|
363
|
-
label="
|
|
389
|
+
label="Gérer vos inspirations"
|
|
364
390
|
@click="$router.push({ name: 'PbInspirations' })"
|
|
365
391
|
/>
|
|
366
392
|
</m-container>
|
|
@@ -375,63 +401,12 @@
|
|
|
375
401
|
/>
|
|
376
402
|
</div>
|
|
377
403
|
</m-flex>
|
|
378
|
-
<m-flex
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
class="pb-project-hub__section-content--loading"
|
|
385
|
-
v-if="isLoadingDocuments"
|
|
386
|
-
direction="column"
|
|
387
|
-
align-items="center"
|
|
388
|
-
justify-content="center"
|
|
389
|
-
align-content="center"
|
|
390
|
-
>
|
|
391
|
-
<pb-animable-loader class="pb-project-hub__section-content--loading-loader" />
|
|
392
|
-
<div class="pb-project-hub__section-content--loading-label">Chargement...</div>
|
|
393
|
-
</m-flex>
|
|
394
|
-
<m-container
|
|
395
|
-
class="pb-project-hub__section-content-cards-container"
|
|
396
|
-
fluid
|
|
397
|
-
v-if="displayedDocuments && displayedDocuments.length > 0"
|
|
398
|
-
>
|
|
399
|
-
<m-flexy class="pb-project-hub__section-content-cards-flexy">
|
|
400
|
-
<m-flexy-col
|
|
401
|
-
class="pb-project-hub__section-content-card-flexy"
|
|
402
|
-
v-for="document in displayedDocuments"
|
|
403
|
-
:key="document.id"
|
|
404
|
-
width="full"
|
|
405
|
-
width-from-m="1of3"
|
|
406
|
-
>
|
|
407
|
-
<div class="pb-project-hub__section-content-card-container">
|
|
408
|
-
<pb-card
|
|
409
|
-
@cardClick="handleDocumentClick(document.id)"
|
|
410
|
-
class="pb-project-hub__section-content-card"
|
|
411
|
-
:image="documentThumbnailUrl.replace('@@PB_MEDIA_ID_FILLER@@', document.id)"
|
|
412
|
-
:text="document.title ? document.title : 'Image sans nom'"
|
|
413
|
-
/>
|
|
414
|
-
</div>
|
|
415
|
-
</m-flexy-col>
|
|
416
|
-
</m-flexy>
|
|
417
|
-
<m-link
|
|
418
|
-
class="pb-project-hub__section-content-link"
|
|
419
|
-
label="Voir tous les documents"
|
|
420
|
-
@click="$router.push({ name: 'PbDocuments' })"
|
|
421
|
-
/>
|
|
422
|
-
</m-container>
|
|
423
|
-
<pb-empty-state
|
|
424
|
-
v-else
|
|
425
|
-
:title="!readOnly ? 'Centraliser vos documents' : ''"
|
|
426
|
-
:subtitle="!readOnly ? '' : 'Aucune information renseignée'"
|
|
427
|
-
image="https://storage.googleapis.com/project-booster-media/media/empty-media.png"
|
|
428
|
-
:button-label="!readOnly ? 'Ajouter des documents' : ''"
|
|
429
|
-
@button-click="handleClickDocumentEmptyState"
|
|
430
|
-
:disabled="readOnly"
|
|
431
|
-
/>
|
|
432
|
-
</div>
|
|
433
|
-
</m-flex>
|
|
434
|
-
<m-flex v-if="areProjectAttributesDisplayed" class="pb-project-hub__section" direction="column" full-width>
|
|
404
|
+
<m-flex
|
|
405
|
+
v-if="areProjectAttributesDisplayed && projectAttributes && Object.keys(projectAttributes).length > 0"
|
|
406
|
+
class="pb-project-hub__section"
|
|
407
|
+
direction="column"
|
|
408
|
+
full-width
|
|
409
|
+
>
|
|
435
410
|
<div class="pb-project-hub__section-header">
|
|
436
411
|
<div class="pb-project-hub__section-title" ref="pbProjectAttributeList">
|
|
437
412
|
{{ titleProjectAttribute }}
|
|
@@ -466,6 +441,36 @@
|
|
|
466
441
|
</m-flex>
|
|
467
442
|
</div>
|
|
468
443
|
</m-flex>
|
|
444
|
+
<m-flex
|
|
445
|
+
v-if="isPlannerDisplayed"
|
|
446
|
+
class="pb-project-hub__section pb-project-hub__planner-section"
|
|
447
|
+
direction="column"
|
|
448
|
+
full-width
|
|
449
|
+
>
|
|
450
|
+
<pb-tasks-preview
|
|
451
|
+
v-if="!plannerError"
|
|
452
|
+
class="pb-project-hub__planner"
|
|
453
|
+
:tasks="tasks"
|
|
454
|
+
:tasks-number="3"
|
|
455
|
+
:read-only="readOnly"
|
|
456
|
+
@show-task-details="handleShowTaskDetails"
|
|
457
|
+
@create-task="handleCreateTask"
|
|
458
|
+
@view-tasks="handleViewTasks"
|
|
459
|
+
@task-completed="handleCompleteTask"
|
|
460
|
+
/>
|
|
461
|
+
<m-flex
|
|
462
|
+
v-else-if="plannerError"
|
|
463
|
+
class="pb-project-hub__planner--error"
|
|
464
|
+
direction="column"
|
|
465
|
+
align-items="center"
|
|
466
|
+
justify-content="center"
|
|
467
|
+
gap="2rem"
|
|
468
|
+
full-width
|
|
469
|
+
>
|
|
470
|
+
<div>Une erreur est survenue lors du chargement des étapes</div>
|
|
471
|
+
<m-button label="Réessayer" @click="$store.dispatch('tasks/reloadPlanner')" />
|
|
472
|
+
</m-flex>
|
|
473
|
+
</m-flex>
|
|
469
474
|
<m-flex v-if="isMailConsentDisplayed" class="pb-project-hub__section" direction="column" full-width>
|
|
470
475
|
<div class="pb-project-hub__section-header">
|
|
471
476
|
<div class="pb-project-hub__section-title" ref="pbConsent">Souscription newsletter</div>
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
{{ payload.viewModel.hero }}
|
|
17
17
|
</div>
|
|
18
18
|
<div class="pb-question__title-container">
|
|
19
|
-
<div
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
<div
|
|
20
|
+
v-if="payload.viewModel.label"
|
|
21
|
+
class="pb-question__title"
|
|
22
|
+
v-html="decorate(payload.viewModel.label, payload.defaultDecoratorValue)"
|
|
23
|
+
/>
|
|
22
24
|
<div v-if="payload.viewModel.subtitle" class="pb-question__subtitle">
|
|
23
25
|
{{ decorate(payload.viewModel.subtitle, payload.defaultDecoratorValue) }}
|
|
24
26
|
<m-link
|
|
@@ -431,8 +433,13 @@ export default defineComponent({
|
|
|
431
433
|
if (
|
|
432
434
|
questionPossibleAnswer &&
|
|
433
435
|
(questionPossibleAnswer?.selected ||
|
|
434
|
-
answerValues.findIndex(
|
|
435
|
-
|
|
436
|
+
answerValues.findIndex(
|
|
437
|
+
(answer: ScenarioStepAnswer | string) =>
|
|
438
|
+
(typeof answer === 'string' && answer === answerCode) ||
|
|
439
|
+
(typeof answer === 'object' &&
|
|
440
|
+
(<ScenarioStepAnswer>answer)?.code === answerCode &&
|
|
441
|
+
(<ScenarioStepAnswer>answer)?.selected),
|
|
442
|
+
) >= 0) &&
|
|
436
443
|
areConditionsValid(questionPossibleAnswer.conditions!, this.answers, this.runtimeOptions)
|
|
437
444
|
) {
|
|
438
445
|
this.selectedAnswers.set(answerCode, true);
|
|
@@ -452,7 +459,12 @@ export default defineComponent({
|
|
|
452
459
|
decorate(valueToDecorate: string, defaultValue = '') {
|
|
453
460
|
if (valueToDecorate) {
|
|
454
461
|
valueToDecorate = `\`${valueToDecorate}\``;
|
|
455
|
-
|
|
462
|
+
try {
|
|
463
|
+
return this.doEval(valueToDecorate, defaultValue);
|
|
464
|
+
} catch (e) {
|
|
465
|
+
console.error(e);
|
|
466
|
+
return valueToDecorate;
|
|
467
|
+
}
|
|
456
468
|
}
|
|
457
469
|
return valueToDecorate;
|
|
458
470
|
},
|
package/src/components/question/upload-document/PbUploadDocument-Features-ShowMore.stories.json
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
"startOpened": false,
|
|
10
10
|
"mediaPayload": {
|
|
11
11
|
"viewModel": {
|
|
12
|
-
"type": "
|
|
13
|
-
"subType": "PLAN",
|
|
12
|
+
"type": "documentsPlans",
|
|
14
13
|
"acceptedFileTypes": "image/jpeg, image/png, image/heif, image/heic, image/heif-sequence, image/heic-sequence, application/pdf",
|
|
15
14
|
"dialog": {
|
|
16
15
|
"hideCross": false,
|
|
@@ -25,14 +24,20 @@
|
|
|
25
24
|
"acceptedMediaTypesErrorLabel": "Seuls les formats JPG et PNG, et PDF sont acceptés",
|
|
26
25
|
"mediaTypes": [
|
|
27
26
|
{
|
|
27
|
+
"type": "PLAN",
|
|
28
|
+
"subtype": "HAND_DRAWN_PLAN",
|
|
28
29
|
"code": "HAND_DRAWN_PLAN",
|
|
29
|
-
"label": "Un plan fait moi
|
|
30
|
+
"label": "Un plan fait moi-même"
|
|
30
31
|
},
|
|
31
32
|
{
|
|
33
|
+
"type": "PLAN",
|
|
34
|
+
"subtype": "ARCHITECT_PLAN",
|
|
32
35
|
"code": "ARCHITECT_PLAN",
|
|
33
36
|
"label": "Un plan d’architecte"
|
|
34
37
|
},
|
|
35
38
|
{
|
|
39
|
+
"type": "PLAN",
|
|
40
|
+
"subtype": "KITCHEN_DESIGNER_PLAN",
|
|
36
41
|
"code": "KITCHEN_DESIGNER_PLAN",
|
|
37
42
|
"label": "Un plan d’un autre cuisiniste"
|
|
38
43
|
}
|
package/src/components/question/upload-document/PbUploadDocument-Features-StartOpen.stories.json
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
"startOpened": true,
|
|
6
6
|
"mediaPayload": {
|
|
7
7
|
"viewModel": {
|
|
8
|
-
"type": "
|
|
9
|
-
"subType": "PLAN",
|
|
8
|
+
"type": "documentsPlans",
|
|
10
9
|
"acceptedFileTypes": "image/jpeg, image/png, image/heif, image/heic, image/heif-sequence, image/heic-sequence, application/pdf",
|
|
11
10
|
"dialog": {
|
|
12
11
|
"hideCross": false,
|
|
@@ -22,14 +21,20 @@
|
|
|
22
21
|
"acceptedMediaTypesErrorLabel": "Seuls les formats JPG et PNG, et PDF sont acceptés",
|
|
23
22
|
"mediaTypes": [
|
|
24
23
|
{
|
|
24
|
+
"type": "PLAN",
|
|
25
|
+
"subtype": "HAND_DRAWN_PLAN",
|
|
25
26
|
"code": "HAND_DRAWN_PLAN",
|
|
26
|
-
"label": "Un plan fait moi
|
|
27
|
+
"label": "Un plan fait moi-même"
|
|
27
28
|
},
|
|
28
29
|
{
|
|
30
|
+
"type": "PLAN",
|
|
31
|
+
"subtype": "ARCHITECT_PLAN",
|
|
29
32
|
"code": "ARCHITECT_PLAN",
|
|
30
33
|
"label": "Un plan d’architecte"
|
|
31
34
|
},
|
|
32
35
|
{
|
|
36
|
+
"type": "PLAN",
|
|
37
|
+
"subtype": "KITCHEN_DESIGNER_PLAN",
|
|
33
38
|
"code": "KITCHEN_DESIGNER_PLAN",
|
|
34
39
|
"label": "Un plan d’un autre cuisiniste"
|
|
35
40
|
}
|
|
@@ -238,9 +238,6 @@ export default defineComponent({
|
|
|
238
238
|
setup(props, { emit }) {
|
|
239
239
|
const store = useStore();
|
|
240
240
|
let storeModuleName = ref(props.payload.viewModel.mediaPayload.viewModel.type);
|
|
241
|
-
if (props.payload.viewModel.mediaPayload.viewModel.subType) {
|
|
242
|
-
storeModuleName.value += props.payload.viewModel.mediaPayload.viewModel.subType === 'PLAN' ? 'Plans' : 'Pictures';
|
|
243
|
-
}
|
|
244
241
|
|
|
245
242
|
const pbMediaUpload = ref<ComponentCustomProperties>();
|
|
246
243
|
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
"startOpened": false,
|
|
6
6
|
"mediaPayload": {
|
|
7
7
|
"viewModel": {
|
|
8
|
-
"type": "
|
|
9
|
-
"subType": "PLAN",
|
|
8
|
+
"type": "documentsPlan",
|
|
10
9
|
"acceptedFileTypes": "image/jpeg, image/png, image/heif, image/heic, image/heif-sequence, image/heic-sequence, application/pdf",
|
|
11
10
|
"dialog": {
|
|
12
11
|
"hideCross": false,
|
|
@@ -21,14 +20,20 @@
|
|
|
21
20
|
"acceptedMediaTypesErrorLabel": "Seuls les formats JPG et PNG, et PDF sont acceptés",
|
|
22
21
|
"mediaTypes": [
|
|
23
22
|
{
|
|
23
|
+
"type": "PLAN",
|
|
24
|
+
"subtype": "HAND_DRAWN_PLAN",
|
|
24
25
|
"code": "HAND_DRAWN_PLAN",
|
|
25
|
-
"label": "Un plan fait moi
|
|
26
|
+
"label": "Un plan fait moi-même"
|
|
26
27
|
},
|
|
27
28
|
{
|
|
29
|
+
"type": "PLAN",
|
|
30
|
+
"subtype": "ARCHITECT_PLAN",
|
|
28
31
|
"code": "ARCHITECT_PLAN",
|
|
29
32
|
"label": "Un plan d’architecte"
|
|
30
33
|
},
|
|
31
34
|
{
|
|
35
|
+
"type": "PLAN",
|
|
36
|
+
"subtype": "KITCHEN_DESIGNER_PLAN",
|
|
32
37
|
"code": "KITCHEN_DESIGNER_PLAN",
|
|
33
38
|
"label": "Un plan d’un autre cuisiniste"
|
|
34
39
|
}
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
"addText": " ",
|
|
7
7
|
"mediaPayload": {
|
|
8
8
|
"viewModel": {
|
|
9
|
-
"type": "
|
|
10
|
-
"subType": "PHOTO",
|
|
9
|
+
"type": "documentsPictures",
|
|
11
10
|
"acceptedFileTypes": "image/jpeg, image/png, image/heif, image/heic, image/heif-sequence, image/heic-sequence",
|
|
12
11
|
"dialog": {
|
|
13
12
|
"hideCross": false,
|
|
@@ -18,7 +17,11 @@
|
|
|
18
17
|
"chooseAnotherMediaLabel": "Choisir une autre photo",
|
|
19
18
|
"uploadProgressTitle": "Chargement de votre photo",
|
|
20
19
|
"errorUploadTitle": "Une erreur est survenue lors de l'envoi de votre photo ",
|
|
21
|
-
"uploadPreviewTitle": "Nom de la photo"
|
|
20
|
+
"uploadPreviewTitle": "Nom de la photo",
|
|
21
|
+
"defaultMediaType": {
|
|
22
|
+
"type": "PHOTO",
|
|
23
|
+
"subtype": "ROOM_PHOTO"
|
|
24
|
+
}
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -368,12 +368,12 @@ export default defineComponent({
|
|
|
368
368
|
|
|
369
369
|
state.value.stepsToResume = requestedStep.stepsToResume!;
|
|
370
370
|
|
|
371
|
-
state.value.currentStep = requestedStep?.step
|
|
371
|
+
state.value.currentStep = scenarios.get(requestedStep?.step.code)!;
|
|
372
372
|
|
|
373
373
|
animateDisplayedStep(stepIndex < state.value.history.stepIndex);
|
|
374
374
|
state.value.history.stepIndex = stepIndex;
|
|
375
375
|
|
|
376
|
-
if (state.value.currentStep.code === '__END__') {
|
|
376
|
+
if (state.value?.currentStep?.code && state.value.currentStep.code === '__END__') {
|
|
377
377
|
/**
|
|
378
378
|
* Emitted when the scenario is completed
|
|
379
379
|
* @event scenario-completed
|
|
@@ -381,7 +381,7 @@ export default defineComponent({
|
|
|
381
381
|
emit('scenario-completed', state.value.answers);
|
|
382
382
|
emitEventToPipeline('SCENARIO-COMPLETED', state.value.currentStep);
|
|
383
383
|
} else {
|
|
384
|
-
emitEventToPipeline('STEP-STARTED', state.value
|
|
384
|
+
emitEventToPipeline('STEP-STARTED', state.value?.currentStep);
|
|
385
385
|
}
|
|
386
386
|
} else {
|
|
387
387
|
console.warn(`Scenario step ${stepIndex} was requested but is not in the history`);
|
|
@@ -593,8 +593,8 @@ export default defineComponent({
|
|
|
593
593
|
state.value.history.steps = [];
|
|
594
594
|
|
|
595
595
|
state.value.stepsToResume = [];
|
|
596
|
-
state.value.currentStep =
|
|
597
|
-
state.value.displayedStep =
|
|
596
|
+
state.value.currentStep = undefined;
|
|
597
|
+
state.value.displayedStep = undefined;
|
|
598
598
|
reverseAnimation.value = false;
|
|
599
599
|
|
|
600
600
|
initScenario('__START__');
|
|
@@ -606,6 +606,9 @@ export default defineComponent({
|
|
|
606
606
|
(newValue) => {
|
|
607
607
|
if (newValue && scenarios) {
|
|
608
608
|
state.value = newValue;
|
|
609
|
+
if (state.value.answers && !(state.value.answers instanceof Map)) {
|
|
610
|
+
state.value.answers = new Map<string, ScenarioStepAnswer[]>(Object.entries(state.value.answers));
|
|
611
|
+
}
|
|
609
612
|
goToStep(state.value.history.stepIndex);
|
|
610
613
|
}
|
|
611
614
|
},
|
|
@@ -617,20 +620,9 @@ export default defineComponent({
|
|
|
617
620
|
},
|
|
618
621
|
);
|
|
619
622
|
|
|
623
|
+
initScenario('__START__');
|
|
620
624
|
onMounted(() => {
|
|
621
625
|
document.getElementsByTagName('body')[0].style.setProperty('overflow-x', 'hidden');
|
|
622
|
-
if (scenarios && !props.previousState) {
|
|
623
|
-
initScenario('__START__');
|
|
624
|
-
} else {
|
|
625
|
-
if (props.previousState.refreshSteps) {
|
|
626
|
-
state.value.answers = props.previousState.answers;
|
|
627
|
-
initScenario('__START__');
|
|
628
|
-
} else {
|
|
629
|
-
state.value = props.previousState;
|
|
630
|
-
const steps = props.previousState?.history?.steps ?? [];
|
|
631
|
-
state.value.stepsToResume = steps[props.previousState.history.stepIndex - 1]?.stepsToResume ?? [];
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
626
|
});
|
|
635
627
|
|
|
636
628
|
return {
|
|
@@ -558,8 +558,7 @@
|
|
|
558
558
|
},
|
|
559
559
|
"mediaPayload": {
|
|
560
560
|
"viewModel": {
|
|
561
|
-
"type": "
|
|
562
|
-
"subType": "PLAN",
|
|
561
|
+
"type": "documentsPictures",
|
|
563
562
|
"acceptedFileTypes": "image/jpeg, image/png, image/heif, image/heic, application/pdf",
|
|
564
563
|
"dialog": {
|
|
565
564
|
"hideCross": false,
|
|
@@ -573,14 +572,20 @@
|
|
|
573
572
|
"mediaTypeTitle": "De quel type de plan s’agit il ?",
|
|
574
573
|
"mediaTypes": [
|
|
575
574
|
{
|
|
575
|
+
"type": "PLAN",
|
|
576
|
+
"subtype": "HAND_DRAWN_PLAN",
|
|
576
577
|
"code": "HAND_DRAWN_PLAN",
|
|
577
578
|
"label": "Un plan fait moi-même"
|
|
578
579
|
},
|
|
579
580
|
{
|
|
581
|
+
"type": "PLAN",
|
|
582
|
+
"subtype": "ARCHITECT_PLAN",
|
|
580
583
|
"code": "ARCHITECT_PLAN",
|
|
581
584
|
"label": "Un plan d’architecte"
|
|
582
585
|
},
|
|
583
586
|
{
|
|
587
|
+
"type": "PLAN",
|
|
588
|
+
"subtype": "KITCHEN_DESIGNER_PLAN",
|
|
584
589
|
"code": "KITCHEN_DESIGNER_PLAN",
|
|
585
590
|
"label": "Un plan d’un autre cuisiniste"
|
|
586
591
|
}
|
|
@@ -707,8 +712,7 @@
|
|
|
707
712
|
},
|
|
708
713
|
"mediaPayload": {
|
|
709
714
|
"viewModel": {
|
|
710
|
-
"type": "
|
|
711
|
-
"subType": "PHOTO",
|
|
715
|
+
"type": "documentsPictures",
|
|
712
716
|
"acceptedFileTypes": "image/jpeg, image/png, image/heif, image/heic",
|
|
713
717
|
"dialog": {
|
|
714
718
|
"hideCross": false,
|
|
@@ -718,7 +722,11 @@
|
|
|
718
722
|
"chooseAnotherMediaLabel": "Choisir une autre photo",
|
|
719
723
|
"uploadProgressTitle": "Chargement de votre photo",
|
|
720
724
|
"errorUploadTitle": "Une erreur est survenue lors de l'envoi de votre photo",
|
|
721
|
-
"uploadPreviewTitle": "Nom de la photo
|
|
725
|
+
"uploadPreviewTitle": "Nom de la photo",
|
|
726
|
+
"defaultMediaType": {
|
|
727
|
+
"type": "PHOTO",
|
|
728
|
+
"subtype": "ROOM_PHOTO"
|
|
729
|
+
}
|
|
722
730
|
}
|
|
723
731
|
}
|
|
724
732
|
}
|
|
@@ -237,7 +237,7 @@ export const contentfulPlanner = (
|
|
|
237
237
|
throw new Error(`No sections found for ${PROJECT_PLANNER_SKELETON_CONTENT_TYPE}`);
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
for (const [index, section] of plannerSections
|
|
240
|
+
for (const [index, section] of plannerSections.entries()) {
|
|
241
241
|
sections[section.sys.id] = {
|
|
242
242
|
title: section.fields.title!,
|
|
243
243
|
position: index,
|
|
@@ -318,7 +318,7 @@ export default defineComponent({
|
|
|
318
318
|
if (tempTask.value?.viewModel?.sections) {
|
|
319
319
|
for (const section of tempTask.value.viewModel.sections) {
|
|
320
320
|
if (section?.options) {
|
|
321
|
-
for (const option of section
|
|
321
|
+
for (const option of section.options) {
|
|
322
322
|
if (
|
|
323
323
|
!isEqual(tempOptionValues.value[decorateValue(option.id)], decorateValue(option.value!)) ||
|
|
324
324
|
(tempOptionValues.value[decorateValue(option.id)] && !option.value)
|
|
@@ -351,7 +351,7 @@ export default defineComponent({
|
|
|
351
351
|
if (tempTask.value?.viewModel?.sections) {
|
|
352
352
|
for (const section of tempTask.value.viewModel.sections) {
|
|
353
353
|
if (section?.options) {
|
|
354
|
-
for (const option of section
|
|
354
|
+
for (const option of section.options) {
|
|
355
355
|
const newValue = tempOptionValues.value[decorateValue(option.id)];
|
|
356
356
|
const sanitizedNewValue = newValue !== undefined ? newValue : undefined ?? '';
|
|
357
357
|
const optionValues = tempTask.value?.optionValues ?? {};
|
|
@@ -30,11 +30,7 @@ const getAppointmentQualification = async (
|
|
|
30
30
|
: `/appointment-qualifications?range=${start}-${end}&groupId=${groupId}&appointmentId=${appointmentId}`;
|
|
31
31
|
const response = await clientApi.get(url);
|
|
32
32
|
|
|
33
|
-
return
|
|
34
|
-
JSON.stringify(response.data).replace(/:"([^"]+)"/g, (match, $1) => {
|
|
35
|
-
return `: "${he.escape($1)}"`;
|
|
36
|
-
}),
|
|
37
|
-
);
|
|
33
|
+
return response.data;
|
|
38
34
|
};
|
|
39
35
|
|
|
40
36
|
const saveAnswersByAppointmentQualificationId = async (appointmentQualificationId: string, data: any) => {
|
|
@@ -7,7 +7,7 @@ const Condition = (
|
|
|
7
7
|
) => {
|
|
8
8
|
const isAnswerMatching = (questionCode: string, answerCode: string) => {
|
|
9
9
|
const questionAnswers = answers.get(questionCode)!;
|
|
10
|
-
return questionAnswers[0]?.code === answerCode;
|
|
10
|
+
return questionAnswers ? questionAnswers[0]?.code === answerCode : false;
|
|
11
11
|
};
|
|
12
12
|
const isAnswerContaining = (questionCode: string, answerCode: string) => {
|
|
13
13
|
const questionAnswers = answers.get(questionCode)!;
|
package/src/types/pb/Scenario.ts
CHANGED
|
@@ -144,8 +144,8 @@ export interface ScenarioHistory {
|
|
|
144
144
|
export interface ScenarioState {
|
|
145
145
|
answers: Map<string, ScenarioStepAnswer[]>;
|
|
146
146
|
stepsToResume: ScenarioStep[];
|
|
147
|
-
currentStep: ScenarioStep |
|
|
148
|
-
displayedStep: ScenarioStep |
|
|
147
|
+
currentStep: ScenarioStep | undefined;
|
|
148
|
+
displayedStep: ScenarioStep | undefined;
|
|
149
149
|
history: ScenarioHistory;
|
|
150
150
|
refreshSteps: boolean;
|
|
151
151
|
}
|