Im Working on Full stack web application for backend im using laravel and for frontend im using VUE js . Now my issue is in Vue . Im adding Stripe payment gateway in my application. Everything is working fine but whenver i add
<stripe-checkout
ref="checkoutRef"
:pk="publishableKey"
:sessionId="sessionId"
/>
above line in my Vue code im starting to get this error :
`Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'parentNode')
and this line is necessary for stripe checkout
I tried adding div around the component but the error is not removed whenever i removed the component my application works fine but i have to add the stripe component in order to stripe checkout works
Here is my full code :
<div class="wrapper">
<TopNavigationComponent />
<SidebarComponent class="main-sidebar" />
<div class="content-wrapper">
<div class="d-flex justify-content-center">
<div class="col-md-10">
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">Cab Booking</h3>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<form @submit.prevent="handleSubmit" class="form-horizontal">
<div class="form-group">
<label for="name">Name:</label>
<input
type="text"
id="name"
v-model="booking.name"
class="form-control"
:class="{ 'is-invalid': nameError }"
placeholder="Name"
/>
<div v-if="nameError" class="invalid-feedback d-block font color">
{{ nameError }}
</div>
</div>
<div class="form-group">
<label for="phone">Phone Number:</label>
<input
type="tel"
id="phone"
v-model="booking.phone"
class="form-control"
:class="{ 'is-invalid': phoneError }"
placeholder="Phone Number"
/>
<div v-if="phoneError" class="invalid-feedback d-block font color">
{{ phoneError }}
</div>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input
type="email"
id="email"
v-model="booking.email"
class="form-control"
:class="{ 'is-invalid': emailError }"
placeholder="Email"
/>
<div v-if="emailError" class="invalid-feedback d-block font color">
{{ emailError }}
</div>
</div>
<div class="form-group">
<label for="departure-date">Departure Date and Time:</label>
<input
type="datetime-local"
id="departure-date"
v-model="booking.departureDateTime"
class="form-control"
:class="{ 'is-invalid': datetimeError }"
/>
<div v-if="datetimeError" class="invalid-feedback d-block font color">
{{ datetimeError }}
</div>
</div>
<div class="form-group">
<label for="return-date">Return Date and Time:</label>
<input
type="datetime-local"
id="return-date"
v-model="booking.returnDateTime"
class="form-control"
:class="{ 'is-invalid': returnDateTimeError }"
/>
<div v-if="returnDateTimeError" class="invalid-feedback d-block font color">
{{ returnDateTimeError }}
</div>
</div>
<div class="form-group">
<label for="cars">Cars:</label>
<select
id="cars"
v-model="booking.car"
class="form-control"
:class="{ 'is-invalid': carError }"
>
<option value="">Select a car</option>
<option v-for="car in cars" :value="car.carTitle" :key="car.id">
{{ car.carTitle }}
</option>
</select>
<div v-if="carError" class="invalid-feedback d-block font color">
{{ carError }}
</div>
</div>
<router-link to="/dashboard">
<button class="btn btn-primary button" type="button">Cancel</button>
</router-link>
<button class="stripe-button" @click="submit">Pay now!</button>
<div>
<stripe-checkout
ref="checkoutRef"
:pk="publishableKey"
:sessionId="sessionId"
/>
</div>
<button type="submit" class="paypal-button">
<i class="paypal-logo">Pay</i><i class="paypal-logo">Pal</i>
</button>
</form>
</div>
<div class="col-md-6">
<div class="booking-details">
<h2>Booking Details</h2>
<p><strong> Name:</strong> {{ booking.name }}</p>
<p><strong>Phone Number:</strong> {{ booking.phone }}</p>
<p><strong>Email:</strong> {{ booking.email }}</p>
<p><strong>Departure Date and Time:</strong> {{ booking.departureDateTime }}</p>
<p><strong>Return Date and Time: </strong>{{ booking.returnDateTime }}</p>
<p><strong>Car:</strong> {{ booking.car }}</p>
<p><strong>Price:</strong> {{ getPrice() }} $ /hr</p>
<p><strong>Total Bill:</strong> {{ calculateBill.toFixed(0) }} $</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref, onMounted, computed } from 'vue'
import axios from 'axios'
import API_URL from '@/config'
import SidebarComponent from '@/components/SidebarComponent.vue'
import TopNavigationComponent from '@/components/TopNavigationComponent.vue'
import { toast } from 'vue3-toastify'
import 'vue3-toastify/dist/index.css'
import { useRouter, useRoute } from 'vue-router'
import { StripeCheckout } from '@vue-stripe/vue-stripe'
export default {
components: {
SidebarComponent,
TopNavigationComponent,
StripeCheckout
},
setup() {
const booking = ref({
name: '',
phone: '',
email: '',
departureDateTime: '',
returnDateTime: '',
car: ''
})
const cars = ref([])
const nameError = ref(null)
const phoneError = ref(null)
const emailError = ref(null)
const datetimeError = ref(null)
const returnDateTimeError = ref(null)
const carError = ref(null)
const route = useRoute()
const router = useRouter()
const publishableKey =
'pk_test_51NE6AVBIPVlJ4mt0xjpNsBF37Dus99OLspog6U4DYOlGa7XTmZumxf3KGzJXCuSGm1C7jv7sCxZatK3fw6jA66CD004S3P4pqS'
const sessionId = ref(null)
const checkoutRef = ref(null)
const getSession = () => {
axios
.get(`${API_URL}/getSession`)
.then((res) => {
sessionId.value = res.data.id
})
.catch((err) => {
console.log(err)
})
}
const submit = () => {
if (sessionId.value && checkoutRef.value) {
checkoutRef.value.redirectToCheckout()
}
}
const fetchCars = async () => {
try {
const response = await axios.get(`${API_URL}/listofcars`)
cars.value = response.data
} catch (error) {
console.error(error)
}
}
onMounted(() => {
fetchCars()
getSession()
const paymentSuccess = route.query.success === 'true'
const paymentFailure = route.query.success === 'false'
if (paymentSuccess) {
toast.success('Your Booking Has Been Successful', {
position: 'top-right',
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: 'colored'
})
router.replace({ query: { ...route.query, success: undefined } })
} else if (paymentFailure) {
toast.error('Booking failed. Please try again.', {
position: 'top-right',
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: 'colored'
})
router.replace({ query: { ...route.query, success: undefined } })
}
})
const calculateBill = computed(() => {
const selectedCar = cars.value.find((car) => car.carTitle === booking.value.car)
if (selectedCar) {
const departure = new Date(booking.value.departureDateTime)
const returnDate = new Date(booking.value.returnDateTime)
const hours = Math.abs(returnDate - departure) / 36e5
return selectedCar.price * hours
}
return 0
})
const getPrice = () => {
const selectedCar = cars.value.find((car) => car.carTitle === booking.value.car)
return selectedCar ? selectedCar.price : ''
}
const handleSubmit = async (e) => {
e.preventDefault()
nameError.value = null
phoneError.value = null
emailError.value = null
datetimeError.value = null
returnDateTimeError.value = null
carError.value = null
if (!booking.value.name) {
nameError.value = 'Name is required'
}
if (!booking.value.phone) {
phoneError.value = 'Phone No is required'
}
if (!booking.value.email) {
emailError.value = 'Email is required'
}
if (!booking.value.departureDateTime) {
datetimeError.value = 'Departure Date & Time is required'
}
if (!booking.value.returnDateTime) {
returnDateTimeError.value = 'Return Date & Time is required'
}
if (!booking.value.car) {
carError.value = 'Please Select a Car For Checkout'
}
if (
!booking.value.name ||
!booking.value.phone ||
!booking.value.email ||
!booking.value.departureDateTime ||
!booking.value.returnDateTime ||
!booking.value.car
) {
return
}
let formData = new FormData()
formData.append('name', booking.value.name)
formData.append('phone', booking.value.phone)
formData.append('email', booking.value.email)
formData.append('departure-date', booking.value.departureDateTime)
formData.append('return-date', booking.value.returnDateTime)
formData.append('cars', booking.value.car)
formData.append('totalBill', calculateBill.value.toFixed(0))
try {
const response = await axios.post(`${API_URL}/payment/initiate`, formData)
if (response.status === 200) {
const data = response.data.redirect_url
window.location.href = data
}
} catch (error) {
toast.error('An error occurred while booking the car', {
position: 'top-right',
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: 'colored'
})
}
}
return {
booking,
cars,
handleSubmit,
getPrice,
calculateBill,
nameError,
phoneError,
emailError,
datetimeError,
returnDateTimeError,
carError,
publishableKey,
sessionId,
checkoutRef,
submit
}
}
}
</script>