project-booster-vue 9.40.0 → 9.41.1
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 +1 -1
- package/src/components/question/PbQuestion.vue +1 -49
- package/src/components/question/amount-input/PbAmountInput.vue +1 -1
- package/src/components/question/city-search/PbCitySearch.vue +1 -2
- package/src/components/question/configurations-import/PbConfigurationsImport.vue +1 -2
- package/src/components/question/dimensions-input/PbDimensionsInput.vue +1 -1
- package/src/components/question/incremental-amount-input/PbIncrementalAmountInput.vue +1 -4
- package/src/components/question/list-select/PbListSelect.vue +1 -3
- package/src/components/question/name-input/PbNameInput.vue +1 -1
- package/src/components/question/space-input/PbSpaceInput.vue +1 -1
- package/src/components/question/upload-document/PbUploadDocument.vue +1 -2
- package/src/components/restitution/PbRestitutionList.stories.mdx +2 -2
- package/src/components/restitution/PbRestitutionList.vue +158 -35
- package/src/components/restitution/PbRestitutionListBlock.vue +67 -24
- package/src/components/restitution/PbRestitutionListLine.vue +29 -15
- package/src/components/restitution/restitution-list-default.json +24 -0
- package/src/services/decorate.ts +65 -0
package/package.json
CHANGED
|
@@ -352,7 +352,6 @@
|
|
|
352
352
|
|
|
353
353
|
<script lang="ts">
|
|
354
354
|
import { defineComponent, PropType } from 'vue';
|
|
355
|
-
import objectPath from 'object-path';
|
|
356
355
|
import MButton from '../mozaic/buttons/MButton.vue';
|
|
357
356
|
import MContainer from '../mozaic/grid/MContainer.vue';
|
|
358
357
|
import MDialog from '../mozaic/dialog/MDialog.vue';
|
|
@@ -366,6 +365,7 @@ import PbCard from '../cards/PbCard.vue';
|
|
|
366
365
|
import PbStickyFooter from '../sticky-footer/PbStickyFooter.vue';
|
|
367
366
|
import { sortAnswers } from './sortAnswers';
|
|
368
367
|
import { areConditionsValid } from '../../services/scenarioConditionals';
|
|
368
|
+
import { decorate } from '@/services/decorate';
|
|
369
369
|
import {
|
|
370
370
|
ScenarioStepAnswer,
|
|
371
371
|
ScenarioStepAnswerDialog,
|
|
@@ -383,54 +383,6 @@ const BACK_ICON =
|
|
|
383
383
|
const INFO_ICON =
|
|
384
384
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Notification_Information_24px.svg';
|
|
385
385
|
|
|
386
|
-
// Function used by the scenario conditions
|
|
387
|
-
const getAnswerValue = (answers: Map<string, ScenarioStepAnswer[]>) => {
|
|
388
|
-
return (answerCode: string, path: string) => {
|
|
389
|
-
let answerValue: ScenarioStepAnswer | undefined = undefined;
|
|
390
|
-
if (answers?.get(answerCode)) {
|
|
391
|
-
const answerValues = answers.get(answerCode) ?? [];
|
|
392
|
-
answerValue = objectPath.get(answerValues[0], path);
|
|
393
|
-
}
|
|
394
|
-
return answerValue;
|
|
395
|
-
};
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
export const doEval = (
|
|
399
|
-
answers: Map<string, ScenarioStepAnswer[]>,
|
|
400
|
-
valueToEval: string,
|
|
401
|
-
defaultValue: string,
|
|
402
|
-
runtimeOptions: any,
|
|
403
|
-
) => {
|
|
404
|
-
return new Function('getAnswerValue', 'answers', 'defaultValue', 'runtimeOptions', `return ${valueToEval}`).call(
|
|
405
|
-
this,
|
|
406
|
-
getAnswerValue(answers),
|
|
407
|
-
Object.fromEntries(answers),
|
|
408
|
-
defaultValue,
|
|
409
|
-
runtimeOptions,
|
|
410
|
-
);
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
//TODO Think to move this kind of function in something like "helpers" or "tools"
|
|
414
|
-
// because this is use in multiple components (as PbIncrementalAmountInput.vue),
|
|
415
|
-
// and it shouldn't be in a component.
|
|
416
|
-
export const decorate = (
|
|
417
|
-
answers: Map<string, ScenarioStepAnswer[]>,
|
|
418
|
-
runtimeOptions = {},
|
|
419
|
-
valueToDecorate: string,
|
|
420
|
-
defaultValue = '',
|
|
421
|
-
): string => {
|
|
422
|
-
let decoratedValue = valueToDecorate;
|
|
423
|
-
if (valueToDecorate) {
|
|
424
|
-
const stringToEval = `\`${valueToDecorate}\``;
|
|
425
|
-
try {
|
|
426
|
-
decoratedValue = doEval(answers, stringToEval, defaultValue, runtimeOptions);
|
|
427
|
-
} catch (error) {
|
|
428
|
-
decoratedValue = valueToDecorate || defaultValue;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
return decoratedValue;
|
|
432
|
-
};
|
|
433
|
-
|
|
434
386
|
export default defineComponent({
|
|
435
387
|
name: 'PbQuestion',
|
|
436
388
|
|
|
@@ -63,7 +63,7 @@ import MTextInput from './../../mozaic/text-input/MTextInput.vue';
|
|
|
63
63
|
import DEFAULT_PAYLOAD from './default-payload.json';
|
|
64
64
|
import { AmountInputPayload } from '@/components/question/amount-input/AmountInput';
|
|
65
65
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
66
|
-
import { decorate } from '@/
|
|
66
|
+
import { decorate } from '@/services/decorate';
|
|
67
67
|
|
|
68
68
|
const BACK_ICON =
|
|
69
69
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -106,14 +106,13 @@ import debounce from 'lodash.debounce';
|
|
|
106
106
|
import merge from 'lodash.merge';
|
|
107
107
|
import initGoogleMapsApi from './google-maps-api';
|
|
108
108
|
import axios from 'axios';
|
|
109
|
-
import objectPath from 'object-path';
|
|
110
109
|
import MFlex from '../../mozaic/flex/MFlex.vue';
|
|
111
110
|
import MButton from '../../mozaic/buttons/MButton.vue';
|
|
112
111
|
import MLink from '../../mozaic/link/MLink.vue';
|
|
113
112
|
import MTextInput from '../../mozaic/text-input/MTextInput.vue';
|
|
114
113
|
import DEFAULT_PAYLOAD from './default-payload.json';
|
|
115
114
|
import { DebouncedFunc } from 'lodash-es';
|
|
116
|
-
import { decorate } from '@/
|
|
115
|
+
import { decorate } from '@/services/decorate';
|
|
117
116
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
118
117
|
|
|
119
118
|
const BACK_ICON =
|
|
@@ -165,7 +165,6 @@ import MLink from '../../../components/mozaic/link/MLink.vue';
|
|
|
165
165
|
import MNotification from '../../../components/mozaic/notifications/MNotification.vue';
|
|
166
166
|
import PbCard from '../../../components/cards/PbCard.vue';
|
|
167
167
|
import { format } from 'date-fns';
|
|
168
|
-
import objectPath from 'object-path';
|
|
169
168
|
import {
|
|
170
169
|
ConfigurationsImportMultiSelectAction,
|
|
171
170
|
ConfigurationsImportPayload,
|
|
@@ -174,7 +173,7 @@ import {
|
|
|
174
173
|
} from '@/components/question/configurations-import/ConfigurationsImport';
|
|
175
174
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
176
175
|
import { Configuration } from '@/types/pb/Configuration';
|
|
177
|
-
import { decorate } from '@/
|
|
176
|
+
import { decorate } from '@/services/decorate';
|
|
178
177
|
|
|
179
178
|
const BACK_ICON =
|
|
180
179
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -101,7 +101,7 @@ import MIcon from '../../mozaic/icon/MIcon.vue';
|
|
|
101
101
|
import { ref } from 'vue';
|
|
102
102
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
103
103
|
import { DimensionsInputPayload } from '@/components/question/dimensions-input/DimensionsInput';
|
|
104
|
-
import { decorate } from '@/
|
|
104
|
+
import { decorate } from '@/services/decorate';
|
|
105
105
|
|
|
106
106
|
const BACK_ICON =
|
|
107
107
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -72,7 +72,7 @@ import MLink from '../../mozaic/link/MLink.vue';
|
|
|
72
72
|
import MButton from '../../mozaic/buttons/MButton.vue';
|
|
73
73
|
import { ref } from 'vue';
|
|
74
74
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
75
|
-
import { decorate } from '@/
|
|
75
|
+
import { decorate } from '@/services/decorate';
|
|
76
76
|
import MQuantitySelector from '../../mozaic/quantityselector/MQuantitySelector.vue';
|
|
77
77
|
import { IncrementalAmountPayload } from '@/components/question/incremental-amount-input/IncrementalAmount';
|
|
78
78
|
|
|
@@ -169,9 +169,6 @@ export default defineComponent({
|
|
|
169
169
|
let tempPayload = cloneDeep(DEFAULT_PAYLOAD);
|
|
170
170
|
tempPayload = merge(tempPayload, props.payload);
|
|
171
171
|
|
|
172
|
-
// This will doEval and decorate dynamically variables from JSON templates
|
|
173
|
-
// For instance:
|
|
174
|
-
// "${getAnswerValue('DEVELOPER', 'code') == 'YES' ? 'I'm developer' : 'I'm not developer'}"
|
|
175
172
|
tempPayload.viewModel.label = decorate(props.answers!, props.runtimeOptions, tempPayload.viewModel.label);
|
|
176
173
|
tempPayload.viewModel.subtitle = decorate(props.answers!, props.runtimeOptions, tempPayload.viewModel.subtitle);
|
|
177
174
|
|
|
@@ -75,15 +75,13 @@
|
|
|
75
75
|
<script lang="ts">
|
|
76
76
|
import { defineComponent, PropType } from 'vue';
|
|
77
77
|
import { ref, computed, onMounted, Ref } from 'vue';
|
|
78
|
-
import objectPath from 'object-path';
|
|
79
78
|
import MFlex from '../../mozaic/flex/MFlex.vue';
|
|
80
79
|
import MButton from '../../mozaic/buttons/MButton.vue';
|
|
81
80
|
import MLink from '../../mozaic/link/MLink.vue';
|
|
82
81
|
import PbItemsList from '../../items/PbItemsList.vue';
|
|
83
82
|
import { sortAnswers } from '../sortAnswers';
|
|
84
83
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
85
|
-
import {
|
|
86
|
-
import { decorate } from '@/components/question/PbQuestion.vue';
|
|
84
|
+
import { decorate } from '@/services/decorate';
|
|
87
85
|
|
|
88
86
|
const BACK_ICON =
|
|
89
87
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -60,7 +60,7 @@ import MToggle from '../../mozaic/toggle/MToggle.vue';
|
|
|
60
60
|
import DEFAULT_PAYLOAD from './default-payload.json';
|
|
61
61
|
import { NameInputPayload } from '@/components/question/name-input/NameInput';
|
|
62
62
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
63
|
-
import { decorate } from '@/
|
|
63
|
+
import { decorate } from '@/services/decorate';
|
|
64
64
|
|
|
65
65
|
const BACK_ICON =
|
|
66
66
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -146,7 +146,7 @@ import MDialog from '../../mozaic/dialog/MDialog.vue';
|
|
|
146
146
|
import DEFAULT_PAYLOAD from './default-payload.json';
|
|
147
147
|
import { SpaceInputPayload } from '@/components/question/space-input/SpaceInput';
|
|
148
148
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
149
|
-
import { decorate } from '@/
|
|
149
|
+
import { decorate } from '@/services/decorate';
|
|
150
150
|
|
|
151
151
|
const BACK_ICON =
|
|
152
152
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -139,7 +139,6 @@
|
|
|
139
139
|
|
|
140
140
|
<script lang="ts">
|
|
141
141
|
import { defineComponent, computed, onMounted, ref, PropType, Ref, ComponentCustomProperties } from 'vue';
|
|
142
|
-
import objectPath from 'object-path';
|
|
143
142
|
import MButton from '../../mozaic/buttons/MButton.vue';
|
|
144
143
|
import MContainer from '../../mozaic/grid/MContainer.vue';
|
|
145
144
|
import MFlex from '../../mozaic/flex/MFlex.vue';
|
|
@@ -156,7 +155,7 @@ import {
|
|
|
156
155
|
UploadDocumentViewModel,
|
|
157
156
|
} from '@/components/question/upload-document/UploadDocument';
|
|
158
157
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
159
|
-
import { decorate, doEval } from '@/
|
|
158
|
+
import { decorate, doEval } from '@/services/decorate';
|
|
160
159
|
|
|
161
160
|
const BACK_ICON =
|
|
162
161
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -6,7 +6,7 @@ import store from './../../stores/store';
|
|
|
6
6
|
import { rest } from 'msw';
|
|
7
7
|
import { successResolver, internalServerErrorResolver } from '../../services/api/mocks/commonMock';
|
|
8
8
|
import { getProjectsResolver } from '../../services/api/mocks/projectsMock';
|
|
9
|
-
import DEFAULT_PAYLOAD from './restitution-default.json';
|
|
9
|
+
import DEFAULT_PAYLOAD from './restitution-list-default.json';
|
|
10
10
|
import NO_PRICE_BAR from './restitution-no-pricebar.json';
|
|
11
11
|
import SAVE_ITEM from './restitution-with-save-item.json';
|
|
12
12
|
import EXIT_OPTIONS from './restitution-with-exit-options.json';
|
|
@@ -131,7 +131,7 @@ export const TemplateSandbox = (args, { argTypes }) => ({
|
|
|
131
131
|
<Canvas>
|
|
132
132
|
<Story
|
|
133
133
|
name="101 Sandbox"
|
|
134
|
-
args={{ payload: DEFAULT_PAYLOAD }}
|
|
134
|
+
args={{ payload: DEFAULT_PAYLOAD, runtimeOptions: { isLoggedIn: true } }}
|
|
135
135
|
parameters={{
|
|
136
136
|
msw: [
|
|
137
137
|
rest.get('/api/inhabitant-projects', getProjectsResolver),
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
@click.once="$emit('go-back')"
|
|
16
16
|
/>
|
|
17
17
|
</m-flex>
|
|
18
|
-
<div class="pb-restitution-list__title">
|
|
18
|
+
<div class="pb-restitution-list__title">{{ payload?.viewModel?.title }}</div>
|
|
19
19
|
|
|
20
20
|
<div class="pb-restitution-list__line">
|
|
21
21
|
<pb-restitution-list-block
|
|
@@ -26,9 +26,31 @@
|
|
|
26
26
|
></pb-restitution-list-block>
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
|
+
<m-flex class="pb-restitution-list__notifications" :direction="'column'" v-if="notifications.length > 0">
|
|
30
|
+
<m-flex
|
|
31
|
+
v-for="(notification, index) in notifications"
|
|
32
|
+
:key="`${index}-${notification.title}`"
|
|
33
|
+
direction="column"
|
|
34
|
+
align-items="center"
|
|
35
|
+
class="pb-restitution-list__notifications__container"
|
|
36
|
+
>
|
|
37
|
+
<m-notification
|
|
38
|
+
:title="notification.title"
|
|
39
|
+
:type="notification.type"
|
|
40
|
+
:text="notification.text"
|
|
41
|
+
:link-label="notification.linkLabel"
|
|
42
|
+
@link-click="handleLinkClicked(notification.linkHref)"
|
|
43
|
+
/>
|
|
44
|
+
</m-flex>
|
|
45
|
+
</m-flex>
|
|
46
|
+
|
|
29
47
|
<m-flex class="pb-restitution-list__footer" direction="row" align-items="center" justify-content="center">
|
|
30
|
-
<div class="pb-restitution-list__footer__call">
|
|
31
|
-
<m-button
|
|
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
|
+
/>
|
|
32
54
|
</div>
|
|
33
55
|
<div class="pb-restitution-list__footer__save">
|
|
34
56
|
<pb-project-item-save
|
|
@@ -37,7 +59,6 @@
|
|
|
37
59
|
@dialog-close="handleDialogClose"
|
|
38
60
|
v-if="isLoggedIn"
|
|
39
61
|
/>
|
|
40
|
-
<!-- <m-button label="Enregistrer mon estimation" theme="bordered"></m-button> -->
|
|
41
62
|
</div>
|
|
42
63
|
</m-flex>
|
|
43
64
|
|
|
@@ -49,16 +70,16 @@
|
|
|
49
70
|
@update:show-dialog="handleShowDialog"
|
|
50
71
|
>
|
|
51
72
|
<template #body>
|
|
52
|
-
<
|
|
73
|
+
<div class="pb-restitution-list__modal__details" direction="column">
|
|
53
74
|
<div class="pb-restitution-list__modal__details__title" v-html="summary.subprojectTemplateLabel"></div>
|
|
54
75
|
|
|
55
76
|
<div class="pb-restitution-list__modal__details__row">
|
|
56
|
-
<
|
|
77
|
+
<div class="pb-restitution-list__modal__details__row__title" justify-content="space-between">
|
|
57
78
|
<div v-html="summary.components[0].title"></div>
|
|
58
79
|
<div>
|
|
59
80
|
<strong>{{ summary.components[0].cost.min }}€ - {{ summary.components[0].cost.max }}€</strong>
|
|
60
81
|
</div>
|
|
61
|
-
</
|
|
82
|
+
</div>
|
|
62
83
|
|
|
63
84
|
<div v-for="line in summary.components" :key="line.details">
|
|
64
85
|
<div class="pb-restitution-list__modal__details__row__label" v-if="line.details">
|
|
@@ -83,7 +104,7 @@
|
|
|
83
104
|
</div>
|
|
84
105
|
|
|
85
106
|
<div v-for="line in summary.components[0].lines" :key="line.text">
|
|
86
|
-
<
|
|
107
|
+
<div
|
|
87
108
|
v-if="line.cost.reduce"
|
|
88
109
|
class="pb-restitution-list__modal__details__row__title"
|
|
89
110
|
:class="{ ' help border-bottom': line.cost.reduce }"
|
|
@@ -100,21 +121,20 @@
|
|
|
100
121
|
<strong>{{ line.cost.reduce }}€</strong>
|
|
101
122
|
</div>
|
|
102
123
|
</div>
|
|
103
|
-
</
|
|
124
|
+
</div>
|
|
104
125
|
</div>
|
|
105
126
|
</div>
|
|
106
127
|
|
|
107
|
-
<
|
|
108
|
-
class="pb-restitution-list__modal__details__totals"
|
|
109
|
-
justify-content="space-between"
|
|
110
|
-
align-items="center"
|
|
111
|
-
>
|
|
128
|
+
<div class="pb-restitution-list__modal__details__totals" justify-content="space-between" align-items="center">
|
|
112
129
|
<div><strong>Montant total</strong> (aides déduites)</div>
|
|
130
|
+
<div class="space-mx">entre</div>
|
|
113
131
|
<div>
|
|
114
|
-
|
|
132
|
+
<strong>{{ summary.cost.min }}€</strong>
|
|
133
|
+
<div class="space-mx">et</div>
|
|
134
|
+
<strong>{{ summary.cost.max }}€</strong>
|
|
115
135
|
</div>
|
|
116
|
-
</
|
|
117
|
-
</
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
118
138
|
</template>
|
|
119
139
|
<template #footer>
|
|
120
140
|
<m-flex class="pb-restitution-list__modal__footer" align-items="center" justify-content="center">
|
|
@@ -133,11 +153,11 @@ import MDialog from '../mozaic/dialog/MDialog.vue';
|
|
|
133
153
|
import MFlex from '../mozaic/flex/MFlex.vue';
|
|
134
154
|
import MLink from '../mozaic/link/MLink.vue';
|
|
135
155
|
import PbProjectItemSave from '../projects/project-item-save/PbProjectItemSave.vue';
|
|
136
|
-
|
|
137
|
-
import {
|
|
156
|
+
import MNotification from '../mozaic/notifications/MNotification.vue';
|
|
157
|
+
import { NotificationOptions } from '@/types/pb/Notification';
|
|
158
|
+
import { RestitutionPayload, RestitutionPayloadAction } from '@/types/pb/Restitution';
|
|
138
159
|
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
139
160
|
import PbRestitutionListBlock from './PbRestitutionListBlock.vue';
|
|
140
|
-
import { NotificationOptions } from '@/types/pb/Notification';
|
|
141
161
|
import { Project } from '../../types/pb/Project';
|
|
142
162
|
|
|
143
163
|
export default defineComponent({
|
|
@@ -148,6 +168,7 @@ export default defineComponent({
|
|
|
148
168
|
MLink,
|
|
149
169
|
PbRestitutionListBlock,
|
|
150
170
|
PbProjectItemSave,
|
|
171
|
+
MNotification,
|
|
151
172
|
},
|
|
152
173
|
data() {
|
|
153
174
|
return {
|
|
@@ -201,15 +222,14 @@ export default defineComponent({
|
|
|
201
222
|
computed: {
|
|
202
223
|
...mapGetters('estimates', { summary: 'getSummary' }),
|
|
203
224
|
isLoggedIn() {
|
|
204
|
-
return true;
|
|
225
|
+
return this.runtimeOptions.isLoggedIn === true;
|
|
205
226
|
},
|
|
206
227
|
},
|
|
207
228
|
created() {
|
|
208
229
|
if (this.payload?.callToActions) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
this.showSaveProjectItem = this.showSaveEstimate;
|
|
230
|
+
if (this.payload?.callToActions) {
|
|
231
|
+
this.showSaveProjectItem = this.showSaveEstimate;
|
|
232
|
+
}
|
|
213
233
|
}
|
|
214
234
|
},
|
|
215
235
|
methods: {
|
|
@@ -238,20 +258,41 @@ export default defineComponent({
|
|
|
238
258
|
linkLabel: 'Voir dans le projet',
|
|
239
259
|
});
|
|
240
260
|
},
|
|
261
|
+
handleDialogClose() {
|
|
262
|
+
this.showSaveProjectItem = false;
|
|
263
|
+
},
|
|
264
|
+
callAction(action: RestitutionPayloadAction) {
|
|
265
|
+
if (action.type === 'MODAL') {
|
|
266
|
+
if (action.component === 'PbProjectItemSave') {
|
|
267
|
+
if (this.runtimeOptions.isLoggedIn === true) {
|
|
268
|
+
this.showSaveProjectItem = true;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
this.$emit('click-save-item', {
|
|
272
|
+
answers: [],
|
|
273
|
+
action: action,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
this.$emit('step-completed', {
|
|
278
|
+
answers: [],
|
|
279
|
+
nextStep: action,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
},
|
|
241
283
|
},
|
|
242
284
|
});
|
|
243
285
|
</script>
|
|
244
286
|
|
|
245
287
|
<style lang="scss" scoped>
|
|
246
288
|
@import 'pb-variables';
|
|
247
|
-
|
|
289
|
+
$responsive-breakpoint: 'm';
|
|
248
290
|
.hidden {
|
|
249
291
|
display: none;
|
|
250
292
|
}
|
|
251
293
|
|
|
252
294
|
.pb-restitution-list {
|
|
253
295
|
@include set-font-face('regular');
|
|
254
|
-
|
|
255
296
|
align-items: center;
|
|
256
297
|
display: flex;
|
|
257
298
|
flex-direction: column;
|
|
@@ -259,12 +300,17 @@ export default defineComponent({
|
|
|
259
300
|
margin: 0 auto;
|
|
260
301
|
padding-bottom: $mu250;
|
|
261
302
|
position: relative;
|
|
262
|
-
width:
|
|
303
|
+
width: 100%;
|
|
304
|
+
|
|
305
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
306
|
+
justify-content: space-between;
|
|
307
|
+
width: calc(100% - #{$mu050} - #{$mu050});
|
|
308
|
+
}
|
|
263
309
|
|
|
264
310
|
&__back-button {
|
|
265
311
|
align-self: flex-start;
|
|
266
312
|
opacity: 1;
|
|
267
|
-
padding: $mu100 0 $mu100 $
|
|
313
|
+
padding: $mu100 0 $mu100 $mu100;
|
|
268
314
|
transition: opacity 0.15s 0.5s;
|
|
269
315
|
z-index: 2;
|
|
270
316
|
|
|
@@ -282,7 +328,11 @@ export default defineComponent({
|
|
|
282
328
|
position: absolute;
|
|
283
329
|
right: 0;
|
|
284
330
|
text-align: center;
|
|
285
|
-
top:
|
|
331
|
+
top: $mu250;
|
|
332
|
+
|
|
333
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
334
|
+
top: 0;
|
|
335
|
+
}
|
|
286
336
|
}
|
|
287
337
|
|
|
288
338
|
&__footer {
|
|
@@ -324,6 +374,14 @@ export default defineComponent({
|
|
|
324
374
|
width: 100%;
|
|
325
375
|
|
|
326
376
|
&__title {
|
|
377
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
378
|
+
display: flex;
|
|
379
|
+
justify-content: space-between;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
& > div {
|
|
383
|
+
margin-bottom: $mu050;
|
|
384
|
+
}
|
|
327
385
|
&.help {
|
|
328
386
|
margin-bottom: $mu150;
|
|
329
387
|
}
|
|
@@ -356,30 +414,55 @@ export default defineComponent({
|
|
|
356
414
|
list-style: disc;
|
|
357
415
|
|
|
358
416
|
ul {
|
|
359
|
-
padding: 0
|
|
417
|
+
padding: 0;
|
|
418
|
+
|
|
419
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
420
|
+
padding: 0 0 0 $mu100;
|
|
421
|
+
}
|
|
360
422
|
}
|
|
361
423
|
|
|
362
424
|
li {
|
|
363
425
|
display: flex;
|
|
364
|
-
|
|
426
|
+
flex-direction: column;
|
|
365
427
|
margin-bottom: $mu075;
|
|
366
428
|
|
|
429
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
430
|
+
flex-direction: row;
|
|
431
|
+
justify-content: space-between;
|
|
432
|
+
}
|
|
433
|
+
|
|
367
434
|
&::before {
|
|
368
435
|
content: '•';
|
|
436
|
+
display: none;
|
|
369
437
|
margin-right: 5px;
|
|
438
|
+
|
|
439
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
440
|
+
display: inherit;
|
|
441
|
+
justify-content: space-between;
|
|
442
|
+
}
|
|
370
443
|
}
|
|
371
444
|
|
|
372
445
|
div {
|
|
373
446
|
&:first-child {
|
|
374
447
|
@include set-font-face('regular');
|
|
375
448
|
@include set-font-scale('05', 's');
|
|
376
|
-
|
|
449
|
+
margin-bottom: $mu050;
|
|
450
|
+
width: 100%;
|
|
451
|
+
|
|
452
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
453
|
+
margin-bottom: 0;
|
|
454
|
+
width: 60%;
|
|
455
|
+
}
|
|
377
456
|
}
|
|
378
457
|
|
|
379
458
|
&:last-child {
|
|
380
459
|
@include set-font-face('semi-bold');
|
|
381
|
-
|
|
382
|
-
|
|
460
|
+
width: 100%;
|
|
461
|
+
|
|
462
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
463
|
+
text-align: right;
|
|
464
|
+
width: 40%;
|
|
465
|
+
}
|
|
383
466
|
}
|
|
384
467
|
}
|
|
385
468
|
}
|
|
@@ -389,6 +472,24 @@ export default defineComponent({
|
|
|
389
472
|
&__totals {
|
|
390
473
|
width: 100%;
|
|
391
474
|
|
|
475
|
+
.space-mx {
|
|
476
|
+
margin-right: 5px;
|
|
477
|
+
|
|
478
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
479
|
+
margin: 0 5px;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
& > div {
|
|
484
|
+
align-items: center;
|
|
485
|
+
display: flex;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
489
|
+
align-items: center;
|
|
490
|
+
display: flex;
|
|
491
|
+
}
|
|
492
|
+
|
|
392
493
|
div {
|
|
393
494
|
&:last-child {
|
|
394
495
|
strong {
|
|
@@ -403,5 +504,27 @@ export default defineComponent({
|
|
|
403
504
|
padding: $mu150 0;
|
|
404
505
|
}
|
|
405
506
|
}
|
|
507
|
+
|
|
508
|
+
&__notifications {
|
|
509
|
+
width: 100%;
|
|
510
|
+
|
|
511
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
512
|
+
width: 710px;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
&__container {
|
|
516
|
+
margin: auto;
|
|
517
|
+
min-width: 90%;
|
|
518
|
+
|
|
519
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
520
|
+
min-width: 100%;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.m-notification {
|
|
527
|
+
margin-top: $mu075;
|
|
528
|
+
width: 100%;
|
|
406
529
|
}
|
|
407
530
|
</style>
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
<div class="pb-restitution-list-block__title" v-html="summary.subprojectTemplateLabel"></div>
|
|
5
5
|
|
|
6
6
|
<div class="pb-restitution-list-block__body" v-if="payload">
|
|
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
10
|
<div class="pb-restitution-list-line__price__min">{{ summary.components[0].cost.min }}€ - </div>
|
|
11
11
|
<div class="pb-restitution-list-line__price__max">{{ summary.components[0].cost.max }}€</div>
|
|
12
|
-
</
|
|
13
|
-
</
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
14
|
|
|
15
15
|
<pb-restitution-list-line
|
|
16
16
|
v-for="line in payload.lines"
|
|
@@ -19,18 +19,15 @@
|
|
|
19
19
|
:line="line"
|
|
20
20
|
></pb-restitution-list-line>
|
|
21
21
|
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
class="pb-restitution-list-block__body__row__title full"
|
|
25
|
-
align-items="center"
|
|
26
|
-
justify-content="space-between"
|
|
27
|
-
>
|
|
22
|
+
<div class="pb-restitution-list-block__body__row unbordered">
|
|
23
|
+
<div class="pb-restitution-list-block__body__row__title full">
|
|
28
24
|
<div><strong>Montant total</strong> (aides déduites)</div>
|
|
29
25
|
<div class="pb-restitution-list-block__body__row__title__amount">
|
|
30
|
-
|
|
26
|
+
<div>entre</div>
|
|
27
|
+
<strong>{{ summary.cost.min }}€</strong> et <strong>{{ summary.cost.max }}€</strong>
|
|
31
28
|
</div>
|
|
32
|
-
</
|
|
33
|
-
</
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
34
31
|
|
|
35
32
|
<m-button
|
|
36
33
|
theme="bordered-neutral"
|
|
@@ -78,12 +75,18 @@ export default defineComponent({
|
|
|
78
75
|
|
|
79
76
|
<style lang="scss" scoped>
|
|
80
77
|
@import 'pb-variables';
|
|
78
|
+
$responsive-breakpoint: 'm';
|
|
81
79
|
|
|
82
80
|
.pb-restitution-list-block {
|
|
83
81
|
@include set-box-shadow('l');
|
|
84
82
|
margin-bottom: $mu250;
|
|
85
|
-
padding: $
|
|
86
|
-
width:
|
|
83
|
+
padding: $mu150;
|
|
84
|
+
width: 80%;
|
|
85
|
+
|
|
86
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
87
|
+
padding: $mu250;
|
|
88
|
+
width: 630px;
|
|
89
|
+
}
|
|
87
90
|
|
|
88
91
|
&__title {
|
|
89
92
|
@include set-font-face('semi-bold');
|
|
@@ -110,18 +113,36 @@ export default defineComponent({
|
|
|
110
113
|
|
|
111
114
|
&__title {
|
|
112
115
|
@include set-font-face('regular');
|
|
113
|
-
width:
|
|
116
|
+
width: 100%;
|
|
117
|
+
|
|
118
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
119
|
+
width: 70%;
|
|
120
|
+
}
|
|
114
121
|
|
|
115
122
|
&.full {
|
|
116
|
-
display:
|
|
123
|
+
display: flex;
|
|
124
|
+
flex-direction: column;
|
|
117
125
|
width: 100%;
|
|
118
126
|
@include set-font-scale('06', 's');
|
|
127
|
+
|
|
128
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
129
|
+
align-items: center;
|
|
130
|
+
flex-direction: row;
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
&__amount {
|
|
122
135
|
@include set-font-scale('06', 's');
|
|
123
|
-
|
|
124
|
-
|
|
136
|
+
|
|
137
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
138
|
+
align-items: center;
|
|
139
|
+
display: flex;
|
|
140
|
+
margin-left: $mu050;
|
|
141
|
+
|
|
142
|
+
strong {
|
|
143
|
+
margin: 0 5px;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
125
146
|
|
|
126
147
|
strong {
|
|
127
148
|
@include set-font-scale('07', 's');
|
|
@@ -132,8 +153,14 @@ export default defineComponent({
|
|
|
132
153
|
&__price {
|
|
133
154
|
@include set-font-face('semi-bold');
|
|
134
155
|
@include set-font-scale('05', 's');
|
|
135
|
-
|
|
136
|
-
width:
|
|
156
|
+
display: flex;
|
|
157
|
+
width: 100%;
|
|
158
|
+
|
|
159
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
160
|
+
flex-direction: row;
|
|
161
|
+
text-align: right;
|
|
162
|
+
width: 30%;
|
|
163
|
+
}
|
|
137
164
|
}
|
|
138
165
|
}
|
|
139
166
|
}
|
|
@@ -141,19 +168,35 @@ export default defineComponent({
|
|
|
141
168
|
|
|
142
169
|
.pb-restitution-list-line {
|
|
143
170
|
border-bottom: 1px solid $color-grey-500;
|
|
171
|
+
display: flex;
|
|
172
|
+
flex-direction: column;
|
|
144
173
|
padding: $mu150 0 $mu075 0;
|
|
145
174
|
|
|
175
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
176
|
+
flex-direction: row;
|
|
177
|
+
}
|
|
178
|
+
|
|
146
179
|
&__title {
|
|
147
180
|
@include set-font-face('regular');
|
|
148
181
|
@include set-font-scale('06', 's');
|
|
149
|
-
|
|
182
|
+
margin-bottom: $mu050;
|
|
183
|
+
width: 100%;
|
|
184
|
+
|
|
185
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
186
|
+
margin-bottom: 0;
|
|
187
|
+
}
|
|
150
188
|
}
|
|
151
189
|
|
|
152
190
|
&__price {
|
|
153
191
|
@include set-font-face('semi-bold');
|
|
154
192
|
@include set-font-scale('06', 's');
|
|
155
|
-
|
|
156
|
-
width:
|
|
193
|
+
display: flex;
|
|
194
|
+
width: 100%;
|
|
195
|
+
|
|
196
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
197
|
+
text-align: right;
|
|
198
|
+
width: 30%;
|
|
199
|
+
}
|
|
157
200
|
|
|
158
201
|
strong {
|
|
159
202
|
@include set-font-scale('07', 's');
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
class="pb-restitution-list-line"
|
|
4
|
-
:class="{ green: line.type === 'REDUCTION' }"
|
|
5
|
-
justify-content="space-between"
|
|
6
|
-
v-if="line.type"
|
|
7
|
-
>
|
|
2
|
+
<div class="pb-restitution-list-line" :class="{ green: line.type === 'REDUCTION' }" v-if="line.type">
|
|
8
3
|
<div class="pb-restitution-list-line__title" v-html="line.text"></div>
|
|
9
|
-
<
|
|
4
|
+
<div class="pb-restitution-list-line__price" v-if="line.type != 'REDUCTION'">
|
|
10
5
|
<div class="pb-restitution-list-line__price__min">
|
|
11
6
|
{{ formatPriceRange(line.cost.min, line.cost.max).min }}€ -
|
|
12
7
|
</div>
|
|
13
8
|
<div class="pb-restitution-list-line__price__max">{{ formatPriceRange(line.cost.min, line.cost.max).max }}€</div>
|
|
14
|
-
</
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
</m-flex>
|
|
18
|
-
</m-flex>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="pb-restitution-list-line__price">{{ line.cost.reduce }}€</div>
|
|
11
|
+
</div>
|
|
19
12
|
</template>
|
|
20
13
|
|
|
21
14
|
<script lang="ts">
|
|
@@ -47,22 +40,43 @@ export default defineComponent({
|
|
|
47
40
|
|
|
48
41
|
<style lang="scss" scoped>
|
|
49
42
|
@import 'pb-variables';
|
|
43
|
+
$responsive-breakpoint: 'm';
|
|
50
44
|
|
|
51
45
|
.pb-restitution-list-line {
|
|
52
46
|
border-bottom: 1px solid $color-grey-500;
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
53
49
|
padding: $mu150 0 $mu075 0;
|
|
54
50
|
|
|
51
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
52
|
+
flex-direction: row;
|
|
53
|
+
justify-content: space-between;
|
|
54
|
+
}
|
|
55
|
+
|
|
55
56
|
&__title {
|
|
56
57
|
@include set-font-face('regular');
|
|
57
58
|
@include set-font-scale('06', 's');
|
|
58
|
-
|
|
59
|
+
margin-bottom: $mu050;
|
|
60
|
+
width: 100%;
|
|
61
|
+
|
|
62
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
63
|
+
margin-bottom: 0;
|
|
64
|
+
text-align: left;
|
|
65
|
+
width: 70%;
|
|
66
|
+
}
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
&__price {
|
|
62
70
|
@include set-font-face('semi-bold');
|
|
63
71
|
@include set-font-scale('06', 's');
|
|
64
|
-
|
|
65
|
-
width:
|
|
72
|
+
display: flex;
|
|
73
|
+
width: 100%;
|
|
74
|
+
|
|
75
|
+
@include set-from-screen($responsive-breakpoint) {
|
|
76
|
+
justify-content: flex-end;
|
|
77
|
+
text-align: right;
|
|
78
|
+
width: 30%;
|
|
79
|
+
}
|
|
66
80
|
|
|
67
81
|
strong {
|
|
68
82
|
@include set-font-scale('07', 's');
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"viewModel": {
|
|
3
|
+
"title": "Votre estimation par travaux"
|
|
4
|
+
},
|
|
5
|
+
"callToActions": [
|
|
6
|
+
{
|
|
7
|
+
"type": "button",
|
|
8
|
+
"label": "Être rappelé par un expert",
|
|
9
|
+
"href": "",
|
|
10
|
+
"bordered": false
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"conditions": ["!runtimeOptions.projectMode && !runtimeOptions.estimateCreated"],
|
|
14
|
+
"type": "button",
|
|
15
|
+
"label": "J'enregistre mon estimation",
|
|
16
|
+
"action": {
|
|
17
|
+
"type": "MODAL",
|
|
18
|
+
"code": "SUMMARY",
|
|
19
|
+
"component": "PbProjectItemSave"
|
|
20
|
+
},
|
|
21
|
+
"bordered": true
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import objectPath from 'object-path';
|
|
2
|
+
|
|
3
|
+
import { ScenarioStepAnswer } from '@/types/pb/Scenario';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This function will doEval and decorate dynamically variables from JSON templates.
|
|
7
|
+
*
|
|
8
|
+
* For instance:
|
|
9
|
+
* "${getAnswerValue('DEVELOPER', 'code') == 'YES' ? 'I'm developer' : 'I'm not developer'}".
|
|
10
|
+
*
|
|
11
|
+
* @param answers A map of string and an array of ScenarioStepAnswer.
|
|
12
|
+
* @param valueToDecorate Targeted value to decorate.
|
|
13
|
+
* @param defaultValue Empty string by default.
|
|
14
|
+
* @returns Decorated value.
|
|
15
|
+
*/
|
|
16
|
+
export function decorate(
|
|
17
|
+
answers: Map<string, ScenarioStepAnswer[]>,
|
|
18
|
+
runtimeOptions = {},
|
|
19
|
+
valueToDecorate: string,
|
|
20
|
+
defaultValue = '',
|
|
21
|
+
): string {
|
|
22
|
+
let decoratedValue = valueToDecorate;
|
|
23
|
+
if (valueToDecorate) {
|
|
24
|
+
const stringToEval = `\`${valueToDecorate}\``;
|
|
25
|
+
try {
|
|
26
|
+
decoratedValue = doEval(answers, stringToEval, defaultValue, runtimeOptions);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
decoratedValue = valueToDecorate || defaultValue;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return decoratedValue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function doEval(
|
|
35
|
+
this: any,
|
|
36
|
+
answers: Map<string, ScenarioStepAnswer[]>,
|
|
37
|
+
valueToEval: string,
|
|
38
|
+
defaultValue: string,
|
|
39
|
+
runtimeOptions: unknown,
|
|
40
|
+
): any {
|
|
41
|
+
return new Function('getAnswerValue', 'answers', 'defaultValue', 'runtimeOptions', `return ${valueToEval}`).call(
|
|
42
|
+
this,
|
|
43
|
+
getAnswerValue(answers),
|
|
44
|
+
Object.fromEntries(answers),
|
|
45
|
+
defaultValue,
|
|
46
|
+
runtimeOptions,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Function used by the scenario conditions.
|
|
52
|
+
*
|
|
53
|
+
* @param answers A map of string and an array of ScenarioStepAnswer.
|
|
54
|
+
* @returns Answers values.
|
|
55
|
+
*/
|
|
56
|
+
function getAnswerValue(answers: Map<string, ScenarioStepAnswer[]>) {
|
|
57
|
+
return (answerCode: string, path: string) => {
|
|
58
|
+
let answerValue: ScenarioStepAnswer | undefined = undefined;
|
|
59
|
+
if (answers?.get(answerCode)) {
|
|
60
|
+
const answerValues = answers.get(answerCode) ?? [];
|
|
61
|
+
answerValue = objectPath.get(answerValues[0], path);
|
|
62
|
+
}
|
|
63
|
+
return answerValue;
|
|
64
|
+
};
|
|
65
|
+
}
|