project-booster-vue 9.2.4 → 9.4.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-booster-vue",
3
- "version": "9.2.4",
3
+ "version": "9.4.0",
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.21",
85
- "@storybook/addon-essentials": "6.4.21",
84
+ "@storybook/addon-a11y": "6.4.22",
85
+ "@storybook/addon-essentials": "6.4.22",
86
86
  "@storybook/addon-knobs": "6.3.1",
87
- "@storybook/addon-links": "6.4.21",
87
+ "@storybook/addon-links": "6.4.22",
88
88
  "@storybook/addon-postcss": "2.0.0",
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",
89
+ "@storybook/addon-storyshots": "6.4.22",
90
+ "@storybook/addon-storyshots-puppeteer": "6.4.22",
91
+ "@storybook/addon-storysource": "6.4.22",
92
+ "@storybook/addons": "6.4.22",
93
+ "@storybook/builder-webpack5": "6.4.22",
94
+ "@storybook/manager-webpack5": "6.4.22",
95
+ "@storybook/source-loader": "6.4.22",
96
96
  "@storybook/storybook-deployer": "2.8.11",
97
- "@storybook/theming": "6.4.21",
98
- "@storybook/vue3": "6.4.21",
97
+ "@storybook/theming": "6.4.22",
98
+ "@storybook/vue3": "6.4.22",
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,7 +147,7 @@
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.8",
150
+ "eslint-plugin-storybook": "0.5.10",
151
151
  "eslint-plugin-vue": "7.11.1",
152
152
  "fluent-json-schema": "3.0.1",
153
153
  "husky": "6.0.0",
@@ -25,9 +25,14 @@
25
25
  "label": "Un plan d’architecte"
26
26
  },
27
27
  {
28
- "type": "PLAN",
29
- "subtype": "KITCHEN_DESIGNER_PLAN",
30
- "label": "Un plan d’un autre cuisiniste"
28
+ "type": "PHOTO",
29
+ "subtype": "ANY",
30
+ "label": "Une photo"
31
+ },
32
+ {
33
+ "type": "OTHER",
34
+ "subtype": "ANY",
35
+ "label": "Autre"
31
36
  }
32
37
  ]
33
38
  }
@@ -83,7 +83,17 @@
83
83
  </m-flex>
84
84
  <m-flex v-if="isDocumentsDisplayed" class="pb-project-hub__section" direction="column" full-width>
85
85
  <div class="pb-project-hub__section-header">
86
- <div class="pb-project-hub__section-title">{{ titleDocument }}</div>
86
+ <div class="pb-project-hub__section-title-container">
87
+ <div class="pb-project-hub__section-title">{{ titleDocument }}</div>
88
+ <pb-media-upload
89
+ v-if="displayedDocuments && displayedDocuments.length > 0"
90
+ storeModuleName="documents"
91
+ :payload="DOCUMENT_UPLOAD_PAYLOAD"
92
+ acceptedFileTypes="image jpeg, image png, image heif, image heic, image/heif-sequence, image/heic-sequence, application
93
+ pdf"
94
+ @media-uploaded="handleDocumentUploaded"
95
+ />
96
+ </div>
87
97
  </div>
88
98
  <div class="pb-project-hub__section-content">
89
99
  <m-flex
@@ -137,6 +147,46 @@
137
147
  />
138
148
  </div>
139
149
  </m-flex>
150
+ <m-flex
151
+ v-if="areProjectAttributesDisplayed && projectAttributes && Object.keys(projectAttributes).length > 0"
152
+ class="pb-project-hub__section"
153
+ direction="column"
154
+ full-width
155
+ >
156
+ <div class="pb-project-hub__section-header">
157
+ <div class="pb-project-hub__section-title" ref="pbProjectAttributeList">
158
+ {{ titleProjectAttribute }}
159
+ </div>
160
+ </div>
161
+ <div class="pb-project-hub__section-content">
162
+ <m-flex
163
+ class="pb-project-hub__section-content--loading"
164
+ v-if="isLoadingProjectAttributes && !projectAttributesLoadError"
165
+ direction="column"
166
+ align-items="center"
167
+ justify-content="center"
168
+ align-content="center"
169
+ >
170
+ <pb-animable-loader class="pb-project-hub__section-content--loading-loader" />
171
+ <div class="pb-project-hub__section-content--loading-label">Chargement...</div>
172
+ </m-flex>
173
+ <pb-empty-state
174
+ v-else-if="project && Object.values(projectAttributes).length === 0 && !projectAttributesLoadError"
175
+ subtitle="Aucune information renseignée"
176
+ disabled
177
+ />
178
+ <m-container
179
+ class="pb-project-hub__section-content-cards-container"
180
+ fluid
181
+ v-else-if="project && projectAttributes && !projectAttributesLoadError"
182
+ >
183
+ <pb-project-attributes :project-attributes="projectAttributes" />
184
+ </m-container>
185
+ <m-flex v-else-if="projectAttributesLoadError" direction="column" align-items="center">
186
+ <div>Une erreur est survenue</div>
187
+ </m-flex>
188
+ </div>
189
+ </m-flex>
140
190
  <m-flex
