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 / PaymentStep.vue
ameliabooking / v3 / src / views / public / StepForm / PaymentStep Last commit date
parts 1 month ago PaymentStep.vue 2 days ago
PaymentStep.vue
797 lines
1 <template>
2 <div ref="paymentStepRef" :class="props.globalClass" :style="cssVars">
3 <div v-if="paymentError" class="am-fs__payments-error">
4 <AmAlert type="error" :title="paymentError" :show-icon="true" :closable="false"> </AmAlert>
5 </div>
6 <div v-show="ready && !loading" class="am-fs__payments">
7 <div class="am-fs__payments-heading">
8 <span class="am-fs__payments-heading-main">
9 {{ amLabels.summary }}
10 </span>
11 </div>
12
13 <div class="am-fs__payments-price">
14 <component
15 :is="componentTypes[formType]"
16 @set-on-site-payment="setOnSitePayment"
17 ></component>
18 </div>
19
20 <AmCheckbox
21 v-if="hasDeposit && fullAmount && paymentGateway !== 'onSite'"
22 v-model="paymentDeposit"
23 class="am-fs__payments-full"
24 :label="amLabels.full_amount_consent"
25 :class="{ 'am-fs__payments-full-checked': paymentDeposit }"
26 @keydown.enter="paymentDeposit = !paymentDeposit"
27 >
28 </AmCheckbox>
29
30 <p
31 v-show="Object.keys(availablePayments).filter((item) => availablePayments[item]).length > 1"
32 class="am-fs__payments-method"
33 >
34 {{ amLabels.payment_method }}
35 </p>
36 <div class="am-fs__payments-main">
37 <div class="am-fs__payments-main-cards">
38 <template v-for="(available, gateway) in availablePayments">
39 <div
40 v-if="
41 available &&
42 Object.keys(availablePayments).filter((item) => availablePayments[item]).length > 1
43 "
44 :key="gateway"
45 :class="
46 'am-fs__payments-main-button' +
47 (paymentGateway === gateway ? ' am-fs__payments-main-button_selected' : '') +
48 ' am-fs__payments-main-button-' +
49 gateway +
50 (stripeCleanupLoading ? ' am-fs__payments-main-button_disabled' : '')
51 "
52 :aria-disabled="stripeCleanupLoading"
53 tabindex="0"
54 @click="setPaymentGateway(gateway)"
55 @keydown.enter="setPaymentGateway(gateway)"
56 >
57 <img
58 v-if="available"
59 :src="
60 baseUrls.wpAmeliaPluginURL +
61 '/v3/src/assets/img/icons/' +
62 paymentsBtn.find((item) => item.key === gateway).value.name
63 "
64 :alt="gateway"
65 />
66 <div>
67 <p>{{ paymentsBtn.find((item) => item.key === gateway).value.text }}</p>
68 </div>
69 </div>
70 </template>
71 </div>
72 </div>
73 <div class="am-fs__payments-sentence">
74 <p>{{ getPaymentSentence() }}</p>
75 </div>
76 <PaymentOnSite
77 ref="refOnSitePayment"
78 :instant-booking="true"
79 :show-recaptcha="false"
80 @payment-error="callPaymentError"
81 />
82 <div v-if="paymentGateway" class="am-fs__payments-pm">
83 <component
84 :is="paymentTypes[paymentGateway]"
85 @payment-error="callPaymentError"
86 @payment-abandoned="callPaymentAbandoned"
87 />
88 </div>
89 </div>
90
91 <BookingSkeleton />
92 </div>
93 </template>
94
95 <script setup>
96 import { useStore } from 'vuex'
97 import { ref, inject, provide, markRaw, watch, computed, onMounted, reactive } from 'vue'
98 import AmCheckbox from '../../../_components/checkbox/AmCheckbox.vue'
99 import AmAlert from '../../../_components/alert/AmAlert.vue'
100 import AppointmentInfo from './parts/AppointmentInfo'
101 import CartInfo from './parts/CartInfo'
102 import PaymentStripe from '../../Parts/Payment/PaymentStripe.vue'
103 import PaymentPayPal from '../../Parts/Payment/PaymentPayPal.vue'
104 import PaymentOnSite from '../../Parts/Payment/PaymentOnSite.vue'
105 import PaymentWc from '../../Parts/Payment/PaymentWc.vue'
106 import PaymentCommon from '../../Parts/Payment/PaymentCommon.vue'
107 import PaymentSquare from '../../Parts/Payment/PaymentSquare.vue'
108 import BookingSkeleton from '../../Parts/BookingSkeleton.vue'
109 import PackageInfo from './parts/PackageInfo'
110 import { settings } from '../../../../plugins/settings'
111 import { useColorTransparency } from '../../../../assets/js/common/colorManipulation'
112 import { usePrepaidPrice, usePaymentError } from '../../../../assets/js/common/appointments'
113 import useAction from '../../../../assets/js/public/actions'
114 import { useBookingData } from '../../../../assets/js/public/booking.js'
115 import {
116 buildStripeIntentCacheKey,
117 prefetchStripePaymentIntent,
118 waitForStripeCleanup,
119 } from '../../../../assets/js/public/stripePaymentIntent.js'
120 import { useCart, useCartItem, useCartHasItems } from '../../../../assets/js/public/cart'
121
122 let props = defineProps({
123 globalClass: {
124 type: String,
125 default: '',
126 },
127 })
128
129 // * Store
130 const store = useStore()
131 const baseUrls = inject('baseUrls')
132 const shortcodeData = inject('shortcodeData')
133 const stepsArray = inject('stepsArray')
134 const sidebarSteps = inject('sidebarSteps')
135
136 // * Labels
137 const globalLabels = inject('labels')
138
139 // * local language short code
140 const localLanguage = inject('localLanguage')
141
142 // * if local lang is in settings lang
143 let langDetection = computed(() => settings.general.usedLanguages.includes(localLanguage.value))
144
145 // * Computed labels
146 let amLabels = computed(() => {
147 let computedLabels = reactive({ ...globalLabels })
148
149 if (settings.customizedData?.sbsNew?.paymentStep?.translations) {
150 let customizedLabels = settings.customizedData.sbsNew.paymentStep.translations
151 Object.keys(customizedLabels).forEach((labelKey) => {
152 if (customizedLabels[labelKey][localLanguage.value] && langDetection.value) {
153 computedLabels[labelKey] = customizedLabels[labelKey][localLanguage.value]
154 } else if (customizedLabels[labelKey].default) {
155 computedLabels[labelKey] = customizedLabels[labelKey].default
156 }
157 })
158 }
159 return computedLabels
160 })
161
162 provide('amLabels', amLabels)
163
164 // * Payment Part
165 const componentTypes = {
166 appointment: markRaw(AppointmentInfo),
167 package: markRaw(PackageInfo),
168 cart: markRaw(CartInfo),
169 }
170
171 let paymentError = computed(() => store.getters['booking/getError'])
172
173 // * Step Functions
174 const { footerBtnDisabledUpdater, headerButtonPreviousClicked, footerButtonClick } = inject(
175 'changingStepsFunctions',
176 {
177 footerBtnDisabledUpdater: () => {},
178 headerButtonPreviousClicked: {
179 value: false,
180 },
181 footerButtonClick: () => {},
182 },
183 )
184
185 watch(headerButtonPreviousClicked, () => {
186 store.commit('booking/setPaymentGateway', '')
187 })
188
189 let cart = computed(() => useCart(store))
190
191 const paymentTypes = {
192 onSite: markRaw(PaymentOnSite),
193 stripe: markRaw(PaymentStripe),
194 payPal: markRaw(PaymentPayPal),
195 razorpay: markRaw(PaymentCommon),
196 mollie: markRaw(PaymentCommon),
197 wc: markRaw(PaymentWc),
198 square: markRaw(PaymentSquare),
199 barion: markRaw(PaymentCommon),
200 }
201
202 let ready = computed(() => store.getters['entities/getReady'])
203
204 let loading = computed(() => store.getters['booking/getLoading'])
205
206 let formType = computed(() =>
207 cart.value.length > 1 ? 'cart' : store.getters['booking/getBookableType'],
208 )
209
210 let paymentGateway = computed(() => {
211 if (!store.getters['booking/getPaymentGateway']) {
212 store.commit('booking/setPaymentGateway', settings.defaultPaymentMethod)
213 }
214 return store.getters['booking/getPaymentGateway']
215 })
216
217 let hasDeposit = computed(() => {
218 switch (store.getters['booking/getBookableType']) {
219 case 'appointment': {
220 let depositPayment = false
221
222 useCart(store)
223 .filter((i) => 'services' in i && Object.keys(i.services).length)
224 .forEach((item) => {
225 let service = store.getters['entities/getCategories']
226 .find((i) => i.serviceList.filter((j) => j.id === item.serviceId).length)
227 .serviceList.find((i) => i.id === item.serviceId)
228
229 if (service.depositPayment !== 'disabled') {
230 depositPayment = true
231 }
232 })
233
234 return ready.value ? depositPayment : false
235 }
236
237 case 'package': {
238 let item = useCartItem(store)
239
240 let pack = store.getters['entities/getPackage'](item.packageId)
241
242 return ready.value ? pack.depositPayment !== 'disabled' : false
243 }
244 }
245
246 return false
247 })
248
249 provide('hasDeposit', hasDeposit)
250
251 let fullAmount = computed(() => {
252 switch (store.getters['booking/getBookableType']) {
253 case 'appointment': {
254 let fullAmountPayment = false
255
256 useCart(store)
257 .filter((i) => 'services' in i && Object.keys(i.services).length)
258 .forEach((item) => {
259 let service = store.getters['entities/getCategories']
260 .find((i) => i.serviceList.filter((j) => j.id === item.serviceId).length)
261 .serviceList.find((i) => i.id === item.serviceId)
262
263 if (service.fullPayment) {
264 fullAmountPayment = true
265 }
266 })
267
268 return ready.value ? fullAmountPayment : false
269 }
270
271 case 'package': {
272 let item = useCartItem(store)
273
274 let pack = store.getters['entities/getPackage'](item.packageId)
275
276 return ready.value ? pack.fullPayment : false
277 }
278 }
279
280 return false
281 })
282
283 // true = pay full amount
284 let paymentDeposit = computed({
285 get: () => store.getters['booking/getPaymentDeposit'],
286 set: (value) => store.commit('booking/setPaymentDeposit', value),
287 })
288
289 let paymentStepRef = ref(null)
290 provide('paymentStepRef', paymentStepRef)
291
292 let mandatoryOnSitePayment = ref(false)
293 let stripeCleanupLoading = ref(false)
294
295 let refOnSitePayment = ref(null)
296
297 function callPaymentError(msg) {
298 if (store.getters['payment/getOnSitePayment']) {
299 store.commit('payment/setOnSitePayment', false)
300 store.commit('booking/setPaymentGateway', 'onSite')
301 mandatoryOnSitePayment.value = true
302 refOnSitePayment.value.continueWithBooking()
303 }
304 usePaymentError(store, msg)
305
306 if (paymentStepRef.value) {
307 paymentStepRef.value.focus()
308 }
309 }
310
311 function callPaymentAbandoned() {
312 store.commit('booking/setLoading', false)
313 }
314
315 let availablePayments = computed(() => {
316 if (ready.value) {
317 if (mandatoryOnSitePayment.value) {
318 return {
319 onSite: true,
320 stripe: false,
321 payPal: false,
322 wc: false,
323 mollie: false,
324 square: false,
325 razorpay: false,
326 barion: false,
327 }
328 }
329
330 let entity = null
331
332 switch (store.getters['booking/getBookableType']) {
333 case 'appointment':
334 entity =
335 useCartHasItems(store) === 1
336 ? store.getters['entities/getBookableFromBookableEntities'](
337 store.getters['booking/getSelection'],
338 )
339 : null
340
341 break
342
343 case 'package':
344 entity = store.getters['entities/getPackage'](store.getters['booking/getPackageId'])
345
346 break
347 }
348
349 let entityPayments = entity && entity.settings ? JSON.parse(entity.settings)['payments'] : null
350
351 let payments = !entityPayments
352 ? {
353 onSite: settings.payments.onSite,
354 stripe: settings.payments.stripe.enabled,
355 payPal: settings.payments.payPal.enabled,
356 wc: settings.payments.wc.enabled,
357 mollie: settings.payments.mollie.enabled,
358 square: settings.payments.square.enabled,
359 razorpay: settings.payments.razorpay.enabled,
360 barion: settings.payments.barion.enabled,
361 }
362 : {
363 onSite:
364 'onSite' in entityPayments
365 ? entityPayments.onSite && settings.payments.onSite
366 : settings.payments.onSite,
367 stripe:
368 'stripe' in entityPayments
369 ? entityPayments.stripe.enabled && settings.payments.stripe.enabled
370 : settings.payments.stripe.enabled,
371 payPal:
372 'payPal' in entityPayments
373 ? entityPayments.payPal.enabled && settings.payments.payPal.enabled
374 : settings.payments.payPal.enabled,
375 wc:
376 'wc' in entityPayments
377 ? (!('enabled' in entityPayments.wc) || entityPayments.wc.enabled) &&
378 settings.payments.wc.enabled
379 : settings.payments.wc.enabled,
380 mollie:
381 'mollie' in entityPayments
382 ? entityPayments.mollie.enabled && settings.payments.mollie.enabled
383 : settings.payments.mollie.enabled,
384 razorpay:
385 'razorpay' in entityPayments
386 ? entityPayments.razorpay.enabled && settings.payments.razorpay.enabled
387 : settings.payments.razorpay.enabled,
388 square:
389 'square' in entityPayments
390 ? entityPayments.square.enabled && settings.payments.square.enabled
391 : settings.payments.square.enabled,
392 barion:
393 'barion' in entityPayments
394 ? entityPayments.barion.enabled &&
395 settings.payments.barion.enabled &&
396 ['USD', 'EUR', 'HUF', 'CZK'].includes(settings.payments.currencyCode)
397 : settings.payments.barion.enabled &&
398 ['USD', 'EUR', 'HUF', 'CZK'].includes(settings.payments.currencyCode),
399 }
400
401 if (
402 !payments.onSite &&
403 !payments.stripe &&
404 !payments.payPal &&
405 !payments.wc &&
406 !payments.mollie &&
407 !payments.square &&
408 !payments.razorpay &&
409 !payments.barion
410 ) {
411 payments = {
412 onSite: settings.payments.onSite,
413 stripe: settings.payments.stripe.enabled,
414 payPal: settings.payments.payPal.enabled,
415 wc: settings.payments.wc.enabled,
416 mollie: settings.payments.mollie.enabled,
417 square: settings.payments.square.enabled,
418 razorpay: settings.payments.razorpay.enabled,
419 barion: settings.payments.barion.enabled,
420 }
421 }
422
423 if (
424 settings.payments.defaultPaymentMethod &&
425 payments[settings.payments.defaultPaymentMethod]
426 ) {
427 store.commit('booking/setPaymentGateway', settings.payments.defaultPaymentMethod)
428
429 footerBtnDisabledUpdater(false)
430 } else {
431 if (Object.keys(payments).filter((item) => payments[item]).length === 1) {
432 for (let key in payments) {
433 if (payments[key]) {
434 store.commit('booking/setPaymentGateway', key)
435
436 footerBtnDisabledUpdater(false)
437 }
438 }
439 }
440 }
441
442 return payments
443 }
444
445 return {}
446 })
447
448 function getStripePrefetchFormData() {
449 return {
450 shortcode: shortcodeData.value,
451 steps: stepsArray.value.map((i) => i.key),
452 sidebar: sidebarSteps.value.map((i) => Object.assign({ key: i.key, data: i.stepSelectedData })),
453 }
454 }
455
456 function getStripeIntentCacheKey() {
457 const coupon = store.getters['booking/getCoupon'] || {}
458
459 return buildStripeIntentCacheKey({
460 couponDiscount: coupon.discount,
461 couponDeduction: coupon.deduction,
462 deposit: store.getters['booking/getPaymentDeposit'],
463 counter: shortcodeData.value.counter,
464 })
465 }
466
467 function prefetchStripeIntent() {
468 if (!settings.payments.stripe.enabled || !availablePayments.value.stripe) {
469 return
470 }
471
472 const bookingData = useBookingData(store, getStripePrefetchFormData(), false, {}, null)
473 bookingData.data.returnUrl = window.location.href
474
475 prefetchStripePaymentIntent(
476 shortcodeData.value.counter,
477 getStripeIntentCacheKey(),
478 bookingData.data,
479 bookingData.options,
480 ).catch(() => {})
481 }
482
483 async function setPaymentGateway(gateway) {
484 if (stripeCleanupLoading.value || paymentGateway.value === gateway) {
485 return
486 }
487
488 if (paymentGateway.value === 'stripe' || gateway === 'stripe') {
489 stripeCleanupLoading.value = true
490
491 try {
492 await waitForStripeCleanup(shortcodeData.value.counter)
493 usePaymentError(store, '')
494 store.commit('booking/setPaymentGateway', gateway)
495 footerBtnDisabledUpdater(false)
496 } finally {
497 stripeCleanupLoading.value = false
498 }
499
500 return
501 }
502
503 usePaymentError(store, '')
504 store.commit('booking/setPaymentGateway', gateway)
505 footerBtnDisabledUpdater(false)
506 }
507
508 function setOnSitePayment(isMandatory) {
509 if (settings.payments.wc.enabled ? settings.payments.wc.onSiteIfFree : true) {
510 if (isMandatory) {
511 store.commit('booking/setPaymentGateway', 'onSite')
512 }
513
514 mandatoryOnSitePayment.value = isMandatory
515 }
516 }
517
518 onMounted(() => {
519 if (paymentStepRef.value) {
520 paymentStepRef.value.focus()
521 }
522
523 if (paymentGateway.value === 'stripe') {
524 prefetchStripeIntent()
525 }
526
527 // Keep restored redirect payment errors (canceled/failed) visible until the user
528 // retries or changes payment method. Clear customer-validation and other stale
529 // errors so a corrected name does not keep showing the previous message.
530 const isPaymentStatusError =
531 paymentError.value &&
532 (paymentError.value === globalLabels.payment_canceled ||
533 paymentError.value === globalLabels.payment_error ||
534 paymentError.value === globalLabels.payment_error_default)
535
536 if (!isPaymentStatusError) {
537 usePaymentError(store, '')
538 }
539
540 if (usePrepaidPrice(store) === 0) {
541 if (settings.payments.wc.enabled === true && !settings.payments.wc.onSiteIfFree) {
542 store.commit('booking/setPaymentGateway', 'wc')
543 } else {
544 store.commit('booking/setPaymentGateway', 'onSite')
545 }
546
547 footerButtonClick()
548 }
549
550 useAction(store, {}, 'InitiateCheckout', formType.value, null, null)
551 })
552
553 let amColors = inject('amColors')
554
555 const cssVars = computed(() => {
556 return {
557 '--am-c-ps-price-bgr': useColorTransparency(amColors.value.colorBtnPrim, 0.05),
558 '--am-c-ps-total-price': amColors.value.colorBtnPrim,
559 '--am-c-ps-text-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
560 '--am-c-ps-text-op50': useColorTransparency(amColors.value.colorMainText, 0.5),
561 '--am-c-ps-text-op25': useColorTransparency(amColors.value.colorMainText, 0.25),
562 '--am-c-ps-text-op20': useColorTransparency(amColors.value.colorMainText, 0.2),
563 '--am-c-ps-text-op06': useColorTransparency(amColors.value.colorMainText, 0.06),
564 '--am-c-ps-primary': amColors.value.colorPrimary,
565 '--am-c-ps-primary-op10': useColorTransparency(amColors.value.colorPrimary, 0.1),
566 '--am-c-ps-primary-op06': useColorTransparency(amColors.value.colorPrimary, 0.06),
567 }
568 })
569
570 let paymentsBtn = []
571
572 Object.keys(availablePayments.value).forEach((key) => {
573 paymentsBtn.push({ key, value: getPaymentBtn(key) })
574 })
575
576 function getPaymentBtn(key) {
577 switch (key) {
578 case 'onSite':
579 return { text: amLabels.value['on_site'], name: 'onSite.svg' }
580 case 'payPal':
581 return { text: amLabels.value['pay_pal'], name: 'payPal.svg' }
582 case 'stripe':
583 return { text: amLabels.value['stripe'], name: 'stripe.svg' }
584 case 'razorpay':
585 return { text: amLabels.value['razorpay'], name: 'razorpay.svg' }
586 case 'mollie':
587 return { text: amLabels.value['mollie'], name: 'mollie.svg' }
588 case 'wc':
589 return { text: amLabels.value['on_line'], name: 'online.svg' }
590 case 'square':
591 return { text: amLabels.value['square'], name: 'square.svg' }
592 case 'barion':
593 return { text: amLabels.value['barion'], name: 'barion.svg' }
594 default:
595 return ''
596 }
597 }
598
599 function getPaymentSentence() {
600 return paymentGateway.value === 'onSite' && !mandatoryOnSitePayment.value
601 ? amLabels.value.payment_onsite_sentence
602 : paymentGateway.value === 'mollie' ||
603 paymentGateway.value === 'wc' ||
604 paymentGateway.value === 'barion'
605 ? amLabels.value.payment_wc_mollie_sentence
606 : ''
607 }
608 </script>
609
610 <script>
611 export default {
612 name: 'PaymentStep',
613 key: 'paymentStep',
614 sidebarData: {
615 label: 'payment_step',
616 icon: 'payment',
617 stepSelectedData: [],
618 finished: false,
619 selected: false,
620 },
621 }
622 </script>
623
624 <style lang="scss">
625 .amelia-v2-booking #amelia-container {
626 .am-fs__main-content.am-fs__payments {
627 padding-top: 0;
628 }
629
630 .am-fs__payments {
631 --am-c-ps-text: var(--am-c-main-text);
632 --am-c-ps-border: var(--am-c-inp-border);
633 & > * {
634 $count: 6;
635 @for $i from 0 through $count {
636 &:nth-child(#{$i + 1}) {
637 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{$i * 100}ms am-animation-slide-up;
638 animation-fill-mode: both;
639 }
640 }
641 }
642
643 &-heading {
644 font-size: 15px;
645 font-style: normal;
646 font-weight: 500;
647 line-height: 1.6;
648 color: var(--am-c-ps-text);
649 margin-bottom: 4px;
650 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{100}ms am-animation-slide-up;
651 animation-fill-mode: both;
652 }
653
654 &-price {
655 border: 1px solid var(--am-c-ps-text-op20);
656 border-radius: 8px;
657 padding: 16px;
658 margin-bottom: 16px;
659 }
660
661 &-sentence {
662 display: flex;
663 justify-content: center;
664 margin-top: 2px;
665 p {
666 display: inline-flex;
667 font-size: 14px;
668 font-weight: 500;
669 line-height: 1.42857;
670 color: var(--am-c-ps-text-op60);
671 }
672 }
673
674 &-full {
675 color: var(--am-c-ps-text);
676 border: 1px solid var(--am-c-ps-text-op25);
677 border-radius: 8px;
678 box-shadow: 0 1px 1px var(--am-c-ps-text-op06);
679 box-sizing: border-box;
680 padding: 12px;
681 margin-bottom: 16px;
682
683 &-checked {
684 border: 1px solid var(--am-c-ps-primary);
685 background: var(--am-c-ps-primary-op10);
686
687 &:after {
688 transform: rotate(45deg) scaleY(1);
689 }
690 }
691
692 .el-checkbox {
693 &__input {
694 height: 32px;
695 line-height: 32px;
696 align-items: center;
697 }
698
699 &__label {
700 line-height: 32px;
701 align-items: center;
702 }
703 }
704 }
705
706 &-method {
707 font-size: 18px;
708 font-weight: 500;
709 line-height: 1.55555;
710 color: var(--am-c-ps-text);
711 margin-bottom: 8px;
712 }
713
714 &-error {
715 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{100}ms am-animation-slide-up;
716 animation-fill-mode: both;
717 margin-bottom: 10px;
718 }
719
720 &-main {
721 &-cards {
722 display: flex;
723 gap: 6px;
724 justify-items: center;
725 flex-wrap: wrap;
726 }
727
728 &-button {
729 display: flex;
730 align-items: center;
731 gap: 2px;
732 min-width: 108px;
733 border: 1px solid var(--am-c-ps-text-op25);
734 border-radius: 8px;
735 box-shadow: 0 1px 1px var(--am-c-ps-text-op06);
736 box-sizing: border-box;
737 padding: 12px;
738 cursor: pointer;
739 flex-direction: column;
740 justify-items: center;
741 height: fit-content;
742
743 &:focus {
744 border: 1px solid var(--am-c-ps-primary);
745 box-shadow: 0 1px 1px var(--am-c-ps-primary-op06);
746 }
747
748 img {
749 height: 24px;
750 width: 24px;
751 }
752
753 &-barion {
754 img {
755 height: 24px;
756 width: 50px;
757 }
758 }
759
760 div {
761 p {
762 font-weight: 500;
763 font-size: 15px;
764 line-height: 24px;
765 color: var(--am-c-ps-text);
766 margin: 0;
767 text-align: center;
768 word-break: break-all;
769 }
770 span {
771 font-size: 12px;
772 font-weight: 400;
773 line-height: 1.66666;
774 color: var(--am-c-ps-text-op50);
775 }
776 }
777
778 &_selected {
779 background: var(--am-c-ps-primary-op10);
780 border: 1px solid var(--am-c-ps-primary);
781 box-sizing: border-box;
782 box-shadow: 0 1px 1px var(--am-c-ps-primary-op06);
783 }
784 }
785 }
786 // pm - payment method
787 &-pm {
788 margin-top: 24px;
789 }
790
791 .el-checkbox__label {
792 font-size: 15px;
793 }
794 }
795 }
796 </style>
797