PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.20
Booking for Appointments and Events Calendar – Amelia v1.2.20
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 / Congratulations / Congratulations.vue
ameliabooking / v3 / src / views / public / StepForm / Congratulations Last commit date
parts 2 years ago AddToCalendar.vue 2 years ago Congratulations.vue 1 year ago
Congratulations.vue
387 lines
1 <template>
2 <div
3 v-if="ready && booked && !loading"
4 :style="cssVars"
5 class="am-fs__main-content am-fs__congrats"
6 :class="[{'am-fs-sb-atc' : checkScreen}, props.globalClass]"
7 >
8 <div class="am-fs__congrats-main">
9 <img :src="baseUrls.wpAmeliaPluginURL+'/v3/src/assets/img/congratulations/congratulations.svg'">
10 <p class="am-fs__congrats-main-heading">
11 {{ amLabels.congratulations }}
12 </p>
13 <span v-if="booked && booked.data.length && bookedType === 'appointment'">{{amLabels.appointment_id}} #{{ booked.data[0].appointmentId }}</span>
14
15 <AddToCalendar v-if="checkScreen" class="am-fs__congrats-main-atc"></AddToCalendar>
16 </div>
17
18 <div
19 class="am-fs__congrats-info"
20 :class="[
21 {'am-fs__congrats-info-mobile' : checkScreen},
22 {'am-fs__congrats-info-mobile-s' : mobileS},
23 ]"
24 >
25 <div class="am-fs__congrats-info-customer">
26 <component :is="componentTypes[bookedType]"></component>
27 <div v-if="booked.price > 0 || (booked.price <= 0 && coupon.code)" class="am-fs__congrats-info-payment">
28 <span v-if="booked && booked.paymentAmount && getPayment(booked.payments).gateway === 'onSite'">
29 {{ amLabels.congrats_total_amount }}:
30 </span>
31 <span v-else>{{ amLabels.congrats_payment }}:</span>
32 <span v-if="booked && booked.paymentAmount && getPayment(booked.payments).gateway">
33 {{ `${useFormattedPrice(booked.paymentAmount)} - ${ getPayment(booked.payments).gatewayTitle ? getPayment(booked.payments).gatewayTitle : getPaymentGatewayNiceName( getPayment(booked.payments))}` }}
34 </span>
35 <span v-else-if="booked">
36 {{ ( getPayment(booked.payments).gateway !== 'onSite' ? useFormattedPrice(booked.paymentAmount) : useFormattedPrice(booked.price < 0 ? 0 : booked.price) ) + ( getPayment(booked.payments).status !== 'paid' ? (' - ' + amLabels.on_site) : '') }}
37 </span>
38 <span v-else></span>
39 </div>
40 <div class="am-fs__congrats-info-customer-border am-fs__congrats-info-customer-name">
41 <span>{{ amLabels.your_name_colon }}:</span>
42 <span>{{ customer.firstName + ' ' + customer.lastName }}</span>
43 </div>
44 <div v-if="customer.email" class="am-fs__congrats-info-customer-email">
45 <span>{{ amLabels.email_address_colon }}:</span>
46 <span>{{ customer.email }}</span>
47 </div>
48 <div v-if="customer.phone" class="am-fs__congrats-info-customer-phone">
49 <span>{{ amLabels.phone_number_colon }}:</span>
50 <span>{{ customer.phone }}</span>
51 </div>
52 </div>
53 </div>
54 </div>
55
56 <!-- Skeleton -->
57 <el-skeleton v-else animated class="am-skeleton-congratz">
58 <template #template>
59 <div class="am-skeleton-congratz-heading">
60 <el-skeleton-item variant="circle" />
61 <el-skeleton-item variant="h3" />
62 <el-skeleton-item variant="text" />
63 </div>
64 <div class="am-skeleton-congratz-booking-info">
65 <div v-for="(item, i) in new Array(10)" :key="item" :class="{'am-customer-info': (i === 6)}">
66 <el-skeleton-item variant="text" :style="{width: `${useRandomIntFromInterval(14, 36)}%`}"/>
67 <el-skeleton-item variant="text" :style="{width: `${useRandomIntFromInterval(14, 36)}%`}"/>
68 </div>
69 </div>
70 </template>
71 </el-skeleton>
72 <!-- /Skeleton -->
73 </template>
74
75 <script setup>
76 import AddToCalendar from './AddToCalendar'
77 import CartInfoService from './parts/CartInfoService'
78 import AppointmentInfoService from './parts/AppointmentInfoService'
79 import PackageInfoService from './parts/PackageInfoService'
80 import { computed, inject, provide, markRaw, watchEffect, onMounted } from 'vue'
81 import { useColorTransparency } from '../../../../assets/js/common/colorManipulation'
82 import { useRandomIntFromInterval, useFormattedPrice } from '../../../../assets/js/common/formatting'
83 import { useStore } from 'vuex'
84 import { useCart } from '../../../../assets/js/public/cart'
85 import { useRenderAction } from "../../../../assets/js/public/renderActions";
86
87 let props = defineProps({
88 globalClass: {
89 type: String,
90 default: ''
91 }
92 })
93
94 // * Root Settings
95 const amSettings = inject('settings')
96
97 const store = useStore()
98
99 // * Labels
100 const amLabels = inject('amLabels')
101
102 /**************
103 * Computed *
104 *************/
105
106 let ready = computed(() => store.getters['entities/getReady'])
107
108 let booked = computed(() => store.getters['booking/getBooked'])
109
110 provide('booked', booked)
111
112 let bookedType = computed(() => {
113 return useCart(store).filter(i => i.serviceId && i.serviceId in i.services).length > 1 ? 'cart' : booked.value.type
114 })
115
116 // * Coupon
117 let coupon = computed(() => store.getters['booking/getCoupon'])
118
119 let loading = computed(() => store.getters['booking/getLoading'])
120
121 let customer = computed(() => {
122 return {
123 firstName: store.getters['booking/getCustomerFirstName'],
124 lastName: store.getters['booking/getCustomerLastName'],
125 email: store.getters['booking/getCustomerEmail'],
126 phone: store.getters['booking/getCustomerPhone'],
127 }
128 })
129
130 /**************
131 * Navigation *
132 *************/
133
134 const { footerButtonClicked } = inject('changingStepsFunctions', {
135 footerButtonClicked: {
136 value: false
137 }
138 })
139
140 function getPayment (payments) {
141 let onlinePayments = payments.filter(i => i.gateway !== 'onSite')
142
143 return onlinePayments.length ? onlinePayments[0] : payments[0]
144 }
145
146 function getPaymentGatewayNiceName (payment) {
147 if (payment.gateway === 'onSite') {
148 return amLabels.value['on_site']
149 }
150
151 if (payment.gateway === 'wc') {
152 return payment.gatewayTitle
153 }
154
155 if (payment.gateway) {
156 return payment.gateway.charAt(0).toUpperCase() + payment.gateway.slice(1)
157 }
158 }
159
160 // * Watching when footer button was clicked
161 watchEffect(() => {
162 if (footerButtonClicked.value) {
163 finish()
164 }
165 })
166
167 const componentTypes = {
168 cart: markRaw(CartInfoService),
169 appointment: markRaw(AppointmentInfoService),
170 package: markRaw(PackageInfoService),
171 }
172
173 const globalSettings = inject('settings')
174 const baseUrls = inject('baseUrls')
175
176 let cWidth = inject('containerWidth', 0)
177 let checkScreen = computed(() => cWidth.value < 540)
178 let mobileS = computed(() => cWidth.value < 340)
179
180 function finish () {
181 let entity = store.getters['entities/getBookableFromBookableEntities'](
182 store.getters['booking/getSelection']
183 )
184
185 let entitySettings = entity.settings ? JSON.parse(entity.settings) : globalSettings
186
187 if ('general' in entitySettings && 'redirectUrlAfterAppointment' in entitySettings.general && entitySettings.general.redirectUrlAfterAppointment) {
188 window.location.href = entitySettings.general.redirectUrlAfterAppointment
189 } else if (globalSettings.general.redirectUrlAfterAppointment) {
190 window.location.href = globalSettings.general.redirectUrlAfterAppointment
191 } else {
192 window.location.reload()
193 }
194 }
195
196
197 let amColors = inject('amColors')
198
199 const cssVars = computed(() => {
200 if (checkScreen.value) {
201 return {
202 '--am-c-atc-text-op40': useColorTransparency(amColors.value.colorMainText, 0.4),
203 '--am-c-atc-heading-text-op40': useColorTransparency(amColors.value.colorSbText, 0.4),
204 '--am-c-atc-text-op30': useColorTransparency(amColors.value.colorMainText, 0.3),
205 '--am-c-atc-text': amColors.value.colorMainText,
206 '--am-c-atc-heading-text': amColors.value.colorSbText,
207 '--am-c-atc-bgr-coverage': booked.value.type === 'package' && !(amSettings.general.addToCalendar && booked.value && booked.value.data.length) ? '50%' : '80%'
208 }
209 } else {
210 return {
211 '--am-c-atc-text-op40': useColorTransparency(amColors.value.colorMainText, 0.4),
212 '--am-c-atc-heading-text-op40': useColorTransparency(amColors.value.colorMainHeadingText, 0.4),
213 '--am-c-atc-text-op30': useColorTransparency(amColors.value.colorMainText, 0.3),
214 '--am-c-atc-text': amColors.value.colorMainText,
215 '--am-c-atc-heading-text': amColors.value.colorMainHeadingText
216 }
217 }
218 })
219
220 onMounted(() => {
221 useRenderAction('congratulationsLoaded')
222 })
223 </script>
224
225 <script>
226 export default {
227 name: 'CongratulationsStep',
228 key: 'congratulations',
229 sidebarData: {
230 label: 'congratulations',
231 icon: 'pennant',
232 selected: true,
233 finished: true
234 }
235 }
236
237 </script>
238
239 <style lang="scss">
240 .amelia-v2-booking #amelia-container {
241 .am-fs__main-content.am-fs__congrats {
242 padding: 16px 16px 16px;
243 height: calc(100% - 56px);
244 margin-top:0
245 }
246
247 .am-fs-sb-atc {
248 --am-c-sb-bgr-atc: var(--am-c-sb-bgr);
249 background-image: linear-gradient(var(--am-c-sb-bgr-atc) var(--am-c-atc-bgr-coverage), transparent 20%);
250 }
251
252 .am-fs__congrats {
253 &-main {
254 margin-top: 22px;
255 display: flex;
256 flex-direction: column;
257 align-items: center;
258 font-family: var(--am-font-family);
259 margin-bottom: 16px;
260
261 & > * {
262 $count: 5;
263 @for $i from 0 through $count {
264 &:nth-child(#{$i + 1}) {
265 animation: 600ms cubic-bezier(.45,1,.4,1.2) #{$i*100}ms am-animation-slide-up;
266 animation-fill-mode: both;
267 }
268 }
269 }
270
271 & img {
272 width:54px;
273 margin-bottom: 8px;
274 }
275 &-heading {
276 margin-bottom: 2px;
277 font-weight: 500;
278 font-size: 18px;
279 line-height: 28px;
280 color: var(--am-c-atc-heading-text);
281 }
282 &-atc {
283 margin-top: 16px
284 }
285 & span {
286 color: var(--am-c-atc-heading-text-op40);
287 font-weight: 400;
288 font-size: 13px;
289 line-height: 18px;
290 }
291 }
292 &-info-mobile {
293 padding: 16px;
294 margin-top: 24px;
295 border-radius: 6px;
296 box-shadow: 0 2px 3px 2px rgba(26, 44, 55, 0.1);
297 }
298 &-info {
299 --am-c-atc-main-bgr: var(--am-c-main-bgr);
300 background-color: var(--am-c-atc-main-bgr);
301 &-customer {
302 &-border {
303 border-top: 1px solid var(--am-c-atc-text-op30);
304 padding-top: 16px;
305 }
306
307 & > div {
308 $count: 20;
309 @for $i from 0 through $count {
310 &:nth-child(#{$i + 1}) {
311 animation: 600ms cubic-bezier(.45,1,.4,1.2) #{$i*100}ms am-animation-slide-up;
312 animation-fill-mode: both;
313 }
314 }
315 }
316
317 & div {
318 display: flex;
319 justify-content: space-between;
320 font-weight: 400;
321 font-size: 14px;
322 margin-bottom: 12px;
323 line-height: 20px;
324 & span {
325 color: var(--am-c-atc-text-op40);
326 }
327 & span:nth-child(2) {
328 color: var(--am-c-atc-text);
329 }
330 }
331 }
332 }
333
334 &-info-mobile-s {
335 .am-fs__congrats-info-customer > div {
336 flex-direction: column;
337 }
338 }
339 }
340
341 .am-skeleton-congratz {
342
343 &-heading {
344 display: flex;
345 flex-direction: column;
346 align-items: center;
347 margin-bottom: 13px;
348
349 :first-child {
350 width: 52px;
351 height: 52px;
352 margin-bottom: 9px;
353 }
354
355 :nth-child(2) {
356 height: 28px;
357 max-width: 132px;
358 margin-bottom: 4px;
359 }
360
361 :last-child {
362 max-width: 148px;
363 height: 18px;
364 }
365 }
366
367 &-booking-info {
368 & > div {
369 display: flex;
370 justify-content: space-between;
371 margin-bottom: 12px;
372
373 .el-skeleton__item {
374 height: 20px;
375 }
376
377 }
378
379 .am-customer-info {
380 border-bottom: 1px solid var(--am-c-skeleton-op20);
381 padding-bottom: 12px;
382 }
383 }
384 }
385 }
386 </style>
387