%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/forge/takeaseat.eco-n-tech.co.uk/components/blocks/Booking/
Upload File :
Create Path :
Current File : //home/forge/takeaseat.eco-n-tech.co.uk/components/blocks/Booking/PaymentStep.vue

<template>
	<div>
		<span class="block text-center text-3xl font-bold mb-6">Payment</span>
    <div class="grid grid-cols-1 sm:grid-cols-2 gap-y-3 mb-6">
      <div class="leading-6 text-center sm:text-left">{{ Object.keys(selected_slots).length }} x Sessions with {{ therapist.user.full_name }}</div>
      <div class="flex items-center justify-center sm:justify-end text-2xl font-bold">{{ totals.formatted }}</div>
    </div>
		<div v-show="isPaymentRequestAllowed"
      id="payment-request-wrapper">
			<div class="w-full flex items-center justify-center mb-8">
				<div class="w-full" id="payment-request-button"></div>
			</div>
			<div class="relative text-center my-6">
				<span class="absolute z-10 top-1/2 left-0 transform -translate-y-1/2 block w-full h-0.5 bg-gray"></span>
				<span class="relative z-20 inline-block px-6 bg-white uppercase">Or Pay with Card</span>
			</div>
		</div>
    <div v-if="isPaymentRequestAllowed == false" 
      class="relative text-center my-6">
      <span class="absolute z-10 top-1/2 left-0 transform -translate-y-1/2 block w-full h-0.5 bg-gray"></span>
      <span class="relative z-20 inline-block px-6 bg-white uppercase">Pay with Card</span>
    </div>
    <div class="grid grid-cols-1 gap-y-2 mb-6"
      v-if="payment_methods.length > 0">
      <label 
        v-for="(payment_method, key) in payment_methods"
        v-bind:key="key"
        :for="'payment_method-'+key"
        :class="selected_payment_method == payment_method.id ? 'bg-gray' : ''"
        class="relative grid grid-cols-2 bg-white border border-black border-opacity-10 py-2 px-3 pl-12 rounded-lg transition cursor-pointer">
        <input 
          class="hidden"
          v-model="selected_payment_method"
          type="radio"
          name="payment_methods"
          :id="'payment_method-'+key"
          :value="payment_method.id" />
        <div 
          :class="'card-icon-'+payment_method.card.brand"
          class="absolute top-0 left-0.5 w-10 h-full bg-center bg-contain"></div>
        <span class="text-sm">{{ payment_method.billing_details.name }}</span>
        <div class="text-sm flex items-center justify-end">
          <span class="mx-2">****{{ payment_method.card.last4 }}</span>
          <span class="mx-2">{{ payment_method.card.exp_month }}/{{ payment_method.card.exp_year }}</span>
        </div>
      </label>
    </div>
    <div v-show="selected_payment_method == null">
      <ValidationObserver ref="paymentForm">
        <form @submit.prevent="submitForm" role="form" method="POST">
          <ValidationProvider rules="required" v-slot="{ errors }">
            <t-input-group label="Name on Card">
              <t-input 
                type="text"
                v-model="card_name"  
                placeholder="Name on Card" />
              <span class="field-invalid" v-if="errors[0]">{{ errors[0] }}</span>
            </t-input-group>
          </ValidationProvider>
          <t-input-group label="Card Information">
            <div class="px-4 py-4 bg-white border border-black border-opacity-20 rounded-xl" id="card-element"></div>
          </t-input-group>
          <div class="flex flex-col items-center justify-center sm:px-10">
            <button 
              :disabled="working == true"
              class="btn btn-primary btn-small rounded-full w-full sm:w-auto"
              type="submit">
              <span v-if="working == false">Pay Now</span>
              <span 
                class="flex items-center justify-center"
                v-else>
                <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                  <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                  <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                </svg>
                <span>Processing</span>
              </span>
            </button>
            <button @click="goBack"
              class="mt-6 uppercase text-blue-light text-sm"
              type="button">Go Back</button>
          </div>
        </form>
      </ValidationObserver>
    </div>
    <div class="flex flex-col items-center justify-center sm:px-10"
      v-if="selected_payment_method">
      <button @click="selected_payment_method = null"
        class="mb-2 uppercase text-blue-light text-sm">Use New Card</button>
      <button 
        @click="createPayment(selected_payment_method)"
        :disabled="working == true"
        class="btn btn-primary btn-small rounded-full w-full sm:w-auto"
        type="button">
        <span v-if="working == false">Pay Now</span>
        <span 
          class="flex items-center justify-center"
          v-else>
          <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
            <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
            <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
          </svg>
          <span>Processing</span>
        </span>
      </button>
      <button @click="goBack"
        class="mt-6 uppercase text-blue-light text-sm"
        type="button">Go Back</button>
    </div>
    <p class="text-sm text-center mt-6 text-black text-opacity-75">By subscribing to Take a Seat you are agreeing to all site <NuxtLink class="text-blue-light hover:underline"
      to="/terms-conditions" target="_blank">Terms and Conditions</NuxtLink>. Please read carefully before continuing.</p>
	</div>
