project-booster-vue 9.22.0 → 9.24.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.22.0",
3
+ "version": "9.24.0",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -6,7 +6,7 @@
6
6
  </template>
7
7
  <template #body>
8
8
  <pb-loader
9
- v-if="(isSearchingConfigurations || configurationsSearchError) && foundConfigurations.length === 0"
9
+ v-if="(isSearchingConfigurations || configurationsSearchError) && configurations.length === 0"
10
10
  title-loading="Chargement"
11
11
  title-error="Nous n’avons pas pu charger vos simulations"
12
12
  subtitle-loading="Nous recherchons vos simulations réalisées"
@@ -15,10 +15,10 @@
15
15
  :state="!!configurationsSearchError ? 'error' : 'loading'"
16
16
  @loader-click="retrySearch"
17
17
  />
18
- <div v-else-if="foundConfigurations.length > 0" class="pb-configurations-search__results">
18
+ <div v-else-if="configurations.length > 0" class="pb-configurations-search__results">
19
19
  <div class="pb-configurations-search__results-title">Vos simulations trouv&eacute;es</div>
20
20
  <pb-configurations-list
21
- :configurations="foundConfigurations"
21
+ :configurations="configurations"
22
22
  :is-loading-configurations="isSearchingConfigurations"
23
23
  :show-load-more-button="hasStillFoundConfigurations"
24
24
  cards-width="1of2"
@@ -27,7 +27,7 @@
27
27
  @refresh-configuration="handleRefreshConfigurations"
28
28
  />
29
29
  </div>
30
- <div v-else-if="foundConfigurations.length === 0" class="pb-configurations-search__results">
30
+ <div v-else-if="configurations.length === 0" class="pb-configurations-search__results">
31
31
  <div class="pb-configurations-search__empty-state-title">
32
32
  Nous n’avons trouvé aucune simulation associée à votre compte
33
33
  </div>
@@ -143,6 +143,7 @@ export default defineComponent({
143
143
  ICONS_PER_TOOL_TYPE,
144
144
  internalShowDialog: false,
145
145
  selectedConfiguration: null as Configuration | null,
146
+ configurations: [] as Configuration[],
146
147
  }),
147
148
 
