PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.8
Booking for Appointments and Events Calendar – Amelia v2.4.8
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 / public / StepForm / PaymentStep / parts / CartInfo.vue
ameliabooking / v3 / src / views / public / StepForm / PaymentStep / parts Last commit date
AppointmentInfo.vue 1 month ago CartInfo.vue 1 month ago PackageInfo.vue 1 month ago
CartInfo.vue
536 lines
1 <template>
2 <div class="am-fs__payments-wrapper" :style="cssVars">
3 <AmCollapse class="am-fs__payments-cart">
4 <template v-for="(item, index) in useAppointmentsAmountInfo(store)" :key="index">
5 <AmCollapseItem
6 v-if="
7 (paymentGateway !== 'onSite' &&
8 item.prepaid.depositAmount &&
9 store.getters['entities/getService'](item.serviceId).depositPayment !== 'disabled') ||
10 item.prepaid.discountAmount
11 "
12 :ref="(el) => (servicesRef[index] = el)"
13 :side="true"
14 :delay="500"
15 @collapse-open="collapseState[index] = false"
16 @collapse-close="collapseState[index] = true"
17 >
18 <template #heading>
19 <div class="am-fs__payments-cart-info">
20 <span>
21 {{ store.getters['entities/getService'](item.serviceId).name }}
22 </span>
23 </div>
24 </template>
25 <template #icon-below>
26 <Transition
27 :duration="{ enter: 500, leave: 500 }"
28 @enter="onCollapseClose"
29 @leave="onCollapseOpen"
30 >
31 <div v-show="collapseState[index]" class="am-fs__payments-cart-sub">
32 <p>
33 {{ amLabels.total_price }}
34 </p>
35 <p class="am-amount">
36 {{ useFormattedPrice(item.prepaid.totalAmount) }}
37 </p>
38 </div>
39 </Transition>
40 </template>
41 <template #default>
42 <div class="am-fs__payments-cart-open">
43 <!-- Discount -->
44 <div v-if="item.prepaid.discountAmount" class="am-fs__payments-cart-open-text">
45 <span> {{ amLabels.summary_services_subtotal }}: </span>
46 <span class="am-amount">
47 {{ useFormattedPrice(item.prepaid.totalAmount) }}
48 </span>
49 </div>
50
51 <div
52 v-if="item.prepaid.discountAmount"
53 class="am-fs__payments-cart-open-text am-fs__payments-cart-open-text-discount"
54 >
55 <span> {{ amLabels.discount_amount_colon }}: </span>
56 <span class="am-amount">
57 {{ useFormattedPrice(item.prepaid.discountAmount) }}
58 </span>
59 </div>
60 <!-- /Discount -->
61
62 <div
63 class="am-fs__payments-cart-sub"
64 :class="{
65 'am-fs__payments-cart-sub-border':
66 paymentGateway !== 'onSite' || item.prepaid.discountAmount,
67 }"
68 >
69 <p>{{ amLabels.total_price }}:</p>
70 <p class="am-amount">
71 {{ useFormattedPrice(item.prepaid.totalAmount - item.prepaid.discountAmount) }}
72 </p>
73 </div>
74
75 <div
76 v-if="
77 store.getters['entities/getService'](item.serviceId).depositPayment !==
78 'disabled' &&
79 item.prepaid.depositAmount &&
80 paymentGateway !== 'onSite'
81 "
82 class="am-fs__payments-cart-open-text"
83 :class="{ 'am-fs__payments-cart-open-text-border': item.prepaid.discountAmount }"
84 >
85 <span> {{ amLabels.paying_now }}: </span>
86 <span>
87 {{ useFormattedPrice(item.prepaid.depositAmount) }}
88 </span>
89 </div>
90
91 <div
92 v-if="
93 store.getters['entities/getService'](item.serviceId).depositPayment !==
94 'disabled' &&
95 item.prepaid.depositAmount &&
96 paymentGateway !== 'onSite'
97 "
98 class="am-fs__payments-cart-open-text"
99 >
100 <span> {{ amLabels.paying_later }}: </span>
101 <span>
102 {{
103 useFormattedPrice(
104 item.prepaid.totalAmount -
105 item.prepaid.discountAmount -
106 item.prepaid.depositAmount,
107 )
108 }}
109 </span>
110 </div>
111 </div>
112 </template>
113 </AmCollapseItem>
114 <div v-else class="am-fs__payments-cart-item">
115 <div class="am-fs__payments-cart-info">
116 <span>
117 {{ store.getters['entities/getService'](item.serviceId).name }}
118 </span>
119 </div>
120 <div class="am-fs__payments-cart-open">
121 <div class="am-fs__payments-cart-sub">
122 <p>
123 {{ amLabels.total_price }}
124 </p>
125 <p class="am-amount">
126 {{ useFormattedPrice(item.prepaid.totalAmount + item.prepaid.discountAmount) }}
127 </p>
128 </div>
129 </div>
130 </div>
131 </template>
132 </AmCollapse>
133
134 <div class="am-fs__payments-app-info">
135 <Coupon
136 v-if="settings.payments.coupons"
137 type="cart"
138 :count="cart.length"
139 :ids="
140 useCart(store)
141 .filter((i) => i.serviceId && i.serviceId in i.services)
142 .map((i) => i.serviceId)
143 "
144 @coupon-applied="couponApplied"
145 />
146
147 <div v-if="!onlyTotal" class="am-fs__payments-app-info-subtotal">
148 <span>{{ amLabels.subtotal }}:</span>
149 <span class="am-amount">{{ useFormattedPrice(cartAmount.totalAmount) }}</span>
150 </div>
151
152 <Transition name="am-fade">
153 <div
154 v-if="settings.payments.coupons"
155 v-show="cartAmount.discountAmount > 0"
156 class="am-fs__payments-app-info-discount"
157 :class="{ 'am-fs__payments-app-info-discount-green': cartAmount.discountAmount > 0 }"
158 >
159 <span>{{ amLabels.discount_amount_colon }}:</span>
160 <span class="am-amount">
161 {{
162 useFormattedPrice(
163 cartAmount.discountAmount > cartAmount.totalAmount
164 ? cartAmount.totalAmount
165 : cartAmount.discountAmount,
166 )
167 }}
168 </span>
169 </div>
170 </Transition>
171
172 <Transition name="am-fade">
173 <div
174 v-if="settings.payments.taxes.enabled"
175 v-show="cartAmount.taxAmount > 0"
176 class="am-fs__payments-app-info-tax"
177 >
178 <span>
179 <template v-if="amSettings.payments.taxes.excluded">
180 {{ `+${amLabels.total_tax_colon}` }}
181 </template>
182 <template v-else>
183 {{ amLabels.incl_tax }}
184 </template>
185 </span>
186 <span class="am-amount">
187 {{ useFormattedPrice(cartAmount.taxAmount) }}
188 </span>
189 </div>
190 </Transition>
191
192 <div
193 class="am-fs__payments-app-info-total"
194 :class="{ 'am-fs__payments-bordered': !onlyTotal }"
195 >
196 <span>{{ amLabels.total_amount_colon }}</span>
197 <span class="am-amount">
198 {{
199 useFormattedPrice(
200 cartAmount.totalAmount - cartAmount.discountAmount + cartAmount.taxAmount,
201 )
202 }}
203 </span>
204 </div>
205
206 <div v-if="hasDeposit && paymentGateway !== 'onSite'">
207 <div class="am-fs__payments-app-info-deposit">
208 <span>{{ amLabels.paying_now }}:</span>
209 <span class="am-amount">
210 {{
211 useFormattedPrice(
212 cartAmount.depositAmount
213 ? cartAmount.depositAmount
214 : cartAmount.totalAmount -
215 cartAmount.discountAmount +
216 cartAmount.taxAmount -
217 cartAmount.depositAmount,
218 )
219 }}
220 </span>
221 </div>
222
223 <div class="am-fs__payments-app-info-remaining">
224 <span>{{ amLabels.paying_later }}:</span>
225 <span class="am-amount">
226 {{
227 useFormattedPrice(
228 cartAmount.depositAmount
229 ? cartAmount.totalAmount -
230 cartAmount.discountAmount +
231 cartAmount.taxAmount -
232 cartAmount.depositAmount
233 : 0,
234 )
235 }}
236 </span>
237 </div>
238 </div>
239 </div>
240 </div>
241 </template>
242
243 <script setup>
244 // * Import from Vue
245 import { inject, ref, computed, watch } from 'vue'
246
247 // * Import from Vuex
248 import { useStore } from 'vuex'
249
250 // * Composables
251 import { useFormattedPrice } from '../../../../../assets/js/common/formatting.js'
252 import { useAppointmentsAmountInfo } from '../../../../../assets/js/common/appointments.js'
253 import { useCart } from '../../../../../assets/js/public/cart'
254 import { useColorTransparency } from '../../../../../assets/js/common/colorManipulation.js'
255
256 // * _components
257 import AmCollapseItem from '../../../../_components/collapse/AmCollapseItem.vue'
258 import AmCollapse from '../../../../_components/collapse/AmCollapse.vue'
259
260 // * Parts
261 import Coupon from '../../../Parts/Payment/Coupon.vue'
262
263 const store = useStore()
264
265 // * Settings
266 let amSettings = inject('settings')
267
268 const amLabels = inject('amLabels')
269
270 const settings = inject('settings')
271
272 let cart = computed(() => useCart(store))
273
274 let onlyTotal = computed(() => {
275 return (
276 (!settings.payments.coupons || cartAmount.value.discountAmount === 0) &&
277 (!settings.payments.taxes.enabled || cartAmount.value.taxAmount === 0)
278 )
279 })
280
281 let cartAmount = computed(() => {
282 let amountInfo = useAppointmentsAmountInfo(store)
283
284 let amount = {
285 totalAmount: 0,
286 discountAmount: 0,
287 taxAmount: 0,
288 depositAmount: 0,
289 }
290
291 amountInfo.forEach((item) => {
292 amount.totalAmount += item.prepaid.totalAmount
293 amount.discountAmount += item.prepaid.discountAmount
294 amount.taxAmount += item.prepaid.taxAmount
295 amount.depositAmount += item.prepaid.depositAmount
296 })
297
298 return amount
299 })
300
301 let hasDeposit = inject('hasDeposit')
302
303 let paymentGateway = computed(() => store.getters['booking/getPaymentGateway'])
304
305 let servicesRef = ref([])
306
307 let collapseState = ref({})
308
309 useAppointmentsAmountInfo(store).forEach((item, index) => {
310 collapseState.value[index] = true
311 })
312
313 function collapseAllCards() {
314 Object.keys(collapseState.value).forEach((key) => {
315 collapseState.value[key] = true
316 })
317
318 servicesRef.value.forEach((item) => {
319 if (item) {
320 item.closingFromParent()
321 }
322 })
323 }
324
325 watch(paymentGateway, () => {
326 collapseAllCards()
327 })
328
329 function onCollapseClose(el) {
330 el.style.opacity = 0
331 setTimeout(() => {
332 el.style.opacity = 1
333 el.style.height = 'var(--am-h-services-sub)'
334 }, 200)
335 }
336
337 function onCollapseOpen(el) {
338 el.style.opacity = 0
339 el.style.setProperty('--am-h-services-sub', `${el.offsetHeight}px`)
340 setTimeout(() => {
341 el.style.height = '0px'
342 }, 100)
343 }
344
345 const emits = defineEmits(['setOnSitePayment'])
346
347 function couponApplied() {
348 emits('setOnSitePayment', cartAmount.value.totalAmount - cartAmount.value.discountAmount <= 0)
349 collapseAllCards()
350 }
351
352 let amColors = inject('amColors')
353
354 let cssVars = computed(() => {
355 return {
356 '--am-c-pay-text': amColors.value.colorMainText,
357 '--am-c-pay-text-op30': useColorTransparency(amColors.value.colorMainText, 0.3),
358 '--am-c-pay-text-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
359 '--am-c-pay-text-op70': useColorTransparency(amColors.value.colorMainText, 0.7),
360 '--am-c-pay-success': amColors.value.colorSuccess,
361 '--am-c-pay-primary': amColors.value.colorPrimary,
362 }
363 })
364 </script>
365
366 <script>
367 export default {
368 name: 'CartInfo',
369 }
370 </script>
371
372 <style lang="scss">
373 .amelia-v2-booking {
374 #amelia-container {
375 .am-fs__payments {
376 &-bordered {
377 border-top: 1px dashed var(--am-c-pay-text-op30);
378 }
379
380 &-app-info {
381 margin: 0;
382
383 &-subtotal {
384 display: flex;
385 justify-content: space-between;
386 margin-top: 16px;
387
388 span {
389 font-size: 14px;
390 font-weight: 500;
391 line-height: 1.42857;
392 color: var(--am-c-pay-text);
393 }
394 }
395
396 &-discount,
397 &-tax {
398 display: flex;
399 justify-content: space-between;
400 font-size: 13px;
401 font-weight: 400;
402 line-height: 1.3846;
403 color: var(--am-c-pay-text);
404 }
405
406 &-discount {
407 &-green {
408 color: var(--am-c-pay-success);
409 }
410 }
411
412 &-total,
413 &-deposit {
414 display: flex;
415 justify-content: space-between;
416 font-size: 15px;
417 font-weight: 500;
418 line-height: 1.33333;
419 color: var(--am-c-pay-text);
420 padding: 8px 0 0;
421
422 &.am-single-row {
423 padding-top: 16px;
424 }
425
426 & > span:nth-child(2) {
427 color: var(--am-c-pay-primary);
428 }
429 }
430 }
431
432 &-cart {
433 .am-collapse-item__heading {
434 flex-wrap: wrap;
435 width: 100%;
436 padding: 12px;
437 transition-delay: 0.5s;
438
439 &-side {
440 transition-delay: 0s;
441 }
442
443 .am-collapse-item__trigger {
444 padding: 0;
445 }
446 }
447 .am-collapse-item__content {
448 & > * {
449 padding: 12px;
450 }
451 }
452
453 &-info {
454 span {
455 font-size: 12px;
456 line-height: 1.33333;
457 font-weight: 500;
458 color: var(--am-c-pay-text-op60);
459 }
460 }
461
462 &-sub {
463 width: 100%;
464 display: flex;
465 justify-content: space-between;
466 transition: all ease-in-out 0.3s;
467
468 &-border {
469 border-top: 1px dashed var(--am-c-pay-text-op30);
470 padding: 12px 0 0;
471 margin: 12px 0 4px;
472 }
473
474 p {
475 font-size: 13px;
476 font-weight: 500;
477 line-height: 1.384615;
478 color: var(--am-c-pay-text);
479 margin: 0;
480 padding: 0;
481 }
482
483 .am-amount {
484 color: var(--am-c-pay-primary);
485 }
486 }
487
488 &-open {
489 width: 100%;
490
491 &-text {
492 display: flex;
493 justify-content: space-between;
494 font-size: 13px;
495 line-height: 1.384615;
496 color: var(--am-c-pay-text);
497
498 &-discount {
499 color: var(--am-c-pay-success);
500 }
501
502 &-border {
503 border-top: 1px dashed var(--am-c-pay-text-op30);
504 padding: 12px 0 0;
505 margin: 12px 0 4px;
506 }
507 }
508 }
509
510 &-item {
511 border: 1px solid var(--am-c-pay-text-op30);
512 border-radius: 8px;
513 padding: 12px;
514 margin: 8px 0;
515 box-sizing: border-box;
516 }
517 }
518
519 .am-amount {
520 white-space: nowrap;
521 }
522
523 .am-fade-enter-active,
524 .am-fade-leave-active {
525 transition: opacity 0.5s ease;
526 }
527
528 .am-fade-enter-from,
529 .am-fade-leave-to {
530 opacity: 0;
531 }
532 }
533 }
534 }
535 </style>
536