141
191
  v-if="isEstimatesDisplayed"
142
192
  class="pb-project-hub__section"
@@ -343,7 +393,15 @@
343
393
  </m-flex>
344
394
  <m-flex v-if="isMediaDisplayed" class="pb-project-hub__section" direction="column" full-width>
345
395
  <div class="pb-project-hub__section-header">
346
- <div class="pb-project-hub__section-title">{{ titlePhotoInspiration }}</div>
396
+ <div class="pb-project-hub__section-title-container">
397
+ <div class="pb-project-hub__section-title">{{ titlePhotoInspiration }}</div>
398
+ <pb-media-upload
399
+ v-if="displayedInspirations && displayedInspirations.length > 0"
400
+ storeModuleName="documents"
401
+ :payload="MEDIA_UPLOAD_PAYLOAD"
402
+ @media-uploaded="handleMediaUploaded"
403
+ />
404
+ </div>
347
405
  </div>
348
406
  <div class="pb-project-hub__section-content">
349
407
  <m-flex
@@ -401,46 +459,6 @@
401
459
  />
402
460
  </div>
403
461
  </m-flex>
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
- >
410
- <div class="pb-project-hub__section-header">
411
- <div class="pb-project-hub__section-title" ref="pbProjectAttributeList">
412
- {{ titleProjectAttribute }}
413
- </div>
414
- </div>
415
- <div class="pb-project-hub__section-content">
416
- <m-flex
417
- class="pb-project-hub__section-content--loading"
418
- v-if="isLoadingProjectAttributes && !projectAttributesLoadError"
419
- direction="column"
420
- align-items="center"
421
- justify-content="center"
422
- align-content="center"
423
- >
424
- <pb-animable-loader class="pb-project-hub__section-content--loading-loader" />
425
- <div class="pb-project-hub__section-content--loading-label">Chargement...</div>
426
- </m-flex>
427
- <pb-empty-state
428
- v-else-if="project && Object.values(projectAttributes).length === 0 && !projectAttributesLoadError"
429
- subtitle="Aucune information renseignée"
430
- disabled
431
- />
432
- <m-container
433
- class="pb-project-hub__section-content-cards-container"
434
- fluid
435
- v-else-if="project && projectAttributes && !projectAttributesLoadError"
436
- >
437
- <pb-project-attributes :project-attributes="projectAttributes" />
438
- </m-container>
439
- <m-flex v-else-if="projectAttributesLoadError" direction="column" align-items="center">
440
- <div>Une erreur est survenue</div>
441
- </m-flex>
442
- </div>
443
- </m-flex>
444
462
  <m-flex
445
463
  v-if="isPlannerDisplayed"
446
464
  class="pb-project-hub__section pb-project-hub__planner-section"
@@ -789,6 +807,9 @@ import { Tool } from '@/types/pb/Tool';
789
807
  import { Configuration } from '@/types/pb/Configuration';
790
808
  import { Estimate } from '@/types/pb/Estimate';
791
809
  import { Task } from '@/types/pb/Task';
810
+ import PbMediaUpload from '@/components/media/upload/PbMediaUpload.vue';
811
+ import DOCUMENT_UPLOAD_PAYLOAD from '@/components/media/upload/document-upload-payload.json';
812
+ import MEDIA_UPLOAD_PAYLOAD from '@/components/media/upload/media-upload-payload.json';
792
813
 
793
814
  const BACK_ICON =
794
815
  'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