148
149
  computed: {
@@ -176,6 +177,7 @@ export default defineComponent({
176
177
 
177
178
  created() {
178
179
  this.internalShowDialog = this.showDialog;
180
+ this.configurations = this.foundConfigurations;
179
181
  },
180
182
 
181
183
  methods: {
@@ -191,7 +193,7 @@ export default defineComponent({
191
193
  },
192
194
 
193
195
  resetConfigurationsSelectedState() {
194
- for (const configuration of this.foundConfigurations) {
196
+ for (const configuration of this.configurations) {
195
197
  configuration.selected = false;
196
198
  }
197
199
  },
@@ -136,7 +136,9 @@ export default defineComponent({
136
136
 
137
137
  async handleValidateClicked() {
138
138
  this.$emit('step-completed', {
139
- answers: [],
139
+ answers: this.payload.multiSelect.actions.VALIDATE.isAnswer
140
+ ? [this.payload.multiSelect.actions.VALIDATE.code]
141
+ : [],
140
142
  nextStep: this.payload.multiSelect.actions.VALIDATE.nextStep,
141
143
  });
142
144
  },
@@ -989,6 +989,8 @@
989
989
  "multiSelect": {
990
990
  "actions": {
991
991
  "VALIDATE": {
992
+ "isAnswer": true,
993
+ "code": "TAKE_APPOINTMENT",
992
994
  "label": "Continuer et prendre RDV",
993
995
  "nextStep": {
994
996
  "code": "APPOINTMENT_FORM"
@@ -0,0 +1,59 @@
1
+ import { nestedAppDecorator } from '../../../.storybook/nested-app-decorator';
2
+ import { ArgsTable, Canvas, Meta, Source, Story } from '@storybook/addon-docs';
3
+ import cloneDeep from 'lodash.clonedeep';
4
+ import PbWarningMessage from './PbWarningMessage';
5
+ import DEFAULT_PAYLOAD from './default-payload.json';
6
+ import WITHOUT_EXPLAIN_LINK from './without-explain-link.json';
7
+
8
+ <Meta
9
+ title="Project Booster/Components/Warning Message/PbWarningMessage 🦠"
10
+ component={PbWarningMessage}
11
+ decorators={[nestedAppDecorator({}, [])]}
12
+ parameters={{ layout: 'fullscreen' }}
13
+ />
14
+
15
+ # 🦠 `PbWarningMessage` - Components
16
+
17
+ [![alt text](https://storage.googleapis.com/project-booster-media/project-booster-vue/project-booster-sources.svg 'Project booster component source code')](https://github.com/adeo/project-booster-vue/tree/master/src/components/question)
18
+
19
+ ---
20
+
21
+ The `PbWarningMessage` Vue component allows select family amount persons. It
22
+ is customizable through the payload property.
23
+
24
+ It has a default provided payload, used in the Sandbox below.
25
+
26
+ The input field is automatically focused.
27
+
28
+ The back button will make `vue-router` trigger the history back feature from the browser. It can be hidden with the
29
+ `showBackButton` flag.
30
+
31
+ # `PbWarningMessage`
32
+
33
+ export const TemplateSandbox = (args, { argTypes }) => ({
34
+ props: Object.keys(argTypes),
35
+ components: { PbWarningMessage },
36
+ setup() {
37
+ return { args };
38
+ },
39
+ template: `<pb-warning-message
40
+ :payload="args.payload"
41
+ :show-back-button="args.showBackButton"
42
+ :completed-event-name="args.completedEventName"
43
+ @step-completed="args.onStepCompleted"
44
+ />`,
45
+ });
46
+
47
+ <Canvas>
48
+ <Story name="101 Sandbox" args={{ payload: DEFAULT_PAYLOAD }}>
49
+ {TemplateSandbox.bind({})}
50
+ </Story>
51
+ </Canvas>
52
+
53
+ # `PbWarningMessage` - Without explain link
54
+
55
+ <Canvas>
56
+ <Story name="Without explain link" args={{ payload: WITHOUT_EXPLAIN_LINK }}>
57
+ {TemplateSandbox.bind({})}
58
+ </Story>
59
+ </Canvas>
@@ -0,0 +1,284 @@
1
+ <template>
2
+ <m-flex class="pb-warning-message" direction="column" align-items="center">
3
+ <m-flex class="pb-warning-message__back-button-container" align-items="stretch">
4
+ <m-link
5
+ :label="payload.viewModel.backLabel"
6
+ :left-icon="BACK_ICON"
7
+ :class="{
8
+ 'pb-warning-message__back-button': true,
9
+ 'pb-warning-message__back-button--hidden':
10
+ !showBackButton && !decorate(answers, runtimeOptions, payload.viewModel.forceBackButton),
11
+ }"
12
+ @click.once="$emit('go-back')"
13
+ />
14
+ </m-flex>
15
+
16
+ <div class="pb-warning-message__title">
17
+ {{ payload.viewModel.label }}
18
+ </div>
19
+
20
+ <div class="pb-warning-message__container--background">
21
+ <m-flex class="pb-warning-message__container__message">
22
+ <div class="pb-warning-message__container__message__left">
23
+ <img :data-src="injectIcon(WARNING_ICON)" id="pb-warning-message-icon" alt="Icon" />
24
+ </div>
25
+ <div class="pb-warning-message__container__message__right">
26
+ <h3>{{ payload.viewModel.subtitle }}</h3>
27
+ <p>{{ payload.viewModel.content }}</p>
28
+ <div class="pb-warning-message__container__message__right__link" v-if="payload.viewModel.explainLink">
29
+ <a :href="payload.viewModel.explainLink.href">{{ payload.viewModel.explainLink.label }}</a>
30
+ </div>
31
+ </div>
32
+ </m-flex>
33
+ </div>
34
+
35
+ <div class="pb-warning-message__container">
36
+ <m-flex
37
+ class="pb-warning-message__container--button"
38
+ direction="column"
39
+ align-items="center"
40
+ justify-content="center"
41
+ >
42
+ <m-button
43
+ :theme="action.bordered ? 'bordered' : 'solid'"
44
+ class="pb-warning-message__container--button__ok mc-button--full"
45
+ :type="action.type"
46
+ :label="action.label"
47
+ icon-position="right"
48
+ :size="small ? 's' : null"
49
+ :href="action.href"
50
+ v-for="action in payload.callToActions"
51
+ :key="action.label"
52
+ @click="callAction(action.action)"
53
+ />
54
+ </m-flex>
55
+ </div>
56
+ </m-flex>
57
+ </template>
58
+
59
+ <script lang="ts">
60
+ import { defineComponent, PropType } from 'vue';
61
+ import { v4 as uuidv4 } from 'uuid';
62
+ import MFlex from './../mozaic/flex/MFlex.vue';
63
+ import MLink from '../mozaic/link/MLink.vue';
64
+ import MButton from '../mozaic/buttons/MButton.vue';
65
+ import { ScenarioStepAnswer } from '@/types/pb/Scenario';
66
+ import SVGInjector from 'svg-injector';
67
+ import { WarningMessagePayloadAction } from '@/types/pb/WarningMessage';
68
+ const BACK_ICON =
69
+ 'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
70
+ const WARNING_ICON =
71
+ 'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Notification_Warning_64px.svg';
72
+
73
+ export default defineComponent({
74
+ name: 'PbWarningMessage',
75
+ components: {
76
+ MFlex,
77
+ MLink,
78
+ MButton,
79
+ },
80
+ props: {
81
+ /**
82
+ * The component view model and business data as an object. The provided prop
83
+ * is merged with the default payload value so only overriden values will change
84
+ * from the default ones.
85
+ */
86
+ payload: {
87
+ type: Object,
88
+ default: () => ({}),
89
+ },
90
+ /**
91
+ * The options provided at runtime to customize component behaviour
92
+ */
93
+ runtimeOptions: {
94
+ type: Object,
95
+ default: () => ({}),
96
+ },
97
+ /**
98
+ * Indicates whether the back button should be displayed
99
+ */
100
+ showBackButton: {
101
+ type: Boolean,
102
+ default: true,
103
+ },
104
+ /**
105
+ * Name for the event to send when the step is questio is answered
106
+ */
107
+ completedEventName: {
108
+ type: String,
109
+ default: 'step-completed',
110
+ },
111
+ /**
112
+ * The previous answers to inject
113
+ */
114
+ answers: {
115
+ type: Object as PropType<Map<string, ScenarioStepAnswer[]>>,
116
+ default: () => new Map<string, ScenarioStepAnswer[]>(),
117
+ },
118
+ },
119
+ methods: {
120
+ injectIcon(icon: string) {
121
+ this.$nextTick(() => {
122
+ const element = document.getElementById('pb-warning-message-icon');
123
+ if (element) {
124
+ SVGInjector(element, {
125
+ each: function (svg) {
126
+ svg.setAttribute('fill', '#C65200');
127
+ },
128
+ });
129
+ }
130
+ });
131
+
132
+ return icon;
133
+ },
134
+ callAction(action: WarningMessagePayloadAction) {
135
+ if (action.type === 'STEP') {
136
+ if (action.code === '__BACK__') {
137
+ this.$emit('go-back');
138
+ } else {
139
+ this.$emit('step-completed', {
140
+ answers: [],
141
+ nextStep: action,
142
+ });
143
+ }
144
+ }
145
+ },
146
+ },
147
+ setup(props, { emit }) {
148
+ const componentId = uuidv4();
149
+
150
+ const skipQuestion = () => {
151
+ /**
152
+ * Emitted when step is completed
153
+ * @event dynamic event name according to completedEventName prop
154
+ * @type {Event}
155
+ */
156
+ emit(props.completedEventName, {
157
+ answers: props.payload?.skippable?.isAnswer
158
+ ? props.payload?.skippable?.defaultAnswer
159
+ ? [props.payload?.skippable?.defaultAnswer]
160
+ : []
161
+ : null,
162
+ nextStep: props.payload?.skippable?.nextStep,
163
+ });
164
+ };
165
+
166
+ return {
167
+ id: componentId,
168
+ skipQuestion,
169
+ BACK_ICON,
170
+ WARNING_ICON,
171
+ };
172
+ },
173
+ });
174
+ </script>
175
+
176
+ <style lang="scss" scoped>
177
+ @import 'pb-variables';
178
+ @import 'settings-tools/all-settings';
179
+ @import 'typography/_t.bodys';
180
+
181
+ $small-responsive-breakpoint: 's-large';
182
+ $responsive-breakpoint: 'm';
183
+ .pb-warning-message {
184
+ @include set-font-face('regular');
185
+ flex-grow: 1;
186
+ margin: 0 auto;
187
+ width: calc(100% - #{$mu050} - #{$mu050});
188
+ &__back-button-container {
189
+ align-self: flex-start;
190
+ }
191
+ &__back-button {
192
+ opacity: 1;
193
+ padding: $mu100 0 $mu100 $mu025;
194
+ transition: opacity 0.15s 0.5s;
195
+ &--hidden {
196
+ opacity: 0;
197
+ pointer-events: none;
198
+ }
199
+ }
200
+ &__body {
201
+ flex-wrap: wrap;
202
+ margin-bottom: $mu250;
203
+ max-width: 100%;
204
+ @include set-from-screen($responsive-breakpoint) {
205
+ flex-wrap: nowrap;
206
+ width: 161px;
207
+ }
208
+ }
209
+
210
+ &__title {
211
+ @include set-font-face('semi-bold');
212
+ @include set-font-scale('07', 's');
213
+ color: $color-grey-700;
214
+ max-width: 100%;
215
+ padding: 0 0 0 0;
216
+ width: 384px;
217
+ @include set-from-screen($responsive-breakpoint) {
218
+ @include set-font-scale('08', 'm');
219
+ padding: $mu250 $mu100 $mu100 $mu100;
220
+ text-align: center;
221
+ width: auto;
222
+ }
223
+ }
224
+
225
+ &__subtitle {
226
+ color: $color-grey-700;
227
+ max-width: 100%;
228
+ padding: 0 0 $mu250 0;
229
+ }
230
+
231
+ &__container__message__right {
232
+ h3 {
233
+ @include set-font-face('semi-bold');
234
+ @include set-font-scale('05', 's');
235
+ margin: $mu100 0 0 0;
236
+ }
237
+
238
+ p {
239
+ margin: $mu075 0 $mu100 0;
240
+ @include set-font-scale('05', 'm');
241
+ }
242
+
243
+ &__link {
244
+ margin: $mu075 0 $mu100 0;
245
+
246
+ a {
247
+ color: $color-grey-900;
248
+ @include set-font-scale('05', 'm');
249
+ }
250
+ }
251
+ }
252
+
253
+ &__container {
254
+ width: 511px;
255
+ }
256
+
257
+ &__container__message__left {
258
+ margin: $mu075 $mu100 0 0;
259
+ min-width: 28px;
260
+
261
+ svg {
262
+ fill: red;
263
+ }
264
+ }
265
+
266
+ &__container--background {
267
+ @extend .pb-warning-message__container;
268
+ @include set-border-radius('m');
269
+ background: $color-warning-100;
270
+ border: 1px solid $color-warning-500;
271
+ margin: $mu150 0 0 0;
272
+ padding: $mu075;
273
+ }
274
+
275
+ &__container--button {
276
+ margin: $mu250 auto 0 auto;
277
+ width: 311px;
278
+
279
+ &__ok {
280
+ margin-bottom: $mu100;
281
+ }
282
+ }
283
+ }
284
+ </style>
@@ -0,0 +1,33 @@
1
+ {
2
+ "viewModel": {
3
+ "backLabel": "Question précédente",
4
+ "label": "Vos travaux dans un appartement",
5
+ "subtitle": "Nous attirons votre attention !",
6
+ "content": "La pose d’une pompe à chaleur n’est pas adaptée a un appartement. Nous n’avons pas d’offre pour les appartements aujourd’hui..",
7
+ "explainLink": {
8
+ "type": "link",
9
+ "label": "Comment faire des travaux de rénovation énergétique en tant que locataire ?",
10
+ "href": "https://www.leroymerlin.fr/v3/p/produits/cuisine/meuble-de-cuisine/cuisine-equipee-l1501755932"
11
+ }
12
+ },
13
+ "callToActions": [
14
+ {
15
+ "type": "button",
16
+ "label": "Ok, poursuivre l'estimation",
17
+ "action": {
18
+ "type": "STEP",
19
+ "code": "__END__"
20
+ },
21
+ "bordered": false
22
+ },
23
+ {
24
+ "type": "button",
25
+ "label": "Changer de le type de propriété",
26
+ "action": {
27
+ "type": "STEP",
28
+ "code": "__BACK__"
29
+ },
30
+ "bordered": true
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "viewModel": {
3
+ "backLabel": "Question précédente",
4
+ "label": "Vos travaux dans un appartement",
5
+ "subtitle": "Nous attirons votre attention !",
6
+ "content": "La pose d’une pompe à chaleur n’est pas adaptée a un appartement. Nous n’avons pas d’offre pour les appartements aujourd’hui.."
7
+ },
8
+ "callToActions": [
9
+ {
10
+ "type": "button",
11
+ "label": "Ok, poursuivre l'estimation",
12
+ "action": {
13
+ "type": "STEP",
14
+ "code": "__END__"
15
+ },
16
+ "bordered": false
17
+ },
18
+ {
19
+ "type": "button",
20
+ "label": "Changer de le type de propriété",
21
+ "action": {
22
+ "type": "STEP",
23
+ "code": "__BACK__"
24
+ },
25
+ "bordered": true
26
+ }
27
+ ]
28
+ }
@@ -0,0 +1,8 @@
1
+ export interface WarningMessagePayloadAction {
2
+ type: string;
3
+ code: string;
4
+ component?: string;
5
+ payload?: {
6
+ link: string;
7
+ };
8
+ }