project-booster-vue 9.43.1 → 9.43.3

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.43.1",
3
+ "version": "9.43.3",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -1278,11 +1278,12 @@ $answers-apparition-duration: '0.5s';
1278
1278
  &__dialog-help {
1279
1279
  &__title {
1280
1280
  padding: $mu250 $mu250 0 $mu250;
1281
+ @include set-font-scale('06', 'm');
1281
1282
  }
1282
1283
 
1283
1284
  &__body {
1284
1285
  padding: 0 $mu250;
1285
- @include set-font-scale('05', 'l');
1286
+ @include set-font-scale('06', 'm');
1286
1287
  &__image {
1287
1288
  background-size: cover;
1288
1289
  padding: 120px 0;
@@ -1,20 +1,18 @@
1
1
  <template>
2
- <m-flex align-items="center" direction="column">
3
- <m-flex
4
- :class="`pb-restitution-list`"
5
- align-items="center"
6
- justify-content="center"
7
- direction="column"
8
- ref="pbRestitutionList"
9
- >
10
- <m-link
11
- v-if="showBackButton"
12
- :left-icon="BACK_ICON"
13
- :label="payload.backLabel || 'Modifier l\'estimation'"
14
- class="pb-restitution-list__back-button"
15
- @click.once="$emit('go-back')"
16
- />
17
- </m-flex>
2
+ <m-flex
3
+ :class="`pb-restitution-list`"
4
+ align-items="center"
5
+ justify-content="flex-start"
6
+ direction="column"
7
+ ref="pbRestitutionList"
8
+ >
9
+ <m-link
10
+ v-if="showBackButton"
11
+ :left-icon="BACK_ICON"
12
+ :label="payload.backLabel || 'Modifier l\'estimation'"
13
+ class="pb-restitution-list__back-button"
14
+ @click.once="$emit('go-back')"
15
+ />
18
16
  <div class="pb-restitution-list__title">{{ payload?.viewModel?.title }}</div>
19
17
 
20
18
  <div class="pb-restitution-list__line">
@@ -23,6 +21,7 @@
23
21
  v-for="component in summary.components"
24
22
  :key="component.componentId"
25
23
  :payload="component"
24
+ :legalMentions="payload?.viewModel?.legalMentions"
26
25
  ></pb-restitution-list-block>
27
26
  </div>
28
27
 
@@ -43,26 +42,28 @@
43
42
  />
44
43
  </m-flex>
45
44
  </m-flex>
45
+ </m-flex>
46
46
 
47
- <m-flex class="pb-restitution-list__footer" direction="row" align-items="center" justify-content="center">
48
- <div class="pb-restitution-list__footer__call" v-for="button in payload.callToActions" :key="button.label">
49
- <m-button
50
- :label="button.label"
51
- @click="callAction(button.action)"
52
- :theme="button.bordered ? 'bordered' : 'solid'"
53
- v-if="areConditionsValid(button.conditions)"
54
- />
55
- </div>
56
- <div class="pb-restitution-list__footer__save">
57
- <pb-project-item-save
58
- v-model:show-save-item="showSaveProjectItem"
59
- @item-saved="handleItemCreated"
60
- @dialog-close="handleDialogClose"
61
- v-if="isLoggedIn"
62
- />
63
- </div>
64
- </m-flex>
47
+ <m-flex class="pb-restitution-list__footer" direction="row" align-items="center" justify-content="center">
48
+ <div class="pb-restitution-list__footer__call" v-for="button in payload.callToActions" :key="button.label">
49
+ <m-button
50
+ :label="button.label"
51
+ @click="callAction(button.action)"
52
+ :theme="button.bordered ? 'bordered' : 'solid'"
53
+ v-if="areConditionsValid(button.conditions)"
54
+ />
55
+ </div>
56
+ <div class="pb-restitution-list__footer__save">
57
+ <pb-project-item-save
58
+ v-model:show-save-item="showSaveProjectItem"
59
+ @item-saved="handleItemCreated"
60
+ @dialog-close="handleDialogClose"
61
+ v-if="isLoggedIn"
62
+ />
63
+ </div>
64
+ </m-flex>
65
65
 
66
+ <div>
66
67
  <m-dialog
67
68
  class="pb-restitution-list__modal"
68
69
  :show-dialog="showDialog"
@@ -79,10 +80,13 @@
79
80
  <div class="pb-restitution-list__modal__details__row__title" justify-content="space-between">
80
81
  <div v-html="component.title"></div>
81
82
  <div v-if="component.cost.min != component.cost.max">
82
- <strong>{{ component.cost.min }}€ et {{ component.cost.max }}€</strong>
83
+ <strong>
84
+ {{ formattedPriceRange(component.cost.min) }} et
85
+ {{ formattedPriceRange(component.cost.max) }}
86
+ </strong>
83
87
  </div>
84
88
  <div v-else>
85
- <strong>{{ component.cost.min }}€</strong>
89
+ <strong>{{ formattedPriceRange(component.cost.min) }}</strong>
86
90
  </div>
87
91
  </div>
88
92
 
@@ -100,8 +104,12 @@
100
104
  <div>
101
105
  <li>
102
106
  <div v-html="line.text"></div>
103
- <div v-if="line.cost.min != line.cost.max">{{ line.cost.min }}€ et {{ line.cost.max }}€</div>
104
- <div v-else>{{ line.cost.min }}€</div>
107
+ <m-flex v-if="line.cost.min != line.cost.max" align-items="center" justify-content="flex-end">
108
+ <span v-html="formattedPriceRange(line.cost.min)"></span>
109
+ <span>&nbsp;et&nbsp;</span>
110
+ <span v-html="formattedPriceRange(line.cost.max)"></span>
111
+ </m-flex>
112
+ <div v-else v-html="formattedPriceRange(line.cost.min)"></div>
105
113
  </li>
106
114
  </div>
107
115
  </ul>
@@ -110,12 +118,12 @@
110
118
  </div>
111
119
 
112
120
  <div class="pb-restitution-list__modal__details__totals" justify-content="space-between" align-items="center">
113
- <div><strong>Montant total</strong> (aides déduites)</div>
121
+ <div><strong>Montant total</strong>&nbsp; (aides déduites)</div>
114
122
  <div class="space-mx">entre</div>
115
123
  <div>
116
- <strong>{{ summary.cost.min }}€</strong>
124
+ <strong v-html="formattedPriceRange(summary.cost.min)"></strong>
117
125
  <div class="space-mx">et</div>
118
- <strong>{{ summary.cost.max }}€</strong>
126
+ <strong v-html="formattedPriceRange(summary.cost.max)"></strong>
119
127
  </div>
120
128
  </div>
121
129
  </div>
@@ -126,7 +134,7 @@
126
134
  </m-flex>
127
135
  </template>
128
136
  </m-dialog>
129
- </m-flex>
137
+ </div>
130
138
  </template>
131
139
 
132
140
  <script lang="ts">
@@ -144,6 +152,7 @@ import { ScenarioStepAnswer } from '@/types/pb/Scenario';
144
152
  import PbRestitutionListBlock from './PbRestitutionListBlock.vue';
145
153
  import { Project } from '../../types/pb/Project';
146
154
  import { areConditionsValid } from '../../services/scenarioConditionals';
155
+ import { priceFormatter } from '@/services/priceFormatter';
147
156
  const BACK_ICON =
148
157
  'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
149
158
 
@@ -219,6 +228,9 @@ export default defineComponent({
219
228
  }
220
229
  },
221
230
  methods: {
231
+ formattedPriceRange(price: any) {
232
+ return Math.round(price).toLocaleString() + '€';
233
+ },
222
234
  handleShowDialog(content: any) {
223
235
  this.dialogContent = content;
224
236
  this.showDialog = !this.showDialog;
@@ -292,12 +304,9 @@ $responsive-breakpoint: 'm';
292
304
 
293
305
  .pb-restitution-list {
294
306
  @include set-font-face('regular');
295
- align-items: center;
296
- display: flex;
297
- flex-direction: column;
298
- flex-grow: 1;
307
+ height: calc(100vh - 120px);
299
308
  margin: 0 auto;
300
- padding-bottom: $mu250;
309
+ padding-top: $mu250;
301
310
  position: relative;
302
311
  width: 100%;
303
312
 
@@ -308,8 +317,11 @@ $responsive-breakpoint: 'm';
308
317
 
309
318
  &__back-button {
310
319
  align-self: flex-start;
320
+ left: 0;
311
321
  opacity: 1;
312
322
  padding: $mu100 0 $mu100 $mu100;
323
+ position: absolute;
324
+ top: 0;
313
325
  transition: opacity 0.15s 0.5s;
314
326
  z-index: 2;
315
327
 
@@ -337,10 +349,12 @@ $responsive-breakpoint: 'm';
337
349
  &__footer {
338
350
  background: #ffffff;
339
351
  bottom: 0;
352
+ justify-self: flex-end;
340
353
  left: 0;
341
354
  padding: $mu100 0 $mu100 $mu025;
342
- position: fixed;
355
+ position: sticky;
343
356
  right: 0;
357
+ width: 100%;
344
358
  @include set-box-shadow('l');
345
359
 
346
360
  &__save,
@@ -7,8 +7,12 @@
7
7
  <div class="pb-restitution-list-line">
8
8
  <div class="pb-restitution-list-line__title" v-html="summary.components[0].title"></div>
9
9
  <div class="pb-restitution-list-line__price">
10
- <div class="pb-restitution-list-line__price__min">{{ summary.components[0].cost.min }}€&nbsp;et&nbsp;</div>
11
- <div class="pb-restitution-list-line__price__max">{{ summary.components[0].cost.max }}€</div>
10
+ <div class="pb-restitution-list-line__price__min">
11
+ {{ formattedPriceRange(summary.components[0].cost.min) }}&nbsp;et&nbsp;
12
+ </div>
13
+ <div class="pb-restitution-list-line__price__max">
14
+ {{ formattedPriceRange(summary.components[0].cost.max) }}
15
+ </div>
12
16
  </div>
13
17
  </div>
14
18
 
@@ -35,7 +39,8 @@
35
39
  <div><strong>Montant total</strong> (aides déduites)</div>
36
40
  <div class="pb-restitution-list-block__body__row__title__amount">
37
41
  <div>entre</div>
38
- <strong>{{ summary.cost.min }}€</strong> et <strong>{{ summary.cost.max }}€</strong>
42
+ <strong>{{ formattedPriceRange(summary.cost.min) }}</strong> et
43
+ <strong>{{ formattedPriceRange(summary.cost.max) }}</strong>
39
44
  </div>
40
45
  </div>
41
46
  </div>
@@ -49,6 +54,10 @@
49
54
  />
50
55
  </div>
51
56
  </m-flex>
57
+
58
+ <div class="pb-restitution-list-block__legal-mentions">
59
+ <p v-for="(mention, index) in legalMentions" :key="'lm-' + index">{{ mention }}</p>
60
+ </div>
52
61
  </m-flex>
53
62
  </template>
54
63
 
@@ -72,6 +81,11 @@ export default defineComponent({
72
81
  default: () => ({}),
73
82
  required: true,
74
83
  },
84
+ legalMentions: {
85
+ type: Array,
86
+ default: () => [],
87
+ required: false,
88
+ },
75
89
  },
76
90
  computed: {
77
91
  ...mapGetters('estimates', { summary: 'getSummary' }),
@@ -80,6 +94,9 @@ export default defineComponent({
80
94
  handleLinkClick(details: any) {
81
95
  this.$emit('button', details);
82
96
  },
97
+ formattedPriceRange(price: any) {
98
+ return Math.round(price).toLocaleString() + '€';
99
+ },
83
100
  },
84
101
  });
85
102
  </script>
@@ -90,7 +107,7 @@ $responsive-breakpoint: 'm';
90
107
 
91
108
  .pb-restitution-list-block {
92
109
  @include set-box-shadow('l');
93
- margin-bottom: $mu250;
110
+ margin-bottom: $mu100;
94
111
  padding: $mu150;
95
112
  width: 80%;
96
113
 
@@ -175,6 +192,19 @@ $responsive-breakpoint: 'm';
175
192
  }
176
193
  }
177
194
  }
195
+
196
+ &__legal-mentions {
197
+ color: $color-grey-600;
198
+ margin-bottom: $mu050;
199
+ width: 80%;
200
+
201
+ @include set-from-screen($responsive-breakpoint) {
202
+ width: 630px;
203
+ }
204
+
205
+ @include set-font-face('regular');
206
+ @include set-font-scale('04', 'm');
207
+ }
178
208
  }
179
209
 
180
210
  .pb-restitution-list-line {
@@ -8,8 +8,8 @@
8
8
  <div class="pb-restitution-list-line__price__max">{{ formatPriceRange(line.cost.min, line.cost.max).max }}€</div>
9
9
  </div>
10
10
  <div class="pb-restitution-list-line__price">
11
- <span v-if="line.cost.min === line.cost.max">{{ line.cost.min }}€</span>
12
- <span v-else>{{ line.cost.min }} et {{ line.cost.max }}€</span>
11
+ <span v-if="line.cost.min === line.cost.max">{{ formatPriceRange(line.cost.min) }}</span>
12
+ <span v-else>{{ formattedPriceRange(line.cost.min) }} et {{ formattedPriceRange(line.cost.max) }}</span>
13
13
  </div>
14
14
  </div>
15
15
  </template>
@@ -31,15 +31,17 @@ export default defineComponent({
31
31
  type: Boolean,
32
32
  default: () => false,
33
33
  },
34
+ formatPriceRange: {
35
+ type: Function,
36
+ default: () => '',
37
+ },
34
38
  },
35
39
  methods: {
36
40
  handleLinkClick() {
37
41
  this.$emit('button', true);
38
42
  },
39
- formatPriceRange(min: number, max: number) {
40
- if (min < max) {
41
- return { min, max };
42
- }
43
+ formattedPriceRange(price: any) {
44
+ return Math.round(price).toLocaleString() + '€';
43
45
  },
44
46
  },
45
47
  });
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "viewModel": {
3
- "title": "Votre estimation par travaux"
3
+ "title": "Votre estimation par travaux",
4
+ "legalMentions": [
5
+ "* Montant estimatif établi selon les réponses renseignées dans le questionnaire et susceptible d'être ajusté lors du devis définitif. Ce montant n’engage pas Leroy Merlin."
6
+ ]
4
7
  },
5
8
  "callToActions": [
6
9
  {
@@ -35,17 +35,6 @@
35
35
  ></m-text-input>
36
36
  </m-flex>
37
37
 
38
- <m-flex class="pb-trezor__form__row">
39
- <m-text-input
40
- v-model="formData.values.surface"
41
- :error="formData.errors.surface"
42
- type="text"
43
- label="Surface"
44
- :required="true"
45
- class="pb-trezor__input"
46
- ></m-text-input>
47
- </m-flex>
48
-
49
38
  <m-flex class="pb-trezor__form__row">
50
39
  <m-text-input
51
40
  v-model="formData.values.zipcode"
@@ -126,7 +115,7 @@ import MCheckbox from '../mozaic/checkbox/MCheckbox.vue';
126
115
  import MLink from '../mozaic/link/MLink.vue';
127
116
  import MTextInput from '../mozaic/text-input/MTextInput.vue';
128
117
  import { ScenarioStepAnswer } from '@/types/pb/Scenario';
129
- import { object, string, boolean } from 'yup';
118
+ import { object, string, boolean, number } from 'yup';
130
119
  import objectPath from 'object-path';
131
120
  const BACK_ICON =
132
121
  'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
@@ -197,11 +186,6 @@ export default defineComponent({
197
186
  props.payload.viewModel.defaultValue?.zipcode?.answerCode,
198
187
  props.payload.viewModel.defaultValue?.zipcode?.path,
199
188
  ) || null;
200
- const surface =
201
- getAnswerValue(
202
- props.payload.viewModel.defaultValue?.surface?.answerCode,
203
- props.payload.viewModel.defaultValue?.surface?.path,
204
- ) || null;
205
189
 
206
190
  let formData = ref<any>({
207
191
  values: {
@@ -209,7 +193,6 @@ export default defineComponent({
209
193
  firstname: '',
210
194
  zipcode: zipcode,
211
195
  email: '',
212
- surface: surface,
213
196
  phone: '',
214
197
  optin: false,
215
198
  optinPartners: false,
@@ -220,17 +203,23 @@ export default defineComponent({
220
203
  zipcode: '',
221
204
  email: '',
222
205
  phone: '',
223
- surface: '',
224
206
  },
225
207
  });
226
208
 
227
209
  const validationSchema = object({
228
210
  lastname: string().required(),
229
211
  firstname: string().required(),
230
- zipcode: string().required(),
212
+ zipcode: string()
213
+ .required()
214
+ .test(() => {
215
+ return formData.value.values.zipcode == null || formData.value.values.zipcode.length === 5;
216
+ }),
231
217
  email: string().email().required(),
232
- phone: string().required(),
233
- surface: string().required(),
218
+ phone: string()
219
+ .required()
220
+ .test(() => {
221
+ return formData.value.values.phone == null || formData.value.values.phone.length === 10;
222
+ }),
234
223
  optin: boolean(),
235
224
  optinPartners: boolean(),
236
225
  });
@@ -7,10 +7,6 @@
7
7
  "zipcode": {
8
8
  "answerCode": "LMFR_PREVIOUS_QUESTION",
9
9
  "path": "value"
10
- },
11
- "surface": {
12
- "answerCode": "LMFR_PREVIOUS_QUESTION",
13
- "path": "space"
14
10
  }
15
11
  },
16
12
  "translationErrors": {
@@ -18,8 +14,7 @@
18
14
  "firstname": "Le prénom est requis",
19
15
  "zipcode": "Le code postal est requis",
20
16
  "email": "Votre adresse mail est requise",
21
- "phone": "Votre numéro de téléphone est requis",
22
- "surface": "Veuillez indiquer la surface de votre logement"
17
+ "phone": "Votre numéro de téléphone est requis"
23
18
  }
24
19
  },
25
20
  "callToActions": [
@@ -280,13 +280,13 @@ $responsive-breakpoint: 'm';
280
280
 
281
281
  &__title {
282
282
  @include set-font-face('semi-bold');
283
- @include set-font-scale('07', 's');
283
+ @include set-font-scale('07', 'm');
284
284
  color: $color-grey-700;
285
285
  max-width: 100%;
286
286
  padding: 0 0 0 0;
287
287
  width: 384px;
288
288
  @include set-from-screen($responsive-breakpoint) {
289
- @include set-font-scale('08', 'm');
289
+ @include set-font-scale('07', 'm');
290
290
  padding: $mu250 $mu100 $mu100 $mu100;
291
291
  text-align: center;
292
292
  width: auto;
@@ -383,11 +383,12 @@ $responsive-breakpoint: 'm';
383
383
  &__dialog-help {
384
384
  &__title {
385
385
  padding: $mu250 $mu250 0 $mu250;
386
+ @include set-font-scale('06', 'm');
386
387
  }
387
388
 
388
389
  &__body {
389
390
  padding: 0 $mu250;
390
- @include set-font-scale('05', 'l');
391
+ @include set-font-scale('06', 'm');
391
392
  &__image {
392
393
  background-size: cover;
393
394
  padding: 120px 0;