PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.6
Booking for Appointments and Events Calendar – Amelia v2.4.6
2.4.8 2.4.7 2.4.6 2.4.5 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 1 month ago
EventCustomerInfo.vue
1005 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(
415 phoneData?.phoneNumber ?? phoneData?.e164,
416 phoneData,
417 countryCode,
418 ),
419 )
420
421 isPhoneValid.value = !!phoneData.isValid
422 },
423 },
424 },
425 })
426
427 // * Form validation rules
428 let infoFormRules = ref({
429 firstName: [
430 {
431 required: true,
432 message: amLabels.value.enter_first_name_warning,
433 trigger: 'submit',
434 },
435 ],
436 lastName: [
437 {
438 required: customizedOptions.value.lastName.required,
439 message: amLabels.value.enter_last_name_warning,
440 trigger: 'submit',
441 },
442 ],
443 email: [
444 {
445 required: customizedOptions.value.email.required,
446 type: 'email',
447 message: amLabels.value.enter_valid_email_warning,
448 trigger: 'submit',
449 },
450 ],
451 phone: [
452 {
453 required: customizedOptions.value.phone.required,
454 message: amLabels.value.enter_phone_warning,
455 trigger: ['blur', 'submit'],
456 },
457 ],
458 })
459
460 let subscribeToMailchimp = computed({
461 get: () => store.getters['customerInfo/getCustomerSubscribe'],
462 set: (val) => {
463 store.commit('customerInfo/setCustomerSubscribe', val)
464 },
465 })
466
467 Object.keys(customFields.value).forEach((fieldKey) => {
468 // * Form Model
469 infoFormData.value[fieldKey] = computed({
470 get: () => store.getters['customFields/getCustomFieldValue'](fieldKey),
471 set: (val) => {
472 let obj = {
473 key: fieldKey,
474 value: val,
475 }
476 store.commit('customFields/setCustomFieldValue', obj)
477 },
478 })
479
480 // * Form Rules
481 infoFormRules.value[fieldKey] = [
482 {
483 message: amLabels.value.required_field,
484 required: customFields.value[fieldKey].required,
485 trigger: 'submit',
486 },
487 ]
488
489 // * Form Construction
490 infoFormConstruction.value[fieldKey] = {
491 template: formFieldsTemplates[customFields.value[fieldKey].type],
492 props: {
493 id: 'am-cf-' + customFields.value[fieldKey].id,
494 itemName: fieldKey,
495 label: customFields.value[fieldKey].label,
496 options: customFields.value[fieldKey].options,
497 class: `am-elfci__item am-cf-width-${customFields.value[fieldKey].width}`,
498 },
499 }
500
501 if (
502 customFields.value[fieldKey].type === 'checkbox' ||
503 customFields.value[fieldKey].type === 'radio'
504 ) {
505 infoFormConstruction.value[fieldKey].props.options = infoFormConstruction.value[
506 fieldKey
507 ].props.options.map((option) => {
508 return {
509 ...option,
510 value: option.label,
511 }
512 })
513 }
514
515 if (customFields.value[fieldKey].type === 'text-area') {
516 infoFormConstruction.value[fieldKey].props = {
517 ...infoFormConstruction.value[fieldKey].props,
518 ...{ itemType: 'textarea' },
519 }
520 }
521
522 if (customFields.value[fieldKey].type === 'file') {
523 infoFormConstruction.value[fieldKey].props = {
524 ...infoFormConstruction.value[fieldKey].props,
525 ...{ btnLabel: amLabels.value.upload_file_here },
526 }
527 }
528
529 if (customFields.value[fieldKey].type === 'datepicker') {
530 infoFormConstruction.value[fieldKey].props = {
531 ...infoFormConstruction.value[fieldKey].props,
532 ...{ weekStartsFromDay: amSettings.wordpress.startOfWeek },
533 refreshValue: refreshDatePickerValue,
534 }
535 }
536 })
537
538 let wcEventEnabled = ref(false)
539
540 onMounted(() => {
541 let eventPayments =
542 selectedEvent && selectedEvent.value.settings
543 ? JSON.parse(selectedEvent.value.settings)['payments']
544 : null
545
546 wcEventEnabled.value =
547 eventPayments && 'wc' in eventPayments
548 ? !('enabled' in eventPayments.wc) || eventPayments.wc.enabled
549 : settings.payments.wc.enabled
550
551 if (isWaitingAvailable.value) {
552 if (eventFluidStepKey.value.indexOf('eventPayment') !== -1) {
553 let index = eventFluidStepKey.value.indexOf('eventPayment')
554 if (index > 0) {
555 eventFluidStepKey.value.splice(index, 1)
556 }
557 }
558 } else {
559 // * remove payment step
560 if (instantBooking.value && eventFluidStepKey.value.indexOf('eventPayment') !== -1) {
561 let index = eventFluidStepKey.value.indexOf('eventPayment')
562 if (index > 0) {
563 eventFluidStepKey.value.splice(index, 1)
564 }
565 }
566
567 // * add payment step
568 if (!instantBooking.value && eventFluidStepKey.value.indexOf('eventPayment') < 0) {
569 eventFluidStepKey.value.push('eventPayment')
570 }
571 }
572
573 nextTick(() => {
574 setTimeout(() => {
575 customerCollectorRef.value.forEach((el) => {
576 if (el.formFieldRef) {
577 allFieldsRefs.value.push(el.formFieldRef)
578 }
579 })
580
581 customFieldsCollectorRefs.value.forEach((el) => {
582 if (el.formFieldRef) {
583 allFieldsRefs.value.push(el.formFieldRef)
584 }
585 })
586 }, 500)
587 })
588
589 Object.keys(customFields.value).forEach((fieldKey) => {
590 // * Placeholder implementation for custom input and textarea
591 if (
592 customFields.value[fieldKey].type === 'text' ||
593 customFields.value[fieldKey].type === 'text-area'
594 ) {
595 refCFPlaceholders.value[fieldKey] = { placeholder: '' }
596 }
597 })
598
599 useAction(
600 store,
601 { customFields, customFieldsPlaceholders: refCFPlaceholders, couponCode },
602 'InitInfoStep',
603 'event',
604 null,
605 null,
606 )
607
608 if (couponCode.value) {
609 store.commit('coupon/setCode', couponCode.value)
610 }
611
612 if (Object.values(refCFPlaceholders.value).filter((cf) => cf.placeholder !== '').length) {
613 Object.keys(refCFPlaceholders.value).forEach((fieldKey) => {
614 infoFormConstruction.value[fieldKey].props = {
615 ...infoFormConstruction.value[fieldKey].props,
616 placeholder: refCFPlaceholders.value[fieldKey].placeholder,
617 }
618 })
619 }
620
621 if (useIvyMapping(store, shortcodeData, infoFormData)) {
622 refreshPhoneComponent.value++
623 }
624 })
625
626 // * Submit Form
627 function submitForm() {
628 // store.commit('setLoading', true)
629 footerButtonReset()
630
631 // Trim inputs
632 infoFormData.value.firstName = infoFormData.value.firstName.trim()
633 infoFormData.value.lastName = infoFormData.value.lastName.trim()
634 infoFormData.value.email = infoFormData.value.email.trim()
635
636 useAction(store, { rules: infoFormRules.value }, 'customValidation', 'event', null, null)
637
638 infoFormRef.value.validate((valid) => {
639 if (valid && (customizedOptions.value.phone.required ? isPhoneValid.value : true)) {
640 phoneError.value = false
641 if (isWaitingAvailable.value) {
642 store.commit('payment/setPaymentGateway', 'onSite')
643
644 refOnSiteBooking.value.continueWithBooking()
645 } else {
646 if (!instantBooking.value) {
647 nextStep()
648 } else {
649 if (
650 amSettings.payments.wc.enabled &&
651 !amSettings.payments.wc.onSiteIfFree &&
652 wcEventEnabled.value
653 ) {
654 store.commit('payment/setPaymentGateway', 'wc')
655
656 refWcBooking.value.continueWithBooking()
657 } else {
658 store.commit('payment/setPaymentGateway', 'onSite')
659
660 refOnSiteBooking.value.continueWithBooking()
661 }
662 }
663 }
664 } else {
665 // store.commit('setLoading', false)
666 let fieldElement
667
668 let phoneField = infoFormRef.value.fields.find((el) => el.prop === 'phone')
669 let shouldFlagPhone =
670 phoneField &&
671 customizedOptions.value.phone.visibility &&
672 (customizedOptions.value.phone.required || !!infoFormData.value.phone) &&
673 !isPhoneValid.value
674
675 if (shouldFlagPhone) {
676 phoneField.validateState = 'error'
677 }
678 phoneError.value = !!(phoneField && phoneField.validateState === 'error')
679
680 infoFormRef.value.fields.some((el) => {
681 if (el.validateState === 'error') {
682 fieldElement = el.$el
683 return el.validateState === 'error'
684 }
685 })
686
687 // * Scroll to first error
688 useScrollTo(infoFormWrapperRef.value, fieldElement, 0, 300)
689 return false
690 }
691 })
692 }
693
694 // * Watching when footer button was clicked
695 watchEffect(() => {
696 if (footerButtonClicked.value) {
697 submitForm()
698 }
699 })
700
701 let paymentError = computed(() => store.getters['payment/getError'])
702
703 function callPaymentError(msg) {
704 store.commit('payment/setError', msg)
705 }
706
707 let visibilityFlags = ref({})
708
709 function checkCustomerCustomFieldVisibility(cf) {
710 if (cf.saveType === 'customer') {
711 let customerCustomFields = store.getters['customerInfo/getCustomer'].customFields
712
713 if (!customerCustomFields || !(cf.id in JSON.parse(customerCustomFields))) {
714 return true
715 }
716
717 if (visibilityFlags.value[cf.id]) {
718 return visibilityFlags.value[cf.id]
719 }
720
721 switch (cf.type) {
722 case 'checkbox':
723 case 'file':
724 visibilityFlags.value[cf.id] =
725 !cf.saveFirstChoice && customFields.value['cf' + cf.id].value !== []
726 return visibilityFlags.value[cf.id]
727 default:
728 visibilityFlags.value[cf.id] =
729 !cf.saveFirstChoice && customFields.value['cf' + cf.id].value !== ''
730 return visibilityFlags.value[cf.id]
731 }
732 }
733
734 return true
735 }
736
737 function addressSelected(addressComponents, cfId) {
738 if (addressComponents && store.getters['customFields/getCustomFields']['cf' + cfId]) {
739 const cf = store.getters['customFields/getCustomFields']['cf' + cfId]
740 cf.components = mapAddressComponentsForXML(addressComponents)
741 store.commit('customFields/setCustomField', cf)
742 }
743 }
744
745 // * Responsive - Container Width
746 let cWidth = inject('containerWidth')
747 let dWidth = inject('dialogWidth')
748
749 let componentWidth = computed(() => {
750 return props.inDialog ? dWidth.value : cWidth.value
751 })
752
753 let responsiveClass = computed(() => useResponsiveClass(componentWidth.value))
754
755 let socialProvider = ref('')
756 const VueAuthenticateInstance = VueAuthenticate.factory(httpClient, SocialAuthOptions)
757 // * Facebook Sign in error alert
758 let authError = ref(false)
759 let authErrorMessage = ref('')
760
761 function onSignupSocial({ provider, credentials }) {
762 const socialCheckUrl = `/users/authentication/${provider}`
763 const data = {}
764 socialProvider = provider
765
766 if (provider === 'google') {
767 data.code = credentials
768 httpClient.post(`${socialCheckUrl}`, data).then((response) => {
769 setDataFromSocialLogin(response.data.data.user)
770 })
771 }
772 if (provider === 'facebook') {
773 VueAuthenticateInstance.options.providers[provider].url = `${socialCheckUrl}`
774 VueAuthenticateInstance.authenticate(provider, data)
775 .then((response) => {
776 setDataFromSocialLogin(response.data.data.user)
777 })
778 .catch((error) => {
779 if (!VueAuthenticateInstance.isAuthenticated()) {
780 authError.value = true
781 authErrorMessage.value = 'User is not authenticated.'
782 store.commit('setLoading', false)
783 }
784 })
785 }
786 }
787
788 function setDataFromSocialLogin(data) {
789 infoFormData.value.firstName = data.firstName
790 infoFormData.value.lastName = data.lastName
791 infoFormData.value.email = data.email
792 if (data.phone) {
793 infoFormData.value.phone = data.phone
794 const normalizedIso = data.countryPhoneIso ? data.countryPhoneIso.trim().toLowerCase() : ''
795 store.commit('customerInfo/setCustomerCountryPhoneIso', normalizedIso)
796 refreshPhoneComponent.value++
797 }
798 }
799 </script>
800
801 <script>
802 export default {
803 name: 'EventCustomerInfo',
804 key: 'customerInfo',
805 label: 'event_customer_info',
806 }
807 </script>
808
809 <style lang="scss">
810 .amelia-v2-booking #amelia-container {
811 // elfci - event list form customer info
812 .am-elfci {
813 * {
814 box-sizing: border-box;
815 word-break: break-word;
816 }
817
818 &__social-wrapper {
819 display: flex;
820 align-items: center;
821 flex-direction: column;
822 width: 100%;
823 margin: 8px 0 24px;
824 gap: 24px;
825
826 .am-social-signin {
827 &__google {
828 #g_id_onload {
829 display: none;
830 }
831 .g_id_signin {
832 width: 64px;
833 }
834 }
835 }
836
837 &__label {
838 font-weight: 500;
839 font-size: 15px;
840 color: var(--black, #04080b);
841 }
842
843 &-button {
844 display: flex;
845 gap: 8px;
846 padding: 8px;
847 justify-content: center;
848 align-items: center;
849 border-radius: 6px;
850 flex: 1 1 0;
851 height: 40px;
852 box-sizing: border-box;
853 border: 1px solid $shade-250;
854 background: var(--white, #fff);
855 cursor: pointer;
856 width: 100%;
857 max-width: 100%;
858 box-shadow: 0 2px 2px 0 rgba(14, 25, 32, 0.03);
859 color: var(--black, #04080b);
860 font-size: 15px;
861 font-weight: 500;
862 }
863 }
864
865 &__social-divider {
866 align-items: center;
867 display: flex;
868 margin-bottom: 24px;
869
870 // Before & After
871 &:before,
872 &:after {
873 background: var(--shade-250, #d1d5d7);
874 content: '';
875 height: 1px;
876 width: 100%;
877 }
878
879 span {
880 flex: none;
881 font-size: 15px;
882 font-style: normal;
883 font-weight: 400;
884 line-height: 24px;
885 color: var(--shade-500, #808a90);
886 margin-left: 8px;
887 margin-right: 8px;
888 }
889 }
890
891 &__main {
892 &-content.am-elf__event-customer-info {
893 padding-top: 20px;
894 }
895
896 &-inner {
897 overflow: hidden;
898 }
899 }
900
901 &__event-customer-info {
902 &-error {
903 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{100}ms am-animation-slide-up;
904 animation-fill-mode: both;
905 margin-bottom: 10px;
906 }
907 }
908
909 &__form {
910 display: flex;
911 flex-wrap: wrap;
912 justify-content: space-between;
913
914 &.am-rw-500 {
915 .am-elfci__item {
916 width: 100%;
917 }
918 }
919
920 & > * {
921 $count: 100;
922 @for $i from 0 through $count {
923 &:nth-child(#{$i + 1}) {
924 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{$i * 100}ms am-animation-slide-up;
925 animation-fill-mode: both;
926 }
927 }
928 }
929
930 .am-elfci__item {
931 width: calc(50% - 12px);
932
933 &.am-cf-width-100 {
934 width: 100%;
935 }
936
937 &.am-subscribe {
938 width: 100%;
939 .el-checkbox {
940 &__input {
941 height: 32px;
942 line-height: 32px;
943 align-items: center;
944 }
945
946 &__label {
947 line-height: 32px;
948 align-items: center;
949 }
950 }
951 }
952
953 .el-form-item {
954 &__label {
955 display: inline-block;
956 color: var(--am-c-main-text);
957 font-family: var(--am-font-family), sans-serif;
958 font-weight: 500;
959 line-height: unset;
960 margin-bottom: 4px;
961
962 &:before {
963 color: var(--am-c-error);
964 }
965 }
966
967 &__error {
968 line-height: 1;
969 color: var(--am-c-error);
970 }
971
972 &__content {
973 color: var(--am-c-main-text);
974 }
975 }
976 }
977
978 &-mobile {
979 gap: 12px 6px;
980 .el-form-item {
981 width: 100%;
982 }
983 &-s {
984 gap: 0;
985 }
986 }
987
988 &__label {
989 display: inline-block;
990 color: var(--am-c-main-text);
991 font-family: var(--am-font-family), sans-serif;
992 font-weight: 500;
993 margin-bottom: 4px;
994 }
995 }
996
997 &__error {
998 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{100}ms am-animation-slide-up;
999 animation-fill-mode: both;
1000 margin-bottom: 10px;
1001 }
1002 }
1003 }
1004 </style>
1005