project-booster-vue 9.3.1 → 9.6.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.3.1",
3
+ "version": "9.6.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
  }
@@ -7,7 +7,8 @@ import { successResolver, internalServerErrorResolver } from '../../../services/
7
7
  import {
8
8
  getProjectByIdResolver,
9
9
  getDoneAppointmentByIdResolver,
10
- getAppointmentByIdResolver,
10
+ getStoreAppointmentByIdResolver,
11
+ getVisioAppointmentByIdResolver,
11
12
  } from '../../../services/api/mocks/projectsMock';
12
13
 
13
14
  <Meta
@@ -54,12 +55,28 @@ The `PbProjectHub` component to access your project.
54
55
 
55
56
  <Canvas>
56
57
  <Story
57
- name="Showcase with appointment"
58
+ name="Showcase with store appointment"
58
59
  parameters={{
59
60
  controls: { disable: true },
60
61
  msw: [
61
62
  rest.get('/api/inhabitant-projects/:projectId', getProjectByIdResolver),
62
- rest.get('/api/inhabitant-projects/:projectId/main-appointment', getAppointmentByIdResolver),
63
+ rest.get('/api/inhabitant-projects/:projectId/main-appointment', getStoreAppointmentByIdResolver),
64
+ ],
65
+ }}
66
+ height="100vh"
67
+ >
68
+ {TemplateSandbox.bind({})}
69
+ </Story>
70
+ </Canvas>
71
+
72
+ <Canvas>
73
+ <Story
74
+ name="Showcase with visio appointment"
75
+ parameters={{
76
+ controls: { disable: true },
77
+ msw: [
78
+ rest.get('/api/inhabitant-projects/:projectId', getProjectByIdResolver),
79
+ rest.get('/api/inhabitant-projects/:projectId/main-appointment', getVisioAppointmentByIdResolver),
63
80
  ],
64
81
  }}
65
82
  height="100vh"
@@ -77,7 +94,7 @@ The `PbProjectHub` component to access your project.
77
94
  controls: { disable: true },
78
95
  msw: [
79
96
  rest.get('/api/inhabitant-projects/:projectId', getProjectByIdResolver),
80
- rest.get('/api/inhabitant-projects/:projectId/main-appointment', getAppointmentByIdResolver),
97
+ rest.get('/api/inhabitant-projects/:projectId/main-appointment', getStoreAppointmentByIdResolver),
81
98
  ],
82
99
  }}
