365 lines
18 KiB
Vue
365 lines
18 KiB
Vue
<script setup>
|
|
import StartOverPupup from '@/views/pages/home/StartOverPupup.vue';
|
|
import axios from '@axios';
|
|
import {
|
|
cardNumberValidator,
|
|
cvvValidator,
|
|
expiryValidator,
|
|
requiredValidator
|
|
} from '@validators';
|
|
import moment from 'moment';
|
|
import { onMounted } from 'vue';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { useStore } from 'vuex';
|
|
const store = useStore()
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const isMobile = ref(window.innerWidth <= 768); // Assuming mobile width is less than or equal to 768px
|
|
const patient_id = localStorage.getItem('patient_id')
|
|
const access_token = store.access_token;
|
|
const seetingPlanLogo = ref();
|
|
const isLoadingVisible = ref(false)
|
|
const paymentForm = ref()
|
|
const cardNumber = ref('')
|
|
const expiry = ref('')
|
|
const cvv = ref('')
|
|
const zipcode = ref('')
|
|
const firstName = ref('')
|
|
const lastName = ref('')
|
|
const email = ref('');
|
|
const phoneNumber = ref('');
|
|
const address = ref('');
|
|
const city = ref('');
|
|
const state = ref('');
|
|
const zip_code = ref('');
|
|
const country = ref('');
|
|
const dob = ref('')
|
|
const gender = ref('')
|
|
const marital_status = ref('')
|
|
const height = ref('')
|
|
const weight = ref('')
|
|
const scheduleDate = ref('');
|
|
const scheduleTime = ref('');
|
|
const timeZone = ref('');
|
|
const timeDifference = ref();
|
|
const shippingAddress = ref();
|
|
const todayDate = ref()
|
|
const planName = ref('')
|
|
const planAmount = ref('')
|
|
const myPlanName = ref(localStorage.getItem('plan_name'))
|
|
const myPlanPrice = ref(localStorage.getItem('plan_price'))
|
|
const myPlanTitle1 = ref(localStorage.getItem('list_sub_title'))
|
|
const myPlanTitle2 = ref(localStorage.getItem('list_one_title'))
|
|
const myPlanTitle3 = ref(localStorage.getItem('list_two_title'))
|
|
const myPlanImage = ref(localStorage.getItem('plan_image'))
|
|
const currentPath = window.location.origin
|
|
|
|
onBeforeMount(async () => {
|
|
store.dispatch('updateIsLoading', true)
|
|
store.dispatch('updateCurrentPage', 'process-payment')
|
|
localStorage.setItem('currentPage', 'process-payment')
|
|
await store.dispatch('getPatientInfo')
|
|
await store.dispatch('getPlanInfo')
|
|
await store.dispatch('getPatientAppointment')
|
|
await store.dispatch('getAdditionalInformation')
|
|
planName.value = store.getters.getPatientPlan.plan_name
|
|
planAmount.value = store.getters.getPatientPlan.plan_amount
|
|
|
|
firstName.value = store.getters.getPatient.first_name;
|
|
lastName.value = store.getters.getPatient.last_name
|
|
email.value = store.getters.getPatient.email
|
|
phoneNumber.value = store.getters.getPatient.phone_no
|
|
dob.value = store.getters.getPatient.dob
|
|
gender.value = store.getters.getPatient.gender
|
|
marital_status.value = store.getters.getPatient.marital_status
|
|
weight.value = store.getters.getPatient.weight
|
|
height.value = store.getters.getPatient.height
|
|
|
|
address.value = store.getters.getShippingInformation.shipping_address1
|
|
city.value = store.getters.getShippingInformation.shipping_city
|
|
state.value = store.getters.getShippingInformation.shipping_state
|
|
zip_code.value = store.getters.getShippingInformation.shipping_zipcode
|
|
country.value = store.getters.getShippingInformation.billing_address1
|
|
shippingAddress.value = (address.value ? address.value + ', ' : '') +
|
|
(city.value ? city.value + ', ' : '') +
|
|
(state.value ? state.value + ' ' : '') +
|
|
(zip_code.value ? zip_code.value + ', ' : '') +
|
|
(country.value ? country.value : '');
|
|
|
|
let diffInMinutes = store.getters.getTimeDiff.time_diff;
|
|
|
|
|
|
// scheduleTime.value = appointmentData.appointment_time;
|
|
const time = moment(store.getters.getBookedAppointment.appointment_time, 'HH:mm:ss');
|
|
|
|
// Check if the time is AM or PM
|
|
scheduleTime.value = time.format('HH:mm a');
|
|
timeZone.value = store.getters.getBookedAppointment.timezone;
|
|
timeDifference.value = diffInMinutes;
|
|
// console.log(gender.value);
|
|
|
|
let dateString = store.getters.getPatient.dob
|
|
let parts = dateString.split("-");
|
|
dob.value = `${parts[1]}-${parts[2]}-${parts[0]}`;
|
|
|
|
const appointment_date = new Date(store.getters.getBookedAppointment.appointment_date);
|
|
const formattedDate = new Intl.DateTimeFormat('en-US', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
}).format(appointment_date);
|
|
scheduleDate.value = formattedDate;
|
|
store.dispatch('updateIsLoading', false)
|
|
})
|
|
|
|
onMounted(async () => {
|
|
todayDate.value = moment().format('MM-DD-YYYY');
|
|
window.addEventListener('resize', checkIfMobile);
|
|
let setting = await axios.post('/api/settings', {})
|
|
console.log(setting.data)
|
|
seetingPlanLogo.value = '/assets/logo/' + setting.data.logo
|
|
|
|
})
|
|
// Detach event listener on component unmount
|
|
onUnmounted(() => {
|
|
window.removeEventListener('resize', checkIfMobile);
|
|
});
|
|
const checkIfMobile = () => {
|
|
isMobile.value = window.innerWidth <= 768;
|
|
};
|
|
|
|
const cardNumberFormat = () => {
|
|
cardNumber.value = cardNumber.value.replace(/\D/g, '').substring(0, 16);
|
|
|
|
}
|
|
const formatExpiry = () => {
|
|
// Automatically format the input to MM/YY format
|
|
expiry.value = expiry.value.replace(/\D/g, '').slice(0, 4).replace(/(\d{2})(\d{2})/, '$1/$2');
|
|
}
|
|
const handleCVVInput = () => {
|
|
// Remove non-digit characters from input
|
|
cvv.value = cvv.value.replace(/\D/g, '');
|
|
}
|
|
|
|
const validatePayment = async () => {
|
|
const { valid: isValid } = await paymentForm.value?.validate();
|
|
console.log('isValid ', isValid);
|
|
if (isValid) {
|
|
await processPayment()
|
|
|
|
router.replace(route.query.to && route.query.to != '/process-payment' ? String(route.query.to) : '/thankyou')
|
|
}
|
|
};
|
|
|
|
const processPayment = async () => {
|
|
await store.dispatch('processPayment')
|
|
}
|
|
const imageSrc = (src) => {
|
|
return `${currentPath}/product/${src}`
|
|
};
|
|
const backFun = () => {
|
|
store.dispatch('updateIsLoading', true)
|
|
router.replace(route.query.to && route.query.to != '/process-payment' ? String(route.query.to) : '/checkout')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<StartOverPupup :showPopup="store.getters.getShowStartOverPupup"></StartOverPupup>
|
|
<VDialog v-model="store.getters.getIsLoading" width="110" height="150" color="primary">
|
|
<VCardText class="" style="color: white !important;">
|
|
<div class="demo-space-x">
|
|
<VProgressCircular :size="40" color="primary" indeterminate />
|
|
</div>
|
|
</VCardText>
|
|
</VDialog>
|
|
<div class="pb-sm-5 pb-2 rounded-top">
|
|
<!-- <VContainer> -->
|
|
<div class="auth-wrapper d-flex align-center justify-center pa-4 mt-4" style="flex-direction: column;">
|
|
<h3 class="mb-8" style="max-width: 600px;width: 100%">Review your treatment and pay</h3>
|
|
<VCard class="auth-card pa-2 rounded-3 mt-1 pb-4 pt-4" style="max-width: 600px;width: 100%;">
|
|
<p class="mb-0" style="font-family: system-ui;">$0 Due Now - Pay Upon Medical Approval</p>
|
|
</VCard>
|
|
<h5 class="mt-8" style="max-width: 600px;width: 100%">Your Plan</h5>
|
|
<VCard class="auth-card pa-2 rounded-3 mt-1 pb-2" style="max-width: 600px;width: 100%">
|
|
<v-row>
|
|
<v-col cols="12" md="3">
|
|
<v-img :src="imageSrc(myPlanImage)" alt="Selected Item" width="200px" height="150px"></v-img>
|
|
</v-col>
|
|
<v-col cols="12" md="9">
|
|
<v-card-title class="pb-0">
|
|
<div style="font-size: 14px;">
|
|
<strong>{{ myPlanName }}</strong>
|
|
<span class="float-right"><strong>${{ myPlanPrice }}</strong></span>
|
|
</div>
|
|
</v-card-title>
|
|
<v-card-subtitle class="pt-0">0.25mg</v-card-subtitle>
|
|
<v-card-text class="pt-0 pb-0">
|
|
<p>1ml x 1 Month</p>
|
|
</v-card-text>
|
|
</v-col>
|
|
</v-row>
|
|
<v-list dense>
|
|
<v-list-item style="border-top: 1px solid #c0c0c075;">
|
|
<v-list-item-content>
|
|
<v-list-item-title>
|
|
<span>{{ myPlanTitle1 }}</span>
|
|
<span class="float-right"><b>Included</b></span>
|
|
</v-list-item-title>
|
|
</v-list-item-content>
|
|
</v-list-item>
|
|
<v-list-item style="border-top: 1px solid #c0c0c075;">
|
|
<v-list-item-content>
|
|
<v-list-item-title>
|
|
<span>{{ myPlanTitle2 }}</span>
|
|
<span class="float-right"><b>Included</b></span>
|
|
</v-list-item-title>
|
|
</v-list-item-content>
|
|
</v-list-item>
|
|
<v-list-item style="border-top: 1px solid #c0c0c075;">
|
|
<v-list-item-content>
|
|
<v-list-item-title>
|
|
<span>{{ myPlanTitle3 }}</span>
|
|
</v-list-item-title>
|
|
</v-list-item-content>
|
|
</v-list-item>
|
|
<!-- Add more features as needed -->
|
|
</v-list>
|
|
</VCard>
|
|
<h5 class="mt-8" style="max-width: 600px;width: 100%">Payment</h5>
|
|
<VCard class="auth-card pa-2 rounded-3 mt-1 pb-2" style="max-width: 600px;width: 100%">
|
|
<h4 class="mb-2 mt-2">
|
|
<VIcon>mdi-credit-card</VIcon> Card
|
|
</h4>
|
|
<VForm ref="paymentForm" @submit.prevent="() => { }">
|
|
<VRow>
|
|
<VCol cols="12" lg="12" md="12">
|
|
<VRow>
|
|
<VCol cols="12" lg="12" md="12">
|
|
<VTextField v-model="cardNumber" label="Credit Card Number*"
|
|
:rules="[requiredValidator, cardNumberValidator]" placeholder="xxxxxxxxxxxxxxxx"
|
|
@input="cardNumberFormat" density="comfortable" />
|
|
</VCol>
|
|
<!-- <VCol cols="12" lg="4" md="4">
|
|
<VTextField v-model="zipcode" label="Zipcode*" type="number"
|
|
:rules="[requiredValidator]" placeholder="zipcode" density="comfortable"/>
|
|
</VCol> -->
|
|
<VCol cols="12" lg="6" md="6">
|
|
<VTextField v-model="expiry" label="Expiration Date*"
|
|
:rules="[requiredValidator, expiryValidator]" placeholder="MM/YY"
|
|
@input="formatExpiry" density="comfortable" />
|
|
</VCol>
|
|
<VCol cols="12" lg="6" md="6">
|
|
<VTextField v-model="cvv" :rules="[requiredValidator, cvvValidator]" label="CVV*"
|
|
maxlength="3" @input="handleCVVInput" density="comfortable" />
|
|
</VCol>
|
|
</VRow>
|
|
</VCol>
|
|
<!-- <VCol cols="12" lg="6" md="6">
|
|
<svg v-if="!isMobile" xmlns="http://www.w3.org/2000/svg"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="auto" height="150"
|
|
viewBox="0 0 256 256" xml:space="preserve">
|
|
|
|
<defs>
|
|
</defs>
|
|
<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;"
|
|
transform="translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)">
|
|
<path
|
|
d="M 81.159 25.776 l -0.9 -10.05 c -0.101 -1.123 -1.092 -1.952 -2.215 -1.851 L 1.86 20.698 c -1.123 0.101 -1.952 1.092 -1.851 2.215 l 4.128 46.09 c 0.101 1.123 1.092 1.952 2.215 1.851 l 3.076 -0.276 L 81.159 25.776 z"
|
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(176,182,188); fill-rule: nonzero; opacity: 1;"
|
|
transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
<path
|
|
d="M 9.428 74.189 c 0 1.074 0.871 1.944 1.944 1.944 h 76.683 c 1.074 0 1.944 -0.871 1.944 -1.944 V 49.73 c -26.255 -4.947 -53.138 -4.734 -80.572 0 V 74.189 z"
|
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(64,89,107); fill-rule: nonzero; opacity: 1;"
|
|
transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
<path
|
|
d="M 88.056 25.776 H 11.372 c -1.074 0 -1.944 0.871 -1.944 1.945 v 7.719 c 26.857 6.175 53.715 6.175 80.572 0 v -7.719 C 90 26.647 89.129 25.776 88.056 25.776 z"
|
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(64,89,107); fill-rule: nonzero; opacity: 1;"
|
|
transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
<rect x="9.43" y="35.44" rx="0" ry="0" width="80.57" height="14.29"
|
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(242,242,242); fill-rule: nonzero; opacity: 1;"
|
|
transform=" matrix(1 0 0 1 0 0) " />
|
|
<path
|
|
d="M 51.045 60.484 H 19.469 c -0.552 0 -1 -0.447 -1 -1 s 0.448 -1 1 -1 h 31.576 c 0.553 0 1 0.447 1 1 S 51.598 60.484 51.045 60.484 z"
|
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(242,242,242); fill-rule: nonzero; opacity: 1;"
|
|
transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
<path
|
|
d="M 37.707 68.001 H 19.469 c -0.552 0 -1 -0.447 -1 -1 s 0.448 -1 1 -1 h 18.238 c 0.552 0 1 0.447 1 1 S 38.259 68.001 37.707 68.001 z"
|
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(242,242,242); fill-rule: nonzero; opacity: 1;"
|
|
transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
<path
|
|
d="M 51.045 68.001 h -8.574 c -0.552 0 -1 -0.447 -1 -1 s 0.448 -1 1 -1 h 8.574 c 0.553 0 1 0.447 1 1 S 51.598 68.001 51.045 68.001 z"
|
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(242,242,242); fill-rule: nonzero; opacity: 1;"
|
|
transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
<path
|
|
d="M 81.153 58.484 H 65.638 c -0.553 0 -1 0.447 -1 1 v 7.517 c 0 0.553 0.447 1 1 1 h 15.516 c 0.553 0 1 -0.447 1 -1 v -7.517 C 82.153 58.932 81.706 58.484 81.153 58.484 z"
|
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(242,242,242); fill-rule: nonzero; opacity: 1;"
|
|
transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" />
|
|
</g>
|
|
</svg>
|
|
</VCol> -->
|
|
</VRow>
|
|
<div class="text-center mb-2 mt-2">
|
|
<VBtn type="submit" class="px-4 mt-4 mb-2" color="primary" variant="flat"
|
|
@click="validatePayment" style="background-color: rgb(var(--v-theme-yellow)) !important;"
|
|
block>
|
|
Confirm</VBtn>
|
|
<VBtn class="px-4" color="grey" variant="flat" @click="backFun" :class="isMobile ? '' : 'mr-2'"
|
|
block>
|
|
Back</VBtn>
|
|
|
|
</div>
|
|
</VForm>
|
|
</VCard>
|
|
</div>
|
|
<!-- </VContainer> -->
|
|
</div>
|
|
|
|
</template>
|
|
<style lang="scss">
|
|
.logo-img {
|
|
display: block;
|
|
position: relative;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.card-title {
|
|
font-family: "Public Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
|
}
|
|
|
|
.v-list-item-title {
|
|
white-space: inherit !important;
|
|
;
|
|
}
|
|
|
|
.v-list {
|
|
min-height: 176px;
|
|
}
|
|
|
|
.no-border {
|
|
border: none !important;
|
|
}
|
|
|
|
td {
|
|
border: none !important;
|
|
}
|
|
|
|
th {
|
|
border: none !important;
|
|
}
|
|
|
|
.cut-text {
|
|
white-space: nowrap;
|
|
/* Prevents text from wrapping */
|
|
overflow: hidden;
|
|
/* Hides any content that overflows the container */
|
|
text-overflow: ellipsis;
|
|
/* Displays an ellipsis (...) to represent the clipped text */
|
|
// width: 100px;
|
|
text-decoration: line-through;
|
|
text-decoration-color: red;
|
|
/* Set the color of the line */
|
|
text-decoration-thickness: 1px;
|
|
/* Adjust the width as needed */
|
|
}
|
|
</style>../store1.js
|