PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.4
Booking for Appointments and Events Calendar – Amelia v2.4.4
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 / EventForm / Common / EventCustomerInfo / EventCustomerInfo.vue
ameliabooking / v3 / src / views / public / EventForm / Common / EventCustomerInfo Last commit date
EventCustomerInfo.vue 6 days ago
EventCustomerInfo.vue
1001 lines
1 <template>
2 <div ref="infoFormWrapperRef" class="am-elfci" :class="props.globalClass">
3 <div v-show="!loading">
4 <div
5 v-if="(paymentError && instantBooking) || (paymentError && isWaitingAvailable)"
6 class="am-elfci__error"
7 >
8 <AmAlert type="error" :title="paymentError" :show-icon="true" :closable="false"> </AmAlert>
9 </div>
10
11 <div v-if="authError" class="am-elfci__error">
12 <AmAlert type="error" :title="authErrorMessage" :show-icon="true" :closable="true">
13 </AmAlert>
14 </div>
15
16 <!-- Social Buttons -->
17 <div
18 v-if="
19 (settings.socialLogin.googleLoginEnabled &&
20 settings.general.googleClientId &&
21 !store.getters['customerInfo/getLoggedUser']) ||
22 (settings.socialLogin.facebookLoginEnabled &&
23 settings.socialLogin.facebookCredentialsEnabled &&
24 !store.getters['customerInfo/getLoggedUser'])
25 "
26 >
27 <div class="am-elfci__social-wrapper">
28 <div class="am-elfci__social-wrapper__label">
29 {{ amLabels.auto_fill_your_details }}
30 </div>
31 <am-social-button :provider="socialProvider" @social-action="onSignupSocial" />
32 </div>
33
34 <!-- Social Divider -->
35 <div class="am-elfci__social-divider">
36 <span class="par-sm">{{ amLabels.or_enter_details_below }}</span>
37 </div>
38 <!-- /Social Divider -->
39 </div>
40 <!-- /Social Buttons -->
41
42 <el-form
43 ref="infoFormRef"
44 :model="infoFormData"
45 :rules="infoFormRules"
46 label-position="top"
47 class="am-elfci__form"
48 :class="responsiveClass"
49 >
50 <template v-for="item in customizedOrder" :key="item.id">
51 <component
52 :is="infoFormConstruction[item.id].template"
53 v-if="
54 item.id in customizedOptions && 'visibility' in customizedOptions[item.id]
55 ? customizedOptions[item.id].visibility
56 : true
57 "
58 ref="customerCollectorRef"
59 v-model="infoFormData[item.id]"
60 v-model:countryCode="infoFormConstruction[item.id].countryCode"
61 v-bind="infoFormConstruction[item.id].props"
62 v-on="
63 'handlers' in infoFormConstruction[item.id]
64 ? infoFormConstruction[item.id].handlers
65 : {}
66 "
67 ></component>
68 </template>
69
70 <el-form-item
71 v-if="
72 amSettings.featuresIntegrations.mailchimp.enabled &&
73 amSettings.mailchimp.subscribeFieldVisible &&
74 customizedOptions.email.visibility
75 "
76 class="am-elfci__item am-subscribe"
77 >
78 <AmCheckbox v-model="subscribeToMailchimp" :label="amLabels.subscribe_to_mailing_list">
79 </AmCheckbox>
80 </el-form-item>
81
82 <!-- Custom Fields -->
83 <template v-for="(item, index) in eventCustomFieldsArray" :key="index">
84 <component
85 :is="infoFormConstruction[`cf${item.id}`].template"
86 v-if="checkCustomerCustomFieldVisibility(item)"
87 ref="customFieldsCollectorRefs"
88 v-model="infoFormData[`cf${item.id}`]"
89 v-bind="infoFormConstruction[`cf${item.id}`].props"
90 @address-selected="(address) => addressSelected(address, item.id)"
91 ></component>
92 </template>
93 </el-form>
94 </div>
95
96 <div v-show="!loading">
97 <PaymentOnSite
98 v-if="
99 isWaitingAvailable ||
100 (instantBooking &&
101 (amSettings.payments.wc.enabled
102 ? amSettings.payments.wc.onSiteIfFree || !wcEventEnabled
103 : true))
104 "
105 ref="refOnSiteBooking"
106 :instant-booking="instantBooking"
107 @payment-error="callPaymentError"
108 />
109
110 <PaymentWc
111 v-if="
112 instantBooking &&
113 amSettings.payments.wc.enabled &&
114 !amSettings.payments.wc.onSiteIfFree &&
115 wcEventEnabled
116 "
117 ref="refWcBooking"
118 :instant-booking="instantBooking"
119 @payment-error="callPaymentError"
120 />
121 </div>
122
123 <CustomerInfoSkeleton />
124 </div>
125 </template>
126
127 <script setup>
128 // * Dedicated parts
129 import PaymentOnSite from '../../../Parts/Payment/Methods/PaymentOnSite.vue'
130 import PaymentWc from '../../../Parts/Payment/Methods/PaymentWc.vue'
131 import CustomerInfoSkeleton from '../../../Parts/Skeletons/CustomerInfoSkeleton.vue'
132
133 // * Import from Vue
134 import { ref, reactive, computed, inject, onMounted, nextTick, watchEffect, watch } from 'vue'
135 import VueAuthenticate from 'vue-authenticate'
136
137 // * Form Fields Templates
138 import { formFieldsTemplates } from '../../../../../assets/js/common/formFieldsTemplates.js'
139
140 // * Import from Vuex
141 import { useStore } from 'vuex'
142
143 // * Composables
144 import { useScrollTo } from '../../../../../assets/js/common/scrollElements.js'
145 import { useResponsiveClass } from '../../../../../assets/js/common/responsive.js'
146 import { usePrepaidPrice } from '../../../../../assets/js/common/appointments'
147
148 // * _components
149 import AmAlert from '../../../../_components/alert/AmAlert.vue'
150 import useAction from '../../../../../assets/js/public/actions'
151 import { settings } from '../../../../../plugins/settings'
152 import httpClient from '../../../../../plugins/axios'
153 import AmSocialButton from '../../../../common/FormFields/AmSocialButton.vue'
154 import { SocialAuthOptions } from '../../../../../assets/js/admin/socialAuthOptions'
155 import AmCheckbox from '../../../../_components/checkbox/AmCheckbox.vue'
156 import { mapAddressComponentsForXML } from '../../../../../assets/js/common/helper'
157 import { useIvyMapping } from '../../../../../assets/js/public/ivy'
158 import { getInternationalPhoneValue } from '../../../../../assets/js/common/phone'
159
160 let props = defineProps({
161 globalClass: {
162 type: String,
163 default: '',
164 },
165 inDialog: {
166 type: Boolean,
167 default: false,
168 },
169 })
170
171 // * Store
172 const store = useStore()
173
174 // get customer data
175 store.dispatch('customerInfo/requestCurrentUserData')
176 // filter custom fields
177 store.dispatch('customFields/filterEventCustomFields')
178
179 const shortcodeData = inject('shortcodeData')
180
181 watch(
182 () => store.getters['customerInfo/getLoggedUser'],
183 (newValue, oldValue) => {
184 if (newValue) {
185 let customer = store.getters['customerInfo/getCustomer']
186
187 store.commit('customFields/populateCustomerCustomFields', customer)
188
189 if (customer.customFields.includes('datepicker')) {
190 refreshDatePickerValue.value = true
191 }
192 }
193 },
194 )
195
196 // * Loading State
197 let loading = computed(() => store.getters['getLoading'])
198
199 // * Root Settings
200 const amSettings = inject('settings')
201
202 // * Event form customization
203 let customizedDataForm = inject('customizedDataForm')
204
205 // * Customization options
206 let customizedOptions = computed(() => {
207 return customizedDataForm.value.customerInfo.options
208 })
209
210 // * Customized fields order
211 let customizedOrder = computed(() => {
212 return customizedDataForm.value.customerInfo.order
213 })
214
215 // * Labels
216 let labels = inject('labels')
217
218 // * local language short code
219 const localLanguage = inject('localLanguage')
220
221 // * if local lang is in settings lang
222 let langDetection = computed(() => amSettings.general.usedLanguages.includes(localLanguage.value))
223
224 // * Computed labels
225 let amLabels = computed(() => {
226 let computedLabels = reactive({ ...labels })
227
228 if (customizedDataForm.value.customerInfo.translations) {
229 let customizedLabels = customizedDataForm.value.customerInfo.translations
230 Object.keys(customizedLabels).forEach((labelKey) => {
231 if (customizedLabels[labelKey][localLanguage.value] && langDetection.value) {
232 computedLabels[labelKey] = customizedLabels[labelKey][localLanguage.value]
233 } else if (customizedLabels[labelKey].default) {
234 computedLabels[labelKey] = customizedLabels[labelKey].default
235 }
236 })
237 }
238 return computedLabels
239 })
240
241 // * Step functionality
242 let { nextStep, footerButtonClicked, footerButtonReset } = inject('changingStepsFunctions', {
243 nextStep: () => {},
244 footerButtonReset: () => {},
245 footerButtonClicked: {
246 value: false,
247 },
248 })
249
250 let selectedEvent = computed(() =>
251 store.getters['eventEntities/getEvent'](store.getters['eventBooking/getSelectedEventId']),
252 )
253
254 // * Custom Fields Array
255 let eventCustomFieldsArray = computed(
256 () => store.getters['customFields/getFilteredCustomFieldsArray'],
257 )
258
259 // * Event Custom Fields
260 let customFields = computed(() => store.getters['customFields/getCustomFields'])
261
262 // * Event fluid step keys
263 let eventFluidStepKey = inject('eventFluidStepKey')
264
265 // * Payment recognition
266 let refOnSiteBooking = ref(null)
267
268 let refWcBooking = ref(null)
269
270 let instantBooking = ref(usePrepaidPrice(store) === 0)
271
272 let isWaitingAvailable = computed(() => store.getters['eventWaitingListOptions/getAvailability'])
273
274 /**
275 * Form Block start
276 */
277 // * Step reference
278 let infoFormWrapperRef = ref(null)
279
280 // * Form reference
281 let infoFormRef = ref(null)
282
283 // * Customer refs
284 let customerCollectorRef = ref([])
285
286 // * Custom fields refs
287 let customFieldsCollectorRefs = ref([])
288
289 // * All form fields refs
290 let allFieldsRefs = ref([])
291
292 // * InitInfoStep hook - custom fields placeholder
293 let refCFPlaceholders = ref({})
294
295 // * InitInfoStep hook - adding coupon
296 let couponCode = ref('')
297
298 // * Form field date picker needs refresh
299 let refreshDatePickerValue = ref(false)
300
301 let phoneError = ref(false)
302 let isPhoneValid = ref(false)
303 let refreshPhoneComponent = ref(0)
304
305 // * Form data
306 let infoFormData = ref({
307 firstName: computed({
308 get: () => store.getters['customerInfo/getCustomerFirstName'],
309 set: (val) => {
310 store.commit('customerInfo/setCustomerFirstName', val ? val : '')
311 },
312 }),
313 lastName: computed({
314 get: () => store.getters['customerInfo/getCustomerLastName'],
315 set: (val) => {
316 store.commit('customerInfo/setCustomerLastName', val ? val : '')
317 },
318 }),
319 email: computed({
320 get: () => store.getters['customerInfo/getCustomerEmail'],
321 set: (val) => {
322 store.commit('customerInfo/setCustomerEmail', val ? val : '')
323 },
324 }),
325 phone: computed({
326 get: () => store.getters['customerInfo/getCustomerPhone'],
327 set: (val) => {
328 store.commit('customerInfo/setCustomerPhone', val ? val : '')
329 },
330 }),
331 })
332
333 // * Form construction
334 let infoFormConstruction = ref({
335 firstName: {
336 template: formFieldsTemplates.text,
337 props: {
338 itemName: 'firstName',
339 label: amLabels.value.first_name_colon,
340 placeholder: amLabels.value.enter_first_name,
341 class: 'am-elfci__item',
342 },
343 },
344 lastName: {
345 template: formFieldsTemplates.text,
346 props: {
347 itemName: 'lastName',
348 label: amLabels.value.last_name_colon,
349 placeholder: amLabels.value.enter_last_name,
350 class: 'am-elfci__item',
351 },
352 },
353 email: {
354 template: formFieldsTemplates.text,
355 props: {
356 itemName: 'email',
357 label: amLabels.value.email_colon,
358 placeholder: amLabels.value.enter_email,
359 class: 'am-elfci__item',
360 },
361 },
362 phone: {
363 countryCode: computed({
364 get: () => {
365 const iso = store.getters['customerInfo/getCustomerCountryPhoneIso']
366 return iso ? iso.toUpperCase() : ''
367 },
368 set: (val) => {
369 store.commit('customerInfo/setCustomerCountryPhoneIso', val ? val.toLowerCase() : '')
370 },
371 }),
372 template: formFieldsTemplates.phone,
373 props: {
374 itemName: 'phone',
375 label: amLabels.value.phone_colon,
376 placeholder: amLabels.value.enter_phone,
377 phoneError: computed(() => phoneError.value && !isPhoneValid.value),
378 errorMessage: computed(() =>
379 phoneError.value && !isPhoneValid.value && infoFormData.value.phone
380 ? amLabels.value.enter_valid_phone_warning
381 : '',
382 ),
383 whatsAppLabel: amLabels.value.whatsapp_opt_in_text,
384 isWhatsApp: computed(
385 () =>
386 amSettings.notifications.whatsAppEnabled && !(phoneError.value && !isPhoneValid.value),
387 ),
388 class: 'am-elfci__item',
389 noResultsLabel: amLabels.value.no_results_found,
390 refreshTrigger: computed(() => refreshPhoneComponent.value),
391 },
392 handlers: {
393 handlePhoneData: (phoneData) => {
394 if (
395 phoneData &&
396 !phoneData.countryCode &&
397 !store.getters['customerInfo/getCustomerCountryPhoneIso'] &&
398 amSettings.general.phoneDefaultCountryCode !== 'auto'
399 ) {
400 store.commit(
401 'customerInfo/setCustomerCountryPhoneIso',
402 amSettings.general.phoneDefaultCountryCode.toLowerCase(),
403 )
404 }
405
406 const countryCode = (
407 phoneData?.countryCode ||
408 store.getters['customerInfo/getCustomerCountryPhoneIso'] ||
409 ''
410 ).toUpperCase()
411
412 store.commit(
413 'customerInfo/setCustomerPhone',
414 getInternationalPhoneValue(phoneData?.phoneNumber ?? phoneData?.e164, phoneData, countryCode)
415 )
416
417 isPhoneValid.value = !!phoneData.isValid
418 },
419 },
420 },
421 })
422
423 // * Form validation rules
424 let infoFormRules = ref({
425 firstName: [
426 {
427 required: true,
428 message: amLabels.value.enter_first_name_warning,
429 trigger: 'submit',
430 },
431 ],
432 lastName: [
433 {
434 required: customizedOptions.value.lastName.required,
435 message: amLabels.value.enter_last_name_warning,
436 trigger: 'submit',
437 },
438 ],
439 email: [
440 {
441 required: customizedOptions.value.email.required,
442 type: 'email',
443 message: amLabels.value.enter_valid_email_warning,
444 trigger: 'submit',
445 },
446 ],
447 phone: [
448 {
449 required: customizedOptions.value.phone.required,
450 message: amLabels.value.enter_phone_warning,
451 trigger: ['blur', 'submit'],
452 },
453 ],
454 })
455
456 let subscribeToMailchimp = computed({
457 get: () => store.getters['customerInfo/getCustomerSubscribe'],
458 set: (val) => {
459 store.commit('customerInfo/setCustomerSubscribe', val)
460 },
461 })
462
463 Object.keys(customFields.value).forEach((fieldKey) => {
464 // * Form Model
465 infoFormData.value[fieldKey] = computed({
466 get: () => store.getters['customFields/getCustomFieldValue'](fieldKey),
467 set: (val) => {
468 let obj = {
469 key: fieldKey,
470 value: val,
471 }
472 store.commit('customFields/setCustomFieldValue', obj)
473 },
474 })
475
476 // * Form Rules
477 infoFormRules.value[fieldKey] = [
478 {
479 message: amLabels.value.required_field,
480 required: customFields.value[fieldKey].required,
481 trigger: 'submit',
482 },
483 ]
484
485 // * Form Construction
486 infoFormConstruction.value[fieldKey] = {
487 template: formFieldsTemplates[customFields.value[fieldKey].type],
488 props: {
489 id: 'am-cf-' + customFields.value[fieldKey].id,
490 itemName: fieldKey,
491 label: customFields.value[fieldKey].label,
492 options: customFields.value[fieldKey].options,
493 class: `am-elfci__item am-cf-width-${customFields.value[fieldKey].width}`,
494 },
495 }
496
497 if (
498 customFields.value[fieldKey].type === 'checkbox' ||
499 customFields.value[fieldKey].type === 'radio'
500 ) {
501 infoFormConstruction.value[fieldKey].props.options = infoFormConstruction.value[
502 fieldKey
503 ].props.options.map((option) => {
504 return {
505 ...option,
506 value: option.label,
507 }
508 })
509 }
510
511 if (customFields.value[fieldKey].type === 'text-area') {
512 infoFormConstruction.value[fieldKey].props = {
513 ...infoFormConstruction.value[fieldKey].props,
514 ...{ itemType: 'textarea' },
515 }
516 }
517
518 if (customFields.value[fieldKey].type === 'file') {
519 infoFormConstruction.value[fieldKey].props = {
520 ...infoFormConstruction.value[fieldKey].props,
521 ...{ btnLabel: amLabels.value.upload_file_here },
522 }
523 }
524
525 if (customFields.value[fieldKey].type === 'datepicker') {
526 infoFormConstruction.value[fieldKey].props = {
527 ...infoFormConstruction.value[fieldKey].props,
528 ...{ weekStartsFromDay: amSettings.wordpress.startOfWeek },
529 refreshValue: refreshDatePickerValue,
530 }
531 }
532 })
533
534 let wcEventEnabled = ref(false)
535
536 onMounted(() => {
537 let eventPayments =
538 selectedEvent && selectedEvent.value.settings
539 ? JSON.parse(selectedEvent.value.settings)['payments']
540 : null
541
542 wcEventEnabled.value =
543 eventPayments && 'wc' in eventPayments
544 ? !('enabled' in eventPayments.wc) || eventPayments.wc.enabled
545 : settings.payments.wc.enabled
546
547 if (isWaitingAvailable.value) {
548 if (eventFluidStepKey.value.indexOf('eventPayment') !== -1) {
549 let index = eventFluidStepKey.value.indexOf('eventPayment')
550 if (index > 0) {
551 eventFluidStepKey.value.splice(index, 1)
552 }
553 }
554 } else {
555 // * remove payment step
556 if (instantBooking.value && eventFluidStepKey.value.indexOf('eventPayment') !== -1) {
557 let index = eventFluidStepKey.value.indexOf('eventPayment')
558 if (index > 0) {
559 eventFluidStepKey.value.splice(index, 1)
560 }
561 }
562
563 // * add payment step
564 if (!instantBooking.value && eventFluidStepKey.value.indexOf('eventPayment') < 0) {
565 eventFluidStepKey.value.push('eventPayment')
566 }
567 }
568
569 nextTick(() => {
570 setTimeout(() => {
571 customerCollectorRef.value.forEach((el) => {
572 if (el.formFieldRef) {
573 allFieldsRefs.value.push(el.formFieldRef)
574 }
575 })
576
577 customFieldsCollectorRefs.value.forEach((el) => {
578 if (el.formFieldRef) {
579 allFieldsRefs.value.push(el.formFieldRef)
580 }
581 })
582 }, 500)
583 })
584
585 Object.keys(customFields.value).forEach((fieldKey) => {
586 // * Placeholder implementation for custom input and textarea
587 if (
588 customFields.value[fieldKey].type === 'text' ||
589 customFields.value[fieldKey].type === 'text-area'
590 ) {
591 refCFPlaceholders.value[fieldKey] = { placeholder: '' }
592 }
593 })
594
595 useAction(
596 store,
597 { customFields, customFieldsPlaceholders: refCFPlaceholders, couponCode },
598 'InitInfoStep',
599 'event',
600 null,
601 null,
602 )
603
604 if (couponCode.value) {
605 store.commit('coupon/setCode', couponCode.value)
606 }
607
608 if (Object.values(refCFPlaceholders.value).filter((cf) => cf.placeholder !== '').length) {
609 Object.keys(refCFPlaceholders.value).forEach((fieldKey) => {
610 infoFormConstruction.value[fieldKey].props = {
611 ...infoFormConstruction.value[fieldKey].props,
612 placeholder: refCFPlaceholders.value[fieldKey].placeholder,
613 }
614 })
615 }
616
617 if (useIvyMapping(store, shortcodeData, infoFormData)) {
618 refreshPhoneComponent.value++
619 }
620 })
621
622 // * Submit Form
623 function submitForm() {
624 // store.commit('setLoading', true)
625 footerButtonReset()
626
627 // Trim inputs
628 infoFormData.value.firstName = infoFormData.value.firstName.trim()
629 infoFormData.value.lastName = infoFormData.value.lastName.trim()
630 infoFormData.value.email = infoFormData.value.email.trim()
631
632 useAction(store, { rules: infoFormRules.value }, 'customValidation', 'event', null, null)
633
634 infoFormRef.value.validate((valid) => {
635 if (valid && (customizedOptions.value.phone.required ? isPhoneValid.value : true)) {
636 phoneError.value = false
637 if (isWaitingAvailable.value) {
638 store.commit('payment/setPaymentGateway', 'onSite')
639
640 refOnSiteBooking.value.continueWithBooking()
641 } else {
642 if (!instantBooking.value) {
643 nextStep()
644 } else {
645 if (
646 amSettings.payments.wc.enabled &&
647 !amSettings.payments.wc.onSiteIfFree &&
648 wcEventEnabled.value
649 ) {
650 store.commit('payment/setPaymentGateway', 'wc')
651
652 refWcBooking.value.continueWithBooking()
653 } else {
654 store.commit('payment/setPaymentGateway', 'onSite')
655
656 refOnSiteBooking.value.continueWithBooking()
657 }
658 }
659 }
660 } else {
661 // store.commit('setLoading', false)
662 let fieldElement
663
664 let phoneField = infoFormRef.value.fields.find((el) => el.prop === 'phone')
665 let shouldFlagPhone =
666 phoneField &&
667 customizedOptions.value.phone.visibility &&
668 (customizedOptions.value.phone.required || !!infoFormData.value.phone) &&
669 !isPhoneValid.value
670
671 if (shouldFlagPhone) {
672 phoneField.validateState = 'error'
673 }
674 phoneError.value = !!(phoneField && phoneField.validateState === 'error')
675
676 infoFormRef.value.fields.some((el) => {
677 if (el.validateState === 'error') {
678 fieldElement = el.$el
679 return el.validateState === 'error'
680 }
681 })
682
683 // * Scroll to first error
684 useScrollTo(infoFormWrapperRef.value, fieldElement, 0, 300)
685 return false
686 }
687 })
688 }
689
690 // * Watching when footer button was clicked
691 watchEffect(() => {
692 if (footerButtonClicked.value) {
693 submitForm()
694 }
695 })
696
697 let paymentError = computed(() => store.getters['payment/getError'])
698
699 function callPaymentError(msg) {
700 store.commit('payment/setError', msg)
701 }
702
703 let visibilityFlags = ref({})
704
705 function checkCustomerCustomFieldVisibility(cf) {
706 if (cf.saveType === 'customer') {
707 let customerCustomFields = store.getters['customerInfo/getCustomer'].customFields
708
709 if (!customerCustomFields || !(cf.id in JSON.parse(customerCustomFields))) {
710 return true
711 }
712
713 if (visibilityFlags.value[cf.id]) {
714 return visibilityFlags.value[cf.id]
715 }
716
717 switch (cf.type) {
718 case 'checkbox':
719 case 'file':
720 visibilityFlags.value[cf.id] =
721 !cf.saveFirstChoice && customFields.value['cf' + cf.id].value !== []
722 return visibilityFlags.value[cf.id]
723 default:
724 visibilityFlags.value[cf.id] =
725 !cf.saveFirstChoice && customFields.value['cf' + cf.id].value !== ''
726 return visibilityFlags.value[cf.id]
727 }
728 }
729
730 return true
731 }
732
733 function addressSelected(addressComponents, cfId) {
734 if (addressComponents && store.getters['customFields/getCustomFields']['cf' + cfId]) {
735 const cf = store.getters['customFields/getCustomFields']['cf' + cfId]
736 cf.components = mapAddressComponentsForXML(addressComponents)
737 store.commit('customFields/setCustomField', cf)
738 }
739 }
740
741 // * Responsive - Container Width
742 let cWidth = inject('containerWidth')
743 let dWidth = inject('dialogWidth')
744
745 let componentWidth = computed(() => {
746 return props.inDialog ? dWidth.value : cWidth.value
747 })
748
749 let responsiveClass = computed(() => useResponsiveClass(componentWidth.value))
750
751 let socialProvider = ref('')
752 const VueAuthenticateInstance = VueAuthenticate.factory(httpClient, SocialAuthOptions)
753 // * Facebook Sign in error alert
754 let authError = ref(false)
755 let authErrorMessage = ref('')
756
757 function onSignupSocial({ provider, credentials }) {
758 const socialCheckUrl = `/users/authentication/${provider}`
759 const data = {}
760 socialProvider = provider
761
762 if (provider === 'google') {
763 data.code = credentials
764 httpClient.post(`${socialCheckUrl}`, data).then((response) => {
765 setDataFromSocialLogin(response.data.data.user)
766 })
767 }
768 if (provider === 'facebook') {
769 VueAuthenticateInstance.options.providers[provider].url = `${socialCheckUrl}`
770 VueAuthenticateInstance.authenticate(provider, data)
771 .then((response) => {
772 setDataFromSocialLogin(response.data.data.user)
773 })
774 .catch((error) => {
775 if (!VueAuthenticateInstance.isAuthenticated()) {
776 authError.value = true
777 authErrorMessage.value = 'User is not authenticated.'
778 store.commit('setLoading', false)
779 }
780 })
781 }
782 }
783
784 function setDataFromSocialLogin(data) {
785 infoFormData.value.firstName = data.firstName
786 infoFormData.value.lastName = data.lastName
787 infoFormData.value.email = data.email
788 if (data.phone) {
789 infoFormData.value.phone = data.phone
790 const normalizedIso = data.countryPhoneIso ? data.countryPhoneIso.trim().toLowerCase() : ''
791 store.commit('customerInfo/setCustomerCountryPhoneIso', normalizedIso)
792 refreshPhoneComponent.value++
793 }
794 }
795 </script>
796
797 <script>
798 export default {
799 name: 'EventCustomerInfo',
800 key: 'customerInfo',
801 label: 'event_customer_info',
802 }
803 </script>
804
805 <style lang="scss">
806 .amelia-v2-booking #amelia-container {
807 // elfci - event list form customer info
808 .am-elfci {
809 * {
810 box-sizing: border-box;
811 word-break: break-word;
812 }
813
814 &__social-wrapper {
815 display: flex;
816 align-items: center;
817 flex-direction: column;
818 width: 100%;
819 margin: 8px 0 24px;
820 gap: 24px;
821
822 .am-social-signin {
823 &__google {
824 #g_id_onload {
825 display: none;
826 }
827 .g_id_signin {
828 width: 64px;
829 }
830 }
831 }
832
833 &__label {
834 font-weight: 500;
835 font-size: 15px;
836 color: var(--black, #04080b);
837 }
838
839 &-button {
840 display: flex;
841 gap: 8px;
842 padding: 8px;
843 justify-content: center;
844 align-items: center;
845 border-radius: 6px;
846 flex: 1 1 0;
847 height: 40px;
848 box-sizing: border-box;
849 border: 1px solid $shade-250;
850 background: var(--white, #fff);
851 cursor: pointer;
852 width: 100%;
853 max-width: 100%;
854 box-shadow: 0 2px 2px 0 rgba(14, 25, 32, 0.03);
855 color: var(--black, #04080b);
856 font-size: 15px;
857 font-weight: 500;
858 }
859 }
860
861 &__social-divider {
862 align-items: center;
863 display: flex;
864 margin-bottom: 24px;
865
866 // Before & After
867 &:before,
868 &:after {
869 background: var(--shade-250, #d1d5d7);
870 content: '';
871 height: 1px;
872 width: 100%;
873 }
874
875 span {
876 flex: none;
877 font-size: 15px;
878 font-style: normal;
879 font-weight: 400;
880 line-height: 24px;
881 color: var(--shade-500, #808a90);
882 margin-left: 8px;
883 margin-right: 8px;
884 }
885 }
886
887 &__main {
888 &-content.am-elf__event-customer-info {
889 padding-top: 20px;
890 }
891
892 &-inner {
893 overflow: hidden;
894 }
895 }
896
897 &__event-customer-info {
898 &-error {
899 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{100}ms am-animation-slide-up;
900 animation-fill-mode: both;
901 margin-bottom: 10px;
902 }
903 }
904
905 &__form {
906 display: flex;
907 flex-wrap: wrap;
908 justify-content: space-between;
909
910 &.am-rw-500 {
911 .am-elfci__item {
912 width: 100%;
913 }
914 }
915
916 & > * {
917 $count: 100;
918 @for $i from 0 through $count {
919 &:nth-child(#{$i + 1}) {
920 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{$i * 100}ms am-animation-slide-up;
921 animation-fill-mode: both;
922 }
923 }
924 }
925
926 .am-elfci__item {
927 width: calc(50% - 12px);
928
929 &.am-cf-width-100 {
930 width: 100%;
931 }
932
933 &.am-subscribe {
934 width: 100%;
935 .el-checkbox {
936 &__input {
937 height: 32px;
938 line-height: 32px;
939 align-items: center;
940 }
941
942 &__label {
943 line-height: 32px;
944 align-items: center;
945 }
946 }
947 }
948
949 .el-form-item {
950 &__label {
951 display: inline-block;
952 color: var(--am-c-main-text);
953 font-family: var(--am-font-family), sans-serif;
954 font-weight: 500;
955 line-height: unset;
956 margin-bottom: 4px;
957
958 &:before {
959 color: var(--am-c-error);
960 }
961 }
962
963 &__error {
964 line-height: 1;
965 color: var(--am-c-error);
966 }
967
968 &__content {
969 color: var(--am-c-main-text);
970 }
971 }
972 }
973
974 &-mobile {
975 gap: 12px 6px;
976 .el-form-item {
977 width: 100%;
978 }
979 &-s {
980 gap: 0;
981 }
982 }
983
984 &__label {
985 display: inline-block;
986 color: var(--am-c-main-text);
987 font-family: var(--am-font-family), sans-serif;
988 font-weight: 500;
989 margin-bottom: 4px;
990 }
991 }
992
993 &__error {
994 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{100}ms am-animation-slide-up;
995 animation-fill-mode: both;
996 margin-bottom: 10px;
997 }
998 }
999 }
1000 </style>
1001