83
100
  args={{
@@ -72,18 +72,36 @@
72
72
  class="pb-project-hub__appointment-notification"
73
73
  type="appointment"
74
74
  :title="appointment.appointmentDate"
75
- :link-label="readOnly ? '' : 'Préparez votre rendez-vous !'"
76
- :link-href="
75
+ :text="
77
76
  readOnly
78
77
  ? ''
79
- : `/projets/preparation-rendez-vous/cuisine.html?appointmentId=${appointment.appointmentId}&groupId=${appointment.groupId}&calendarId=${appointment.calendarId}&leadSourceDetail=Project_Space`
78
+ : appointment.appointmentDate.endsWith('en magasin')
79
+ ? 'N’oubliez pas !'
80
+ : 'Retrouvez le lien d\'accès à la visio-conférence dans le mail qui vous est envoyé. \n' +
81
+ 'N’oubliez pas !'
80
82
  "
83
+ :link-label="
84
+ readOnly
85
+ ? ''
86
+ : 'Ajoutez des plans aux mesures de votre pièce et des photos pour bien préparer le rendez-vous.'
87
+ "
88
+ @link-click="handleAppointmentLinkClick"
81
89
  />
82
90
  </m-flex>
83
91
  </m-flex>
84
92
  <m-flex v-if="isDocumentsDisplayed" class="pb-project-hub__section" direction="column" full-width>
85
93
  <div class="pb-project-hub__section-header">
86
- <div class="pb-project-hub__section-title">{{ titleDocument }}</div>
94
+ <div class="pb-project-hub__section-title-container">
95
+ <div class="pb-project-hub__section-title">{{ titleDocument }}</div>
96
+ <pb-media-upload
97
+ v-if="displayedDocuments && displayedDocuments.length > 0"
98
+ storeModuleName="documents"
99
+ :payload="DOCUMENT_UPLOAD_PAYLOAD"
100
+ acceptedFileTypes="image jpeg, image png, image heif, image heic, image/heif-sequence, image/heic-sequence, application
101
+ pdf"
102
+ @media-uploaded="handleDocumentUploaded"
103
+ />
104
+ </div>
87
105
  </div>
88
106
  <div class="pb-project-hub__section-content">
89
107
  <m-flex
@@ -383,7 +401,15 @@
383
401
  </m-flex>
384
402
  <m-flex v-if="isMediaDisplayed" class="pb-project-hub__section" direction="column" full-width>
385
403
  <div class="pb-project-hub__section-header">
386
- <div class="pb-project-hub__section-title">{{ titlePhotoInspiration }}</div>
404
+ <div class="pb-project-hub__section-title-container">
405
+ <div class="pb-project-hub__section-title">{{ titlePhotoInspiration }}</div>
406
+ <pb-media-upload
407
+ v-if="displayedInspirations && displayedInspirations.length > 0"
408
+ storeModuleName="documents"
409
+ :payload="MEDIA_UPLOAD_PAYLOAD"
410
+ @media-uploaded="handleMediaUploaded"
411
+ />
412
+ </div>
387
413
  </div>
388
414
  <div class="pb-project-hub__section-content">
389
415
  <m-flex
@@ -755,7 +781,7 @@
755
781
  </template>
756
782
 
757
783
  <script lang="ts">
758
- import { defineComponent } from 'vue';
784
+ import { defineComponent, nextTick } from 'vue';
759
785
  import { format } from 'date-fns';
760
786
  import Velocity from 'velocity-animate';
761
787
  import { mapGetters } from 'vuex';
@@ -789,6 +815,9 @@ import { Tool } from '@/types/pb/Tool';
789
815
  import { Configuration } from '@/types/pb/Configuration';
790
816
  import { Estimate } from '@/types/pb/Estimate';
791
817
  import { Task } from '@/types/pb/Task';
818
+ import PbMediaUpload from '@/components/media/upload/PbMediaUpload.vue';
819
+ import DOCUMENT_UPLOAD_PAYLOAD from '@/components/media/upload/document-upload-payload.json';
820
+ import MEDIA_UPLOAD_PAYLOAD from '@/components/media/upload/media-upload-payload.json';
792
821
 
793
822
  const BACK_ICON =
794
823
  'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
@@ -830,6 +859,7 @@ export default defineComponent({
830
859
  name: 'PbProjectHub',
831
860
 
832
861
  components: {
862
+ PbMediaUpload,
833
863
  MAccordion,
834
864
  MButton,
835
865
  MContainer,
@@ -917,6 +947,8 @@ export default defineComponent({
917
947
  showMoreButtonAnimationDelay: 0,
918
948
  BACK_ICON,
919
949
  TASK_MODEL,
950
+ DOCUMENT_UPLOAD_PAYLOAD,
951
+ MEDIA_UPLOAD_PAYLOAD,
920
952
  displayCategoriesDialog: false,
921
953
  }),
922
954
 
@@ -1338,6 +1370,26 @@ export default defineComponent({
1338
1370
  behavior: 'smooth',
1339
1371
  });
1340
1372
  },
1373
+
1374
+ handleDocumentUploaded() {
1375
+ this.$store.dispatch('documents/refreshMediaList');
1376
+ },
1377
+
1378
+ handleMediaUploaded() {
1379
+ this.$store.dispatch('media/refreshMediaList');
1380
+ },
1381
+
1382
+ handleAppointmentLinkClick() {
1383
+ this.$store.dispatch('sendEventToBus', {
1384
+ code: 'appointmentLinkClicked',
1385
+ payload: this.project.id,
1386
+ });
1387
+ nextTick(() => {
1388
+ (<any>(
1389
+ window
1390
+ )).location = `/projets/preparation-rendez-vous/cuisine.html?inhabitantProjectId=${this.project.id}&appointmentId=${this.appointment.appointmentId}&groupId=${this.appointment.groupId}&calendarId=${this.appointment.calendarId}&leadSourceDetail=Project_Space`;
1391
+ });
1392
+ },
1341
1393
  },
1342
1394
  });
1343
1395
  </script>
@@ -1403,6 +1455,11 @@ $appear-duration: 100ms;
1403
1455
 
1404
1456
  &-header {
1405
1457
  padding-bottom: $mu150;
1458
+ width: 100%;
1459
+ }
1460
+
1461
+ &-title-container {
1462
+ display: flex;
1406
1463
  }
1407
1464
 
1408
1465
  &-title {
@@ -1410,6 +1467,7 @@ $appear-duration: 100ms;
1410
1467
  @include set-font-scale('07', 'm');
1411
1468
 
1412
1469
  color: $color-grey-800;
1470
+ flex-grow: 1;
1413
1471
  }
1414
1472
 
1415
1473
  &-subtitle {
@@ -432,14 +432,13 @@ export default defineComponent({
432
432
  const questionPossibleAnswer = this.questionPossibleAnswers.get(answerCode);
433
433
  if (
434
434
  questionPossibleAnswer &&
435
- (questionPossibleAnswer?.selected ||
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) &&
435
+ answerValues.findIndex(
436
+ (answer: ScenarioStepAnswer | string) =>
437
+ (typeof answer === 'string' && answer === answerCode) ||
438
+ (typeof answer === 'object' &&
439
+ (<ScenarioStepAnswer>answer)?.code === answerCode &&
440
+ (<ScenarioStepAnswer>answer)?.selected),
441
+ ) >= 0 &&
443
442
  areConditionsValid(questionPossibleAnswer.conditions!, this.answers, this.runtimeOptions)
444
443
  ) {
445
444
  this.selectedAnswers.set(answerCode, true);
@@ -499,10 +498,9 @@ export default defineComponent({
499
498
  if (!this.payload.multiSelect) {
500
499
  this.initAnswersSelectedState(this.payload.answers);
501
500
  }
502
- answer.selected = !answer.selected;
503
501
 
504
502
  if (this.payload.multiSelect) {
505
- this.selectedAnswers.set(answer.code, answer.selected);
503
+ this.selectedAnswers.set(answer.code, !this.selectedAnswers.get(answer.code) ?? true);
506
504
 
507
505
  const selected = Object.fromEntries(Object.entries(this.selectedAnswers).filter(([, value]) => value === true));
508
506
  /**
@@ -514,7 +512,7 @@ export default defineComponent({
514
512
  Object.keys(Object.fromEntries(this.selectedAnswers)).forEach((answerCode) => {
515
513
  this.selectedAnswers.set(answerCode, false);
516
514
  });
517
- this.selectedAnswers.set(answer.code, answer.selected);
515
+ this.selectedAnswers.set(answer.code, !this.selectedAnswers.get(answer.code) ?? true);
518
516
 
519
517
  /**
520
518
  * Emitted when step is completed
@@ -289,7 +289,12 @@ export default defineComponent({
289
289
  let stepIndex = state.value.history.stepIndex - 1;
290
290
 
291
291
  const steps = state.value.history.steps ?? [];
292
- while (stepIndex > 0 && steps[stepIndex - 1].step.type !== 'STEP') {
292
+ while (
293
+ stepIndex > 0 &&
294
+ steps[stepIndex - 1] &&
295
+ steps[stepIndex - 1].step &&
296
+ steps[stepIndex - 1].step.type !== 'STEP'
297
+ ) {
293
298
  stepIndex--;
294
299
  }
295
300
 
@@ -356,7 +361,13 @@ export default defineComponent({
356
361
  }
357
362
  };
358
363
  const goToStep = (stepIndex: number) => {
359
- let requestedStep = state.value.history?.steps?.[stepIndex - 1];
364
+ let requestedStep = state.value.history?.steps ? state.value.history.steps[stepIndex - 1] : undefined;
365
+
366
+ if (!requestedStep) {
367
+ requestedStep = state.value.history?.steps
368
+ ? state.value.history.steps[state.value.history.stepIndex - 1]
369
+ : undefined;
370
+ }
360
371
 
361
372
  if (requestedStep) {
362
373
  if (requestedStep.step.resetAnswersOnBack) {
@@ -231,7 +231,14 @@
231
231
  }
232
232
  }
233
233
  },
234
- "appointment": {
234
+ "storeAppointment": {
235
+ "groupId": 188921,
236
+ "calendarId": 375614,
237
+ "appointnmentId": 3200901,
238
+ "appointmentDate": "RDV le samedi 4 Décembre à 16h00 en magasin",
239
+ "isPast": false
240
+ },
241
+ "visioAppointment": {
235
242
  "groupId": 188921,
236
243
  "calendarId": 375614,
237
244
  "appointnmentId": 3200901,
@@ -1,5 +1,12 @@
1
1
  import { RestRequest, ResponseComposition, RestContext } from 'msw';
2
- import { projectsEmpty, projects, projectAttributes, appointment, doneAppointment } from './jsons/projects.json';
2
+ import {
3
+ projectsEmpty,
4
+ projects,
5
+ projectAttributes,
6
+ storeAppointment,
7
+ visioAppointment,
8
+ doneAppointment,
9
+ } from './jsons/projects.json';
3
10
 
4
11
  export const getEmptyProjectsResolver = (req: RestRequest, res: ResponseComposition, ctx: RestContext) => {
5
12
  return res(
@@ -57,8 +64,12 @@ export const getProjectAttributesByIdResolver = (req: RestRequest, res: Response
57
64
  return res(ctx.status(200), ctx.json(projectAttributes));
58
65
  };
59
66
 
60
- export const getAppointmentByIdResolver = (req: RestRequest, res: ResponseComposition, ctx: RestContext) => {
61
- return res(ctx.status(200), ctx.json(appointment));
67
+ export const getStoreAppointmentByIdResolver = (req: RestRequest, res: ResponseComposition, ctx: RestContext) => {
68
+ return res(ctx.status(200), ctx.json(storeAppointment));
69
+ };
70
+
71
+ export const getVisioAppointmentByIdResolver = (req: RestRequest, res: ResponseComposition, ctx: RestContext) => {
72
+ return res(ctx.status(200), ctx.json(visioAppointment));
62
73
  };
63
74
 
64
75
  export const getDoneAppointmentByIdResolver = (req: RestRequest, res: ResponseComposition, ctx: RestContext) => {