PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.6
Booking for Appointments and Events Calendar – Amelia v2.4.6
2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / v3 / src / views / admin / customize / steps / parts / CartItemBody.vue
ameliabooking / v3 / src / views / admin / customize / steps / parts Last commit date
AddToCalendar.vue 1 month ago AppointmentInfo.vue 1 month ago AppointmentInfoService.vue 1 month ago Calendar.vue 1 month ago CartItemBody.vue 1 month ago CartItemHead.vue 1 month ago CustomerCongratsInfo.vue 1 month ago PackageInfo.vue 1 month ago PackageInfoService.vue 1 month ago PaymentCongratsInfo.vue 1 month ago PaymentPackageInfo.vue 1 month ago
CartItemBody.vue
425 lines
1 <template>
2 <div v-if="props.data" class="am-fs__ci" :style="cssVars">
3 <div class="am-fs__ci-main">
4 <!-- Service -->
5 <div class="am-fs__ci-block">
6 <div class="am-fs__ci-title">
7 {{ labelsDisplay('service_colon', 'cartStep') }}
8 </div>
9 <div class="am-fs__ci-prod">
10 <div class="am-fs__ci-prod__title">
11 <span class="am-fs__ci-prod__title-name">
12 {{ data.service.name }}
13 </span>
14 <span class="am-fs__ci-prod__title-price">
15 {{ `(${useFormattedPrice(data.service.price)})` }}
16 </span>
17 <span class="am-fs__ci-prod__title-number">
18 {{
19 `x ${data.service.persons} ${
20 data.service.persons === 1
21 ? labelsDisplay('summary_person', 'cartStep')
22 : labelsDisplay('summary_persons', 'cartStep')
23 }`
24 }}
25 </span>
26 </div>
27 <div class="am-fs__ci-prod__price">
28 {{ useFormattedPrice(serviceAggregatedPrice) }}
29 </div>
30 </div>
31 <div class="am-fs__ci-cost">
32 <div class="am-fs__ci-cost__title">
33 {{ labelsDisplay('summary_services_subtotal', 'cartStep') }}
34 </div>
35 <div class="am-fs__ci-cost__price">
36 {{ useFormattedPrice(serviceAggregatedPrice) }}
37 </div>
38 </div>
39 </div>
40 <!-- /Service -->
41
42 <!-- Extras -->
43 <div v-if="data.extras" class="am-fs__ci-block">
44 <div class="am-fs__ci-title">
45 {{ labelsDisplay('extras', 'cartStep') }}
46 </div>
47 <div
48 v-for="(extraData, extraIndex) in data.extras"
49 :key="extraIndex"
50 class="am-fs__ci-prod"
51 >
52 <div class="am-fs__ci-prod__title">
53 <span class="am-fs__ci-prod__title-name">
54 {{ extraData.name }}
55 </span>
56 <span v-if="extraData.price" class="am-fs__ci-prod__title-price">
57 {{ `(${useFormattedPrice(extraData.price)})` }}
58 </span>
59 <span class="am-fs__ci-prod__title-number">
60 {{ ` x ${extraData.quantity}` }}
61 </span>
62 <span class="am-fs__ci-prod__title-number">
63 {{
64 ` x ${data.service.persons} ${
65 data.service.persons === 1
66 ? labelsDisplay('summary_person', 'cartStep')
67 : labelsDisplay('summary_persons', 'cartStep')
68 }`
69 }}
70 </span>
71 </div>
72 <div class="am-fs__ci-prod__price">
73 {{ useFormattedPrice(extraAggregatedPrice(extraData)) }}
74 </div>
75 </div>
76 <div class="am-fs__ci-cost">
77 <div class="am-fs__ci-cost__title">
78 {{ labelsDisplay('summary_extras_subtotal', 'cartStep') }}
79 </div>
80 <div class="am-fs__ci-cost__price">
81 {{ useFormattedPrice(extrasTotalPrice()) }}
82 </div>
83 </div>
84 </div>
85 <!-- /Extras -->
86
87 <!-- Total -->
88 <div class="am-fs__ci-block">
89 <div class="am-fs__ci-cost">
90 <div class="am-fs__ci-cost__title">
91 {{ labelsDisplay('total_price', 'cartStep') }}
92 </div>
93 <div class="am-fs__ci-cost__price">
94 {{ useFormattedPrice(serviceAggregatedPrice + extrasTotalPrice()) }}
95 </div>
96 </div>
97 </div>
98 <!-- /Total -->
99 </div>
100
101 <div class="am-fs__ci-info">
102 <div class="am-fs__ci-title">
103 {{ labelsDisplay('info', 'cartStep') }}
104 </div>
105 <div class="am-fs__ci-info__el">
106 <span class="am-icon-calendar"></span>
107 <span>
108 {{ getFrontedFormattedDate(props.data.service.date) }}
109 </span>
110 </div>
111 <div class="am-fs__ci-info__el">
112 <span class="am-icon-clock"></span>
113 <span>
114 {{
115 `${getFrontedFormattedTime(props.data.service.time)} - ${getFrontedFormattedTime(
116 addSeconds(props.data.service.time, duration),
117 )}`
118 }}
119 </span>
120 </div>
121 <div class="am-fs__ci-info__el">
122 <span class="am-icon-user"></span>
123 <span>
124 {{ `${props.data.service.employee.firstName} ${props.data.service.employee.lastName}` }}
125 </span>
126 </div>
127 <div class="am-fs__ci-info__el">
128 <span class="am-icon-date-time"></span>
129 <span>
130 {{ useSecondsToDuration(duration, amLabels.h, amLabels.min) }}
131 </span>
132 </div>
133 <div class="am-fs__ci-info__el">
134 <span class="am-icon-locations"></span>
135 <span>
136 {{ props.data.service.location.name }}
137 </span>
138 </div>
139 <div class="am-fs__ci-info__el">
140 <span class="am-icon-users-plus"></span>
141 <span>
142 {{ `${props.data.service.persons} / ${props.data.service.maxCapacity}` }}
143 </span>
144 </div>
145 </div>
146
147 <div class="am-fs__ci-manage">
148 <div class="am-fs__ci-manage__discard">
149 <span class="am-icon-bucket"></span>
150 <span>{{ labelsDisplay('delete', 'cartStep') }}</span>
151 </div>
152 <div class="am-fs__ci-manage__edit">
153 <span>{{ labelsDisplay('edit', 'cartStep') }}</span>
154 <span class="am-icon-edit"></span>
155 </div>
156 </div>
157 </div>
158 </template>
159
160 <script setup>
161 // * Import from Vue
162 import { computed, inject, ref } from 'vue'
163
164 // * Composables
165 import { useColorTransparency } from '../../../../../assets/js/common/colorManipulation'
166 import { useFormattedPrice } from '../../../../../assets/js/common/formatting'
167 import {
168 addSeconds,
169 useSecondsToDuration,
170 getFrontedFormattedTime,
171 getFrontedFormattedDate,
172 } from '../../../../../assets/js/common/date'
173 import { useReactiveCustomize } from '../../../../../assets/js/admin/useReactiveCustomize.js'
174
175 let props = defineProps({
176 data: {
177 type: Object,
178 default: null,
179 },
180 index: {
181 type: Number,
182 default: 0,
183 },
184 size: {
185 type: Number,
186 default: 0,
187 },
188 globalClass: {
189 type: String,
190 default: '',
191 },
192 })
193
194 // * Features
195 let features = inject('features')
196
197 // * Multi lingual
198 let langKey = inject('langKey')
199
200 // * Component labels
201 let amLabels = inject('labels')
202
203 let pageRenderKey = inject('pageRenderKey')
204 const { amCustomize } = useReactiveCustomize()
205
206 // * Label computed function
207 function labelsDisplay(label, stepKey) {
208 let computedLabel = computed(() => {
209 return amCustomize.value[pageRenderKey.value][stepKey].translations &&
210 amCustomize.value[pageRenderKey.value][stepKey].translations[label] &&
211 amCustomize.value[pageRenderKey.value][stepKey].translations[label][langKey.value]
212 ? amCustomize.value[pageRenderKey.value][stepKey].translations[label][langKey.value]
213 : amLabels[label]
214 })
215
216 return computedLabel.value
217 }
218
219 /**************
220 * Navigation *
221 *************/
222
223 let serviceAggregatedPrice = computed(() => {
224 return props.data.service.price * props.data.service.persons
225 })
226
227 function extraAggregatedPrice(extra) {
228 return extra.price * extra.quantity * props.data.service.persons
229 }
230
231 function extrasTotalPrice() {
232 let price = 0
233 if (!features.extras) return price
234
235 props.data.extras.forEach((extra) => {
236 price += extraAggregatedPrice(extra)
237 })
238
239 return price
240 }
241
242 let duration = ref(
243 props.data.service.duration +
244 (features.extras
245 ? props.data.extras.reduce((accumulator, extra) => {
246 return accumulator + extra.duration * extra.quantity
247 }, 0)
248 : 0),
249 )
250
251 let amColors = inject('amColors')
252
253 let cssVars = computed(() => {
254 return {
255 // am - amelia
256 // c - color
257 // ci - cart item
258 // op - opacity
259 '--am-c-ci-text': amColors.value.colorMainText,
260 '--am-c-ci-text-op80': useColorTransparency(amColors.value.colorMainText, 0.8),
261 '--am-c-ci-text-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
262 '--am-c-ci-text-op30': useColorTransparency(amColors.value.colorMainText, 0.3),
263 '--am-c-ci-text-op05': useColorTransparency(amColors.value.colorMainText, 0.05),
264 '--am-c-ci-success': amColors.value.colorSuccess,
265 '--am-c-ci-primary': amColors.value.colorPrimary,
266 '--am-c-ci-error': amColors.value.colorError,
267 }
268 })
269 </script>
270
271 <script>
272 export default {
273 name: 'CartItemBody',
274 }
275 </script>
276
277 <style lang="scss">
278 #amelia-app-backend-new #amelia-container {
279 // am - amelia
280 // fs - form step
281 // ci - cart item
282 .am-fs__ci {
283 width: 100%;
284 padding: 12px;
285
286 * {
287 word-break: break-word;
288 }
289
290 &-block {
291 padding: 0 0 12px;
292 margin: 0 0 12px;
293 border-bottom: 1px dashed var(--am-c-ci-text-op30);
294
295 &:last-of-type {
296 border: none;
297 margin: 0;
298 }
299 }
300
301 &-title {
302 width: 100%;
303 font-size: 12px;
304 font-weight: 500;
305 line-height: 1.333333;
306 margin: 0 0 8px;
307 color: var(--am-c-ci-text-op60);
308 }
309
310 &-prod {
311 width: 100%;
312 display: flex;
313 align-items: center;
314 justify-content: space-between;
315 margin: 0 0 8px;
316
317 &__title {
318 display: flex;
319 flex-wrap: wrap;
320 align-items: center;
321 color: var(--am-c-ci-text);
322
323 * {
324 display: block;
325 font-size: 13px;
326 line-height: 1.38462;
327 font-weight: 400;
328 margin-right: 4px;
329 color: var(--am-c-ci-text);
330 }
331 }
332
333 &__price {
334 flex: 0 0 auto;
335 align-self: flex-start;
336 font-size: 13px;
337 line-height: 1.38462;
338 font-weight: 400;
339 color: var(--am-c-ci-text);
340 }
341 }
342
343 &-cost {
344 width: 100%;
345 display: flex;
346 align-items: center;
347 justify-content: space-between;
348 margin: 12px 0 0;
349
350 * {
351 font-size: 13px;
352 line-height: 1.38462;
353 font-weight: 500;
354 color: var(--am-c-ci-text);
355 }
356 }
357
358 &-info {
359 display: flex;
360 align-items: center;
361 flex-wrap: wrap;
362 padding: 12px;
363 background: var(--am-c-ci-text-op05);
364 border-radius: 8px;
365
366 &__el {
367 display: flex;
368 align-items: center;
369 margin: 0 10px 0 0;
370
371 span {
372 display: block;
373 font-size: 13px;
374 font-weight: 400;
375 line-height: 1.38462;
376 color: var(--am-c-ci-text-op80);
377
378 &[class*='am-icon']*='am-icon'] {
379 font-size: 24px;
380 line-height: 1;
381 color: var(--am-c-ci-primary);
382 }
383 }
384 }
385 }
386
387 &-manage {
388 width: 100%;
389 display: flex;
390 align-items: center;
391 justify-content: space-between;
392 flex-wrap: wrap;
393 margin: 14px 0 0;
394
395 div {
396 display: flex;
397 align-items: center;
398 padding: 2px 6px;
399 }
400
401 span {
402 display: block;
403 font-size: 14px;
404 font-weight: 500;
405 line-height: 1.42857;
406 cursor: pointer;
407
408 &[class*='am-icon']*='am-icon'] {
409 font-size: 24px;
410 line-height: 1;
411 }
412 }
413
414 &__discard {
415 color: var(--am-c-ci-error);
416 }
417
418 &__edit {
419 color: var(--am-c-ci-primary);
420 }
421 }
422 }
423 }
424 </style>
425