PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / trunk
Booking for Appointments and Events Calendar – Amelia vtrunk
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 / assets / js / public / public.js
ameliabooking / v3 / src / assets / js / public Last commit date
actions.js 5 days ago booking.js 5 days ago cabinet.js 5 days ago cart.js 5 days ago catalog.js 5 days ago coupon.js 5 days ago customFields.js 5 days ago events.js 5 days ago facebookPixel.js 5 days ago ivy.js 5 days ago package.js 5 days ago panel.js 5 days ago public.js 5 days ago renderActions.js 5 days ago restore.js 5 days ago slots.js 5 days ago translation.js 5 days ago user.js 5 days ago
public.js
500 lines
1 import { createApp, defineAsyncComponent } from 'vue/dist/vue.esm-bundler'
2 import { createStore } from 'vuex'
3 import entities from './../../../store/modules/entities'
4 import booking from './../../../store/modules/booking'
5 import event from './../../../store/modules/event'
6 import attendee from './../../../store/modules/attendee'
7 import appointment from './../../../store/modules/appointment'
8 import employee from './../../../store/modules/employee'
9 import eventEntities from '../../../store/modules/eventEntities'
10 import eventBooking from '../../../store/modules/eventBooking'
11 import shortcodeParams from '../../../store/modules/shortcodeParams'
12 import params from '../../../store/modules/params'
13 import pagination from '../../../store/modules/pagination'
14 import customerInfo from '../../../store/modules/customerInfo'
15 import customFields from '../../../store/modules/customFields'
16 import recurring from '../../../store/modules/recurring'
17 import persons from '../../../store/modules/persons.js'
18 import tickets from '../../../store/modules/tickets.js'
19 import payment from '../../../store/modules/payment.js'
20 import bookableType from '../../../store/modules/bookableType.js'
21 import coupon from '../../../store/modules/coupon.js'
22 import auth from '../../../store/modules/auth.js'
23 import cabinet from '../../../store/modules/cabinet.js'
24 import cabinetFilters from '../../../store/modules/cabinetFilters.js'
25 import eventWaitingListOptions from '../../../store/modules/eventWaitingListOptions'
26 import stepByStepFilters from '../../../store/modules/stepByStepFilters.js'
27 import appointmentWaitingListOptions from '../../../store/modules/appointmentWaitingListOptions'
28
29 import { provide, ref, reactive, readonly } from 'vue'
30 import VueGtag from 'vue-gtag'
31 import { MazUi } from 'maz-ui/plugins'
32 import { mazUi as mazUiThemePreset } from '@maz-ui/themes/presets/mazUi'
33 import 'maz-ui/styles'
34 import { install, init } from './facebookPixel.js'
35
36 import { useLicence } from '../common/licence'
37
38 import dayjs from 'dayjs'
39 import updateLocale from 'dayjs/plugin/updateLocale'
40
41 dayjs.extend(updateLocale)
42
43 dayjs.updateLocale(dayjs.locale(), {
44 weekStart: window.wpAmeliaSettings.wordpress.startOfWeek,
45 })
46
47 // It is necessary to investigate what is the best practice
48 // import axios from './plugins/axios'
49
50 const StepFormWrapper = defineAsyncComponent({
51 loader: () => import('../../../views/public/StepForm/BookingStepForm.vue'),
52 })
53
54 const CatalogFormWrapper = defineAsyncComponent({
55 loader: () => import('../../../views/public/CatalogForm/CatalogForm.vue'),
56 })
57
58 const EventsListFormWrapper = defineAsyncComponent({
59 loader: () => import('../../../views/public/EventForm/EventListForm/EventsListForm.vue'),
60 })
61
62 const EventsCalendarFormWrapper = defineAsyncComponent({
63 loader: () => import('../../../views/public/EventForm/EventCalendarForm/EvensCalendarForm.vue'),
64 })
65
66 const DialogForms = defineAsyncComponent({
67 loader: () => import('../../../views/public/Dialog/DialogForms.vue'),
68 })
69
70 const CustomerPanelWrapper = defineAsyncComponent({
71 loader: () => import('../../../views/public/Cabinet/CustomerPanel/CustomerPanel.vue'),
72 })
73
74 if (typeof window.ameliaShortcodeData === 'undefined') {
75 window.ameliaShortcodeData = [{ counter: null }]
76 }
77
78 const dynamicCdn = window.wpAmeliaUrls.wpAmeliaPluginURL + 'v3/public/'
79
80 window.__dynamic_handler__ = function (importer) {
81 return dynamicCdn + 'assets/' + importer
82 }
83 // @ts-ignore
84 window.__dynamic_preload__ = function (preloads) {
85 return preloads.map((preload) => dynamicCdn + preload)
86 }
87
88 function ameliaBeforeFormSubmit(submit, onError, data) {
89 let formFound = false
90
91 if (window.ameliaShortcodeDataTriggered !== undefined) {
92 window.ameliaShortcodeDataTriggered.forEach((shortcodeData) => {
93 if (parseInt(shortcodeData.ivy) === parseInt(data.formId)) {
94 shortcodeData.ivy = data
95 shortcodeData.trigger = 'ivy'
96
97 setTimeout(() => {
98 const ivyForm = document.getElementsByClassName('ivyforms-form-' + data.formId)[0]
99 if (ivyForm) {
100 ivyForm.style.display = 'none'
101 }
102 }, 200)
103
104 window.amelia.load(shortcodeData)
105
106 formFound = true
107 }
108 })
109 }
110
111 if (!formFound) {
112 submit()
113 }
114 }
115
116 function registerAmeliaIvyFormsHook() {
117 let wpAmeliaSettings = JSON.parse(JSON.stringify(window.wpAmeliaSettings))
118
119 if (wpAmeliaSettings.featuresIntegrations?.ivy?.enabled === false) {
120 return false
121 }
122
123 const register = window.IvyForms?.hooks?.registerBeforeFormSubmit
124
125 if (typeof register !== 'function') {
126 return false
127 }
128
129 window.IvyForms?.hooks?.registerBeforeFormSubmit(ameliaBeforeFormSubmit)
130 }
131
132 if (!registerAmeliaIvyFormsHook()) {
133 window.addEventListener('ivyforms:ready', () => registerAmeliaIvyFormsHook(), { once: true })
134 }
135
136 let isMounted = ref(false)
137
138 function getMazLocale() {
139 const locale = Array.isArray(window.localeLanguage) ? window.localeLanguage[0] : ''
140
141 if (typeof locale !== 'string' || !locale) {
142 return 'en'
143 }
144
145 // Normalize WP locale formats like en_US -> en for maz-ui locale keys.
146 return locale.toLowerCase().replace('_', '-').split('-')[0] || 'en'
147 }
148
149 if (window.ameliaShortcodeDataTriggered !== undefined) {
150 window.ameliaShortcodeDataTriggered.forEach((shortCodeData) => {
151 // * Shortcodes that are rendered in Amelia Popup
152 if (shortCodeData.in_dialog) {
153 // * Collection of all external buttons that are connected to "Amelia popup"
154 let externalButtonsLoading = setInterval(() => {
155 let externalButtons =
156 shortCodeData.trigger_type && shortCodeData.trigger_type === 'class'
157 ? [...document.getElementsByClassName(shortCodeData.trigger)]
158 : [document.getElementById(shortCodeData.trigger)]
159
160 if (
161 externalButtons.length > 0 &&
162 externalButtons[0] !== null &&
163 typeof externalButtons[0] !== 'undefined'
164 ) {
165 clearInterval(externalButtonsLoading)
166
167 // * Detect if form loaded from redirection
168 if ('ameliaCache' in window && window.ameliaCache.length && window.ameliaCache[0]) {
169 let cacheData = JSON.parse(window.ameliaCache[0])
170 if (
171 cacheData &&
172 'request' in cacheData &&
173 'form' in cacheData.request &&
174 'shortcode' in cacheData.request.form &&
175 'trigger' in cacheData.request.form.shortcode &&
176 cacheData.request.form.shortcode.trigger &&
177 parseInt(cacheData.request.form.shortcode.counter) === parseInt(shortCodeData.counter)
178 ) {
179 shortCodeData.isRestored = true
180 }
181 }
182
183 // * vue creation
184 createAmelia(shortCodeData)
185
186 // * Made the buttons invisible because amelia components are not fully loaded
187 externalButtons.forEach((btn) => {
188 btn.style.pointerEvents = 'none'
189 })
190
191 // Create a timeout to prevent buttons from being permanently disabled
192 let componentLoadTimeout
193
194 let componentsLoaded = setInterval(() => {
195 if (isMounted.value) {
196 clearInterval(componentsLoaded)
197 clearTimeout(componentLoadTimeout)
198 // * Made the buttons visible because amelia components are fully loaded
199 externalButtons.forEach((btn) => {
200 btn.style.removeProperty('pointer-events')
201 })
202 }
203 }, 250)
204
205 // Safety timeout - if components don't load within 12 seconds, enable buttons anyway
206 componentLoadTimeout = setTimeout(() => {
207 clearInterval(componentsLoaded)
208 console.warn('Amelia components loading timeout')
209 externalButtons.forEach((btn) => {
210 btn.style.removeProperty('pointer-events')
211 })
212 }, 12000)
213 }
214 }, 250)
215 } else if (!shortCodeData.ivy) {
216 let ameliaPopUpLoaded = false
217
218 let ameliaBookingButtonLoadInterval = setInterval(function () {
219 let ameliaPopUpButtons =
220 shortCodeData.trigger_type && shortCodeData.trigger_type === 'class'
221 ? [...document.getElementsByClassName(shortCodeData.trigger)]
222 : [document.getElementById(shortCodeData.trigger)]
223
224 if (
225 !ameliaPopUpLoaded &&
226 ameliaPopUpButtons.length > 0 &&
227 ameliaPopUpButtons[0] !== null &&
228 typeof ameliaPopUpButtons[0] !== 'undefined'
229 ) {
230 ameliaPopUpLoaded = true
231
232 clearInterval(ameliaBookingButtonLoadInterval)
233 ameliaPopUpButtons.forEach((ameliaPopUpButton) => {
234 ameliaPopUpButton.onclick = function () {
235 let ameliaBookingFormLoadInterval = setInterval(function () {
236 let ameliaPopUpForms = document.getElementsByClassName(
237 'amelia-skip-load-' + shortCodeData.counter,
238 )
239
240 if (ameliaPopUpForms.length) {
241 clearInterval(ameliaBookingFormLoadInterval)
242 for (let i = 0; i < ameliaPopUpForms.length; i++) {
243 if (
244 !ameliaPopUpForms[i].classList.contains(
245 'amelia-v2-booking-' + shortCodeData.counter + '-loaded',
246 )
247 ) {
248 createAmelia(shortCodeData)
249 }
250 }
251 }
252 }, 1000)
253 }
254
255 if ('ameliaCache' in window && window.ameliaCache.length && window.ameliaCache[0]) {
256 let cacheData = JSON.parse(window.ameliaCache[0])
257
258 if (
259 cacheData &&
260 'request' in cacheData &&
261 'form' in cacheData.request &&
262 'shortcode' in cacheData.request.form &&
263 'trigger' in cacheData.request.form.shortcode &&
264 cacheData.request.form.shortcode.trigger
265 ) {
266 if (
267 !('trigger_type' in cacheData.request.form.shortcode) ||
268 !cacheData.request.form.shortcode.trigger_type ||
269 cacheData.request.form.shortcode.trigger_type === 'id'
270 ) {
271 let el = document.getElementById(cacheData.request.form.shortcode.trigger)
272
273 if (typeof el !== 'undefined') {
274 el.click()
275 }
276 } else if (
277 'trigger_type' in cacheData.request.form.shortcode &&
278 cacheData.request.form.shortcode.trigger_type === 'class'
279 ) {
280 let el = document.getElementsByClassName(cacheData.request.form.shortcode.trigger)
281
282 if (typeof el !== 'undefined' && el.length) {
283 el[0].click()
284 }
285 }
286 }
287 }
288 })
289 }
290 }, 1000)
291 }
292 })
293 }
294
295 window.ameliaShortcodeData.forEach((item) => {
296 createAmelia(item)
297 })
298
299 function createAmelia(shortcodeData) {
300 let wpAmeliaSettings = JSON.parse(JSON.stringify(window.wpAmeliaSettings))
301
302 if (window?.ameliaActions?.init) {
303 window.ameliaActions.init(shortcodeData, wpAmeliaSettings)
304 }
305
306 const settings = reactive(wpAmeliaSettings)
307
308 let wpAmeliaTimeZones = 'wpAmeliaTimeZones' in window ? window.wpAmeliaTimeZones : []
309
310 let app = createApp({
311 setup() {
312 const baseURLs = reactive(window.wpAmeliaUrls)
313 const labels = reactive(window.wpAmeliaLabels)
314 const timeZones = reactive(wpAmeliaTimeZones)
315 const timeZone = ref('wpAmeliaTimeZone' in window ? window.wpAmeliaTimeZone[0] : '')
316 const localLanguage = ref(window.localeLanguage[0])
317 const licence = reactive(useLicence())
318 provide('settings', readonly(settings))
319 provide('baseUrls', readonly(baseURLs))
320 provide('labels', readonly(labels))
321 provide('timeZones', readonly(timeZones))
322 provide('timeZone', readonly(timeZone))
323 provide('localLanguage', readonly(localLanguage))
324 provide('shortcodeData', readonly(ref(shortcodeData)))
325 provide('licence', licence)
326 provide('isMounted', isMounted)
327 },
328 })
329
330 if (settings.featuresIntegrations.googleAnalytics.enabled && settings.googleTag.id) {
331 app.use(VueGtag, {
332 config: { id: wpAmeliaSettings.googleTag.id },
333 })
334 }
335
336 if (settings.featuresIntegrations.googleAnalytics.enabled && settings.googleAnalytics.id) {
337 app.use(VueGtag, {
338 config: { id: wpAmeliaSettings.googleAnalytics.id },
339 })
340 }
341
342 if (settings.facebookPixel.id) {
343 install()
344
345 init(wpAmeliaSettings.facebookPixel.id)
346 }
347
348 let data =
349 'ameliaCache' in window && window.ameliaCache.length && window.ameliaCache[0]
350 ? JSON.parse(window.ameliaCache[0])
351 : null
352
353 app.use(MazUi, {
354 theme: {
355 preset: mazUiThemePreset,
356 strategy: 'runtime',
357 darkModeStrategy: 'class',
358 },
359 translations: {
360 locale: getMazLocale(),
361 fallbackLocale: 'en',
362 },
363 })
364
365 app
366 .component('StepFormWrapper', StepFormWrapper)
367 .component('CatalogFormWrapper', CatalogFormWrapper)
368 .component('EventsListFormWrapper', EventsListFormWrapper)
369 .component('EventsCalendarFormWrapper', EventsCalendarFormWrapper)
370 .component('DialogForms', DialogForms)
371 .component('CustomerPanelWrapper', CustomerPanelWrapper)
372 .use(
373 createStore({
374 namespaced: true,
375
376 state: () => ({
377 settings: reactive(wpAmeliaSettings),
378 labels: reactive(window.wpAmeliaLabels),
379 localLanguage: ref(window.localeLanguage[0]),
380 baseUrls: reactive(window.wpAmeliaUrls),
381 timeZones: reactive(wpAmeliaTimeZones),
382 timeZone: ref('wpAmeliaTimeZone' in window ? window.wpAmeliaTimeZone[0] : ''),
383 isRtl: ref(document.documentElement.dir === 'rtl'),
384 ready: false,
385 loading: true,
386 formKey: '',
387 restoring:
388 data &&
389 data?.request?.form?.shortcode?.counter &&
390 parseInt(data.request.form.shortcode.counter) === parseInt(shortcodeData.counter),
391 restored: false,
392 ivy: shortcodeData.ivy,
393 }),
394
395 getters: {
396 getSettings(state) {
397 return state.settings
398 },
399
400 getLabels(state) {
401 return state.labels
402 },
403
404 getLocalLanguage(state) {
405 return state.localLanguage
406 },
407
408 getBaseUrls(state) {
409 return state.baseUrls
410 },
411
412 getRestoring(state) {
413 return state.restoring
414 },
415
416 getRestored(state) {
417 return state.restored
418 },
419
420 getReady(state) {
421 return state.ready
422 },
423
424 getLoading(state) {
425 return state.loading
426 },
427
428 getFormKey(state) {
429 return state.formKey
430 },
431
432 getIsRtl(state) {
433 return state.isRtl
434 },
435
436 getIvy(state) {
437 return state.ivy
438 },
439 },
440
441 mutations: {
442 setRestoring(state, payload) {
443 state.restoring = payload
444 },
445
446 setRestored(state, payload) {
447 state.restored = payload
448 },
449
450 setReady(state, payload) {
451 state.ready = payload
452 },
453
454 setLoading(state, payload) {
455 state.loading = payload
456 },
457
458 setFormKey(state, payload) {
459 state.formKey = payload
460 },
461
462 setIvy(state, payload) {
463 state.ivy = payload
464 },
465 },
466
467 modules: {
468 entities,
469 booking,
470 event,
471 attendee,
472 appointment,
473 employee,
474 eventEntities,
475 eventBooking,
476 shortcodeParams,
477 params,
478 pagination,
479 customerInfo,
480 customFields,
481 recurring,
482 persons,
483 tickets,
484 payment,
485 bookableType,
486 coupon,
487 auth,
488 cabinet,
489 cabinetFilters,
490 eventWaitingListOptions,
491 stepByStepFilters,
492 appointmentWaitingListOptions,
493 },
494 }),
495 )
496 .mount(`#amelia-v2-booking${shortcodeData.counter !== null ? '-' + shortcodeData.counter : ''}`)
497 }
498
499 window.amelia = { load: createAmelia }
500