@@ -830,6 +851,7 @@ export default defineComponent({
830
851
  name: 'PbProjectHub',
831
852
 
832
853
  components: {
854
+ PbMediaUpload,
833
855
  MAccordion,
834
856
  MButton,
835
857
  MContainer,
@@ -917,6 +939,8 @@ export default defineComponent({
917
939
  showMoreButtonAnimationDelay: 0,
918
940
  BACK_ICON,
919
941
  TASK_MODEL,
942
+ DOCUMENT_UPLOAD_PAYLOAD,
943
+ MEDIA_UPLOAD_PAYLOAD,
920
944
  displayCategoriesDialog: false,
921
945
  }),
922
946
 
@@ -1338,6 +1362,14 @@ export default defineComponent({
1338
1362
  behavior: 'smooth',
1339
1363
  });
1340
1364
  },
1365
+
1366
+ handleDocumentUploaded() {
1367
+ this.$store.dispatch('documents/refreshMediaList');
1368
+ },
1369
+
1370
+ handleMediaUploaded() {
1371
+ this.$store.dispatch('media/refreshMediaList');
1372
+ },
1341
1373
  },
1342
1374
  });
1343
1375
  </script>
@@ -1403,6 +1435,11 @@ $appear-duration: 100ms;
1403
1435
 
1404
1436
  &-header {
1405
1437
  padding-bottom: $mu150;
1438
+ width: 100%;
1439
+ }
1440
+
1441
+ &-title-container {
1442
+ display: flex;
1406
1443
  }
1407
1444
 
1408
1445
  &-title {
@@ -1410,6 +1447,7 @@ $appear-duration: 100ms;
1410
1447
  @include set-font-scale('07', 'm');
1411
1448
 
1412
1449
  color: $color-grey-800;
1450
+ flex-grow: 1;
1413
1451
  }
1414
1452
 