</template>

<script>
export default {
  props: {
    value: {
      required: true
    },
    selected_slots: {
      type: Object,
      required: true
    }
  },

	data() {
		return {
			error: null,
      working: false,
      stripe: null,
      card: {},
      selected_payment_method: null,
      isPaymentRequestAllowed: false,
			paymentRequest: {},
      card_name: null
		}
	},

  computed: {
    totals() {
      return this.$store.state.booking.summary.totals
    },
    therapist() {
      return this.$store.state.booking.therapist
    },
    payment_methods() {
      return this.$store.state.account.billing.paymentMethods
    },
    setup_intent() {
      return this.$store.state.account.billing.setupIntent
    },
    connect_id() {
      return this.$store.state.booking.payment.connect_id
    }
  },

	async mounted() {
    await this.$store.dispatch('account/billing/setupIntent')
    await this.$store.dispatch('account/billing/getPaymentMethods')

    this.mountCard();
	},

	methods: {
		mountCard() {
			const elements = this.$stripe.elements();
      
			this.card = elements.create('card', {
        style: {
          base: {
            fontSize: '15px',
            fontFamily: 'Poppins, sans-serif'
          }
        }
      });

      this.getPaymentRequest();
			this.card.mount('#card-element');
		},

    submitForm() {
      this.$refs.paymentForm.validate().then(success => {
        if (!success) {
          return;
        }

        this.confirmCardSetup();
      });
    },

    async getPaymentRequest() {
			this.paymentRequest = await this.$stripe.paymentRequest({
				country: 'GB',
				currency: 'gbp',
				total: {
					amount: parseInt(this.totals.amount),
          label: 'Takeaseat Booking with '+this.therapist.user.full_name,
				},
				requestPayerName: true,
				requestPayerEmail: true
			});

			this.mountPaymentButton();
		},

		async mountPaymentButton() {
			const elements = this.$stripe.elements();

			let prButton = elements.create('paymentRequestButton', {
				paymentRequest: this.paymentRequest,
			});

			// Check the availability of the Payment Request API first.
			this.paymentRequest.canMakePayment().then(function(result) {
				if (result) {
          this.isPaymentRequestAllowed = true;
					prButton.mount('#payment-request-button');
				} else {
          this.isPaymentRequestAllowed = false;
				}
			}.bind(this));

      this.paymentRequest.on('paymentmethod', function(event) {
        event.complete('success');
        this.createPayment(event.paymentMethod.id);
      }.bind(this));
		},

    async confirmCardSetup() {
      this.working = true;

      const { setupIntent, error } = await this.$stripe.confirmCardSetup(
        this.setup_intent, {
          payment_method: {
            card: this.card,
            billing_details: {
              name: this.card_name
            }
          }
        }
      );

      if (error) {
        this.$toast.error(error.message).goAway(3000);
        await this.$store.dispatch('account/billing/setupIntent')
        this.working = false;
      } else {
        this.createPayment(setupIntent.payment_method)
      }
    },

    async createPayment(payment_method) {
      this.working = true;

      await this.$axios.post('/booking/payment/'+this.therapist.user.id, {
        grand_total: this.totals.amount,
        sessions: this.selected_slots,
        sessions_count: Object.keys(this.selected_slots).length,
        payment_method: payment_method
      }).then((response) => {
        if(response.status == 200) {
          this.createBooking(response.data);
        }
      }).catch((error) => {
        this.working = false;
        this.$toast.error(error.response.data.message).goAway(3000);
      })
    },

    async createBooking(data) {
      this.working = true;

      await this.$axios.post('/booking/create', {
        sessions: this.selected_slots,
        amount: this.totals.amount,
        therapist_id: this.therapist.id,
        charges: data.charges,
        transfer: data.transfer
      }).then((response) => {
        if(response.status == 200) {
          this.$store.commit('booking/success/setBookings', response.data)
          this.$router.push({
            path: '/booking/success'
          })
        }
      }).catch((error) => {
        this.$toast.error(error.response.message).goAway(1000);
        this.working = false;
      })
    },

    goBack() {
      this.$emit("input", 2);
    }
	}
}
</script>

Zerion Mini Shell 1.0