1415
1453
  &-subtitle {
@@ -427,8 +427,8 @@ export default defineComponent({
427
427
  this.pageSize = this.payload.viewModel.showMore.itemsPerPage;
428
428
  }
429
429
 
430
+ const answerValues = this.answers?.get(this.stepName ?? '') ?? [];
430
431
  for (const { code: answerCode } of Object.values(Object.fromEntries(this.questionPossibleAnswers))) {
431
- const answerValues = this.answers?.get(this.stepName ?? '') ?? [];
432
432
  const questionPossibleAnswer = this.questionPossibleAnswers.get(answerCode);
433
433
  if (
434
434
  questionPossibleAnswer &&
@@ -195,7 +195,10 @@ export default defineComponent({
195
195
  remainingSteps: 0,
196
196
  });
197
197
  const reverseAnimation = ref(false);
198
+ const forceRefresh = ref(false);
198
199
  const noPointerEvents = ref(false);
200
+ const stepAnimationTimeoutId = ref<ReturnType<typeof setTimeout>>();
201
+ const progressUpdateTimeoutId = ref<ReturnType<typeof setTimeout>>();
199
202
 
200
203
  const initScenario = (currentScenarioCode: string, stepToResume: ScenarioStep | undefined = undefined) => {
201
204
  if (currentScenarioCode === '__START__') {
@@ -312,6 +315,7 @@ export default defineComponent({
312
315
  currentStep: state.value.currentStep,
313
316
  stepIndex: state.value.history.stepIndex,
314
317
  stepHistory: state.value.history.steps,
318
+ stepsToResume: state.value.stepsToResume,
315
319
  },
316
320
  });
317
321
  };
@@ -395,36 +399,42 @@ export default defineComponent({
395
399
  }
396
400
  };
397
401
  const updateProgressInScenario = () => {
398
- if (state.value.stepsToResume.slice(-1)[0]?.trackProgress) {
399
- // Use current step props
400
- setTimeout(() => {
401
- progress.value = {
402
- ...progress.value,
403
- ...trackProgress(state.value.history.stepIndex - 1, state.value.history.steps!),
404
- };
405
-
406
- progress.value.progress =
407
- (100 * (progress.value.currentPosition - 1)) /
408
- (progress.value.currentPosition + progress.value.remainingSteps);
409
- }, 450);
410
- } else if (state.value.stepsToResume.slice(-2, -1)[0]?.trackProgress) {
411
- // Use current last progress tracked scenario step props for first step of nested scenario
412
- setTimeout(() => {
413
- const currentProgress = trackProgress(state.value.history.stepIndex - 1, state.value.history.steps!);
414
-
415
- if (currentProgress.currentPosition === 1) {
416
- const previousProgress = trackProgress(state.value.history.stepIndex - 3, state.value.history.steps!);
417
- previousProgress.currentPosition++;
418
- previousProgress.remainingSteps--;
402
+ if (state.value.stepsToResume) {
403
+ if (progressUpdateTimeoutId.value) {
404
+ clearTimeout(progressUpdateTimeoutId.value);
405
+ }
406
+
407
+ if (state.value.stepsToResume.slice(-1)[0]?.trackProgress) {
408
+ // Use current step props
409
+ progressUpdateTimeoutId.value = setTimeout(() => {
419
410
  progress.value = {
420
411
  ...progress.value,
421
- ...previousProgress,
412
+ ...trackProgress(state.value.history.stepIndex - 1, state.value.history.steps!),
422
413
  };
414
+
423
415
  progress.value.progress =
424
416
  (100 * (progress.value.currentPosition - 1)) /
425
417
  (progress.value.currentPosition + progress.value.remainingSteps);
426
- }
427
- }, 450);
418
+ }, 450);
419
+ } else if (state.value.stepsToResume.slice(-2, -1)[0]?.trackProgress) {
420
+ // Use current last progress tracked scenario step props for first step of nested scenario
421
+ progressUpdateTimeoutId.value = setTimeout(() => {
422
+ const currentProgress = trackProgress(state.value.history.stepIndex - 1, state.value.history.steps!);
423
+
424
+ if (currentProgress.currentPosition === 1) {
425
+ const previousProgress = trackProgress(state.value.history.stepIndex - 3, state.value.history.steps!);
426
+ previousProgress.currentPosition++;
427
+ previousProgress.remainingSteps--;
428
+ progress.value = {
429
+ ...progress.value,
430
+ ...previousProgress,
431
+ };
432
+ progress.value.progress =
433
+ (100 * (progress.value.currentPosition - 1)) /
434
+ (progress.value.currentPosition + progress.value.remainingSteps);
435
+ }
436
+ }, 450);
437
+ }
428
438
  }
429
439
  };
430
440
  const trackProgress = (originIndex: number, steps: ScenarioHistoryItem[]) => {
@@ -469,7 +479,11 @@ export default defineComponent({
469
479
  const animateDisplayedStep = (reversed = false) => {
470
480
  reverseAnimation.value = reversed;
471
481
 
472
- setTimeout(() => {
482
+ if (stepAnimationTimeoutId.value) {
483
+ clearTimeout(stepAnimationTimeoutId.value);
484
+ }
485
+
486
+ stepAnimationTimeoutId.value = setTimeout(() => {
473
487
  nextTick(() => {
474
488
  state.value.displayedStep = state.value.currentStep;
475
489
  setTimeout(() => {
@@ -580,7 +594,8 @@ export default defineComponent({
580
594
  watch(route, () => {
581
595
  const requestedStepIndex = route.params?.stepCode as string;
582
596
 
583
- if (requestedStepIndex && requestedStepIndex !== `${state.value.history.stepIndex}`) {
597
+ if ((requestedStepIndex && requestedStepIndex !== `${state.value.history.stepIndex}`) || forceRefresh.value) {
598
+ forceRefresh.value = false;
584
599
  goToStep(parseInt(requestedStepIndex));
585
600
  }
586
601
  });
@@ -609,7 +624,9 @@ export default defineComponent({
609
624
  if (state.value.answers && !(state.value.answers instanceof Map)) {
610
625
  state.value.answers = new Map<string, ScenarioStepAnswer[]>(Object.entries(state.value.answers));
611
626
  }
612
- goToStep(state.value.history.stepIndex);
627
+ const newRoute = `/steps/${state.value.history.stepIndex}/previous/${uuidv4()}`;
628
+ forceRefresh.value = true;
629
+ router.replace(newRoute);
613
630
  }
614
631
  },
615
632
  );
@@ -147,7 +147,6 @@ export interface ScenarioState {
147
147
  currentStep: ScenarioStep | undefined;
148
148
  displayedStep: ScenarioStep | undefined;
149
149
  history: ScenarioHistory;
150
- refreshSteps: boolean;
151
150
  }
152
151
 
153
152
  export interface ScenarioStepAnswerData {