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 / BookingStepForm.vue
ameliabooking / v3 / src / views / public / StepForm Last commit date
BringingAnyone 1 year ago CartStep 2 years ago Congratulations 1 year ago DateTimeStep 1 year ago Extras 3 years ago InfoStep 1 year ago InitStep 1 year ago PakagesStep 3 years ago PaymentStep 1 year ago RecurringStep 2 years ago _fields 2 years ago BookingStepForm.vue 1 year ago
BookingStepForm.vue
1622 lines
1 <template>
2 <template v-if="!amFonts.customFontSelected">
3 <link rel="preconnect" href="https://fonts.googleapis.com">
4 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
5 <link rel="stylesheet" type="text/css" :href="`${baseUrls.wpAmeliaPluginURL}v3/src/assets/scss/common/fonts/font.css`" media="all">
6 </template>
7 <div
8 v-if="!empty && formDialogVisibility"
9 id="amelia-container"
10 ref="ameliaContainer"
11 class="am-fs__wrapper"
12 :class="{'am-collapsed': sidebarCollapsed}"
13 :style="cssVars"
14 >
15 <SideBar
16 v-if="containerWidth > 560 && sidebarVisibility"
17 class="am-fs-sb"
18 :class="{'am-collapsed': sidebarCollapsed}"
19 :style="{width: !sidebarCollapsed ? '240px' : '72px', paddingBottom: `${sidebarFooterHeight + 16}px` }"
20 >
21 <template #step-list>
22 <div class="am-fs-sb__step-wrapper">
23 <template v-if="ready && (stepsArray[stepIndex] !== congratulationsStep || !amSettings.general.addToCalendar || (booked && booked.data.length === 0))">
24 <div
25 v-for="step in sidebarSteps"
26 :key="step.key"
27 class="am-fs-sb__step"
28 >
29 <div class="am-fs-sb__step-inner">
30 <div class="am-fs-sb__step-icon">
31 <span :class="`am-icon-${step.icon}`"></span>
32 <span
33 v-if="step.key === 'cartStep' && useCartHasItems(store) !== 0"
34 class="am-fs-sb__step-icon__number"
35 :class="sidebarCollapseItemsClass"
36 >
37 {{useCartHasItems(store)}}
38 </span>
39 </div>
40 <transition name="fade">
41 <p
42 v-if="!sidebarCollapsed"
43 class="am-fs-sb__step-heading"
44 :class="sidebarCollapseItemsClass"
45 >
46 {{ step.label }}
47 </p>
48 </transition>
49 <div
50 class="am-fs-sb__step-checker"
51 :class="[{'am-fs-sb__step-checker-selected': step.selected}, sidebarCollapseItemsClass]"
52 >
53 <transition name="fade">
54 <span v-if="step.finished" class="am-icon-check"></span>
55 </transition>
56 </div>
57 </div>
58 <TransitionGroup
59 tag="span"
60 name="fade"
61 appear
62 class="am-fs-sb__step-selection__wrapper"
63 :class="{'am-fs-sb__step-selection-packages': step.key === packageAppointmentsStep.key && step.stepSelectedData.length > 3 }"
64 >
65 <template v-if="!sidebarCollapsed && (useCart(store).length === 1 || step.key === 'cartStep')">
66 <p
67 v-for="(itemSelected, index) in step.stepSelectedData"
68 :key="itemSelected.position"
69 class="am-fs-sb__step-selection"
70 >
71 <span v-if="step.key !== packageAppointmentsStep.key || index < 3">
72 {{ itemSelected.value }}
73 </span>
74 <span v-else>
75 {{ amLabels.plus_more }}
76 </span>
77 </p>
78 </template>
79 </TransitionGroup>
80 </div>
81 </template>
82 <template v-else-if="ready">
83 <div>
84 <transition name="fade">
85 <AddToCalendar v-if="!sidebarCollapsed"></AddToCalendar>
86 </transition>
87 <div v-if="sidebarCollapsed" class="am-fs-sb__step">
88 <div class="am-fs-sb__step-inner">
89 <div class="am-fs-sb__step-icon">
90 <span :class="`am-icon-${stepsArray[stepIndex].sidebarData.icon}`"></span>
91 </div>
92 <div
93 class="am-fs-sb__step-checker"
94 :class="[{'am-fs-sb__step-checker-selected': stepsArray[stepIndex].sidebarData.selected}, sidebarCollapseItemsClass]"
95 >
96 <transition name="fade">
97 <span v-if="stepsArray[stepIndex].sidebarData.finished" class="am-icon-check"></span>
98 </transition>
99 </div>
100 </div>
101 </div>
102 </div>
103 </template>
104 <template v-else>
105 <!-- Skeleton -->
106 <el-skeleton animated>
107 <template #template>
108 <div v-for="item in new Array(3)" :key="item">
109 <div class="el-skeleton-item-wrapper">
110 <el-skeleton-item variant="text" />
111 </div>
112 </div>
113 </template>
114 </el-skeleton>
115 <!-- /Skeleton -->
116 </template>
117 </div>
118 </template>
119 <template #support-info>
120 <div
121 ref="sidebarFooterRef"
122 class="am-fs-sb__footer"
123 >
124 <div
125 v-if="(amSettings.company.email || amSettings.company.phone)
126 && (footerCustomizeOptions.heading || footerCustomizeOptions.phone || footerCustomizeOptions.email)"
127 class="am-fs-sb__support"
128 >
129 <transition name="fade">
130 <div
131 v-if="!sidebarCollapsed && footerCustomizeOptions.heading"
132 class="am-fs-sb__support-heading"
133 :class="sidebarCollapseItemsClass"
134 >
135 {{ amLabels.get_in_touch }}
136 </div>
137 </transition>
138 <a
139 v-if="amSettings.company.phone && footerCustomizeOptions.phone"
140 class="am-fs-sb__support-email"
141 :href="`tel:${amSettings.company.phone}`"
142 >
143 <template v-if="!sidebarCollapsed">
144 {{ amSettings.company.phone }}
145 </template>
146 <template v-else>
147 <span class="am-icon-phone"></span>
148 </template>
149 </a>
150 <a
151 v-if="amSettings.company.email && footerCustomizeOptions.email"
152 class="am-fs-sb__support-email"
153 :href="`mailto:${amSettings.company.email}`"
154 >
155 <template v-if="!sidebarCollapsed">
156 {{ amSettings.company.email }}
157 </template>
158 <template v-else>
159 <span class="am-icon-email"></span>
160 </template>
161 </a>
162 </div>
163 <div
164 class="am-fs-sb__menu"
165 :class="sidebarCollapseItemsClass"
166 @click="sidebarCollapsed = !sidebarCollapsed"
167 >
168 <Transition name="fade">
169 <span
170 v-if="!sidebarCollapsed"
171 class="am-fs-sb__menu-text"
172 >
173 {{ amLabels.collapse_menu }}
174 </span>
175 </Transition>
176 <span :class="`am-icon-arrow-circle-${sidebarCollapsed ? 'left' : 'right'}`"></span>
177 </div>
178 </div>
179 </template>
180 </SideBar>
181 <MainContent>
182 <template v-if="stepsArray[stepIndex] !== congratulationsStep" #header>
183 <MainContentHeader :sidebar-visible="sidebarVisibility" :ready="ready"></MainContentHeader>
184 </template>
185 <template #step>
186 <component :is="stepsArray[stepIndex]" global-class="am-fs__main-content"></component>
187 </template>
188 <template #footer>
189 <MainContentFooter
190 :second-button-show="stepsArray[stepIndex] === congratulationsStep && amSettings.roles.customerCabinet.enabled && amSettings.roles.customerCabinet.pageUrl !== null"
191 :add-to-cart-button-show="useCartStep(store) && stepsArray[stepIndex] === cartStep"
192 :back-to-cart-button-show="useCartStep(store) && cart.length > 1 && stepsArray[stepIndex] !== cartStep && stepsArray[stepIndex] !== infoStep && stepsArray[stepIndex] !== paymentStep && stepsArray[stepIndex] !== congratulationsStep"
193 :booked="booked"
194 :loading="loading"
195 :payment-gateway="paymentGateway"
196 :customized-labels="footerLabels"
197 :primary-footer-button-type="primFooterBtnType"
198 :secondary-footer-button-type="secFooterBtnType"
199 :add-to-cart-button-type="addToCartBtnType"
200 :back-to-cart-button-type="backToCartBtnType"
201 :back-to-cart-label="dedicatedStepLabel('cancel', 'cartStep')"
202 :ready="ready"
203 @add-to-cart="addToCart"
204 @back-to-cart="backToCart"
205 ></MainContentFooter>
206 </template>
207 </MainContent>
208 </div>
209 <template v-else>
210 <div v-if="shortcodeData.show !== 'packages' && !shortcodeData.package" ref="ameliaContainer" class="am-no-services">
211 <img :src="baseUrls.wpAmeliaPluginURL+'/v3/src/assets/img/am-empty-booking.svg'" style="margin-top: 10px;">
212 <div class="am-no-services-oops">{{amLabels.oops}}</div>
213 <div class="am-no-services-text">{{amLabels.no_services_employees}}</div>
214 <div class="am-no-services-text-2">
215 <p>{{amLabels.add_services_employees}}</p>
216 <a href="https://wpamelia.com/services-and-categories/" rel="nofollow">
217 {{amLabels.add_services_url}}&nbsp;
218 </a>
219 <span style="font-size:14px">{{amLabels.and}}&nbsp;</span>
220 <a href="https://wpamelia.com/employees/" rel="nofollow">
221 {{amLabels.add_employees_url}}
222 </a>
223 </div>
224 </div>
225 <div v-else ref="ameliaContainer" class="am-no-services" style="height: 100%">
226 <img :src="baseUrls.wpAmeliaPluginURL+'/v3/src/assets/img/am-empty-booking.svg'" style="margin-top: 10px;">
227 <div>{{amLabels.oops}}</div>
228 <div>{{amLabels.no_package_services}}</div>
229 <a href="https://wpamelia.com/services-and-categories/" rel="nofollow">
230 {{amLabels.add_services_url}}&nbsp;
231 </a>
232 </div>
233 </template>
234 <BackLink/>
235 </template>
236
237 <script setup>
238 // * Form construction
239 import MainContent from '../../common/SbsFormConstruction/MainContent/MainContent.vue'
240 import MainContentHeader from '../../common/SbsFormConstruction/MainContent/parts/MainContentHeader.vue'
241 import MainContentFooter from '../../common/SbsFormConstruction/MainContent/parts/MainContentFooter'
242 import SideBar from '../../common/SbsFormConstruction/SideBar/SideBar.vue'
243 import BackLink from '../Parts/BackLink'
244
245 // * Step components
246 import InitStep from './InitStep/InitStep.vue'
247 import BringingAnyone from "./BringingAnyone/BringingAnyone"
248 import Extras from './Extras/Extras.vue'
249 import PackageInfo from './PakagesStep/PackageInfoStep'
250 import DateTimeStep from './DateTimeStep/DateTimeStep.vue'
251 import PackageAppointmentsStep from './PakagesStep/PackageAppointmentsStep.vue'
252 import PackageAppointmentsListStep from './PakagesStep/PackageAppointmentsListStep.vue'
253 import CartStep from './CartStep/CartStep.vue'
254 import InfoStep from './InfoStep/InfoStep.vue'
255 import Congratulations from './Congratulations/Congratulations.vue'
256 import AddToCalendar from './Congratulations/AddToCalendar.vue'
257 import PaymentStep from './PaymentStep/PaymentStep.vue'
258 import PackagesStep from './PakagesStep/PackageStep'
259 import RecurringStep from "./RecurringStep/RecurringStep";
260 import RecurringSummary from "./RecurringStep/RecurringSummary";
261
262 // * import from Vue
263 import {
264 ref,
265 reactive,
266 watch,
267 provide,
268 inject,
269 markRaw,
270 computed,
271 onMounted,
272 watchEffect,
273 nextTick
274 } from 'vue'
275 // * import from Vuex
276 import { useStore } from 'vuex'
277 // * import composable
278 import useRestore from '../../../assets/js/public/restore'
279 import { useBuildPackage } from '../../../assets/js/public/package.js'
280 import { defaultCustomizeSettings } from '../../../assets/js/common/defaultCustomize.js'
281 import useAction from "../../../assets/js/public/actions";
282 import { useRenderAction } from "../../../assets/js/public/renderActions.js";
283 import { useColorTransparency } from "../../../assets/js/common/colorManipulation";
284 import { usePrepaidPrice, useCapacity } from '../../../assets/js/common/appointments'
285 import {
286 useCart,
287 useCartStep,
288 useInitCartItem,
289 useCartHasItems,
290 useInitSelection,
291 useAddToCart,
292 useGoToCartStep
293 } from '../../../assets/js/public/cart'
294
295 // * Emits
296 const emits = defineEmits(['isRestored'])
297
298 let formDialogVisibility = inject('formDialogVisibility', ref(true))
299
300 // * Global flag for determination when component is fully loaded (used for Amelia popup)
301 let isMounted = inject('isMounted')
302
303 // * Plugin Licence
304 let licence = inject('licence')
305
306 // * Component reference
307 let ameliaContainer = ref(null)
308 // * Plugin wrapper width
309 let containerWidth = ref()
310 provide('containerWidth', containerWidth)
311
312 let empty = ref(false)
313
314 // * window resize listener
315 window.addEventListener('resize', resize);
316 // * resize function
317 function resize() {
318 if (ameliaContainer.value) {
319 containerWidth.value = ameliaContainer.value.offsetWidth
320 }
321 }
322
323 onMounted(() => {
324 store.commit('shortcodeParams/setForm', 'stepForm')
325
326 document.getElementById(
327 'amelia-v2-booking-' + shortcodeData.value.counter
328 ).classList.add('amelia-v2-booking-' + shortcodeData.value.counter + '-loaded')
329
330 useAction(store, {}, 'ViewContent', 'appointment', null, null)
331
332 nextTick(() => {
333 containerWidth.value = ameliaContainer.value.offsetWidth
334 })
335
336 useAction(store, {containerWidth}, 'ContainerWidth', 'appointment', null, null)
337
338 isMounted.value = true
339 })
340
341 // * Root Settings
342 const amSettings = inject('settings')
343
344 // * Customize
345 const amCustomize = amSettings.customizedData ? amSettings.customizedData.sbsNew : defaultCustomizeSettings.sbsNew
346 if (amCustomize) {
347 provide('amCustomize', amCustomize)
348 }
349
350 let footerCustomizeOptions = computed(() => {
351 let obj = {
352 heading: true,
353 phone: true,
354 email: true
355 }
356
357 if ('supportHeading' in amCustomize.sidebar.options) {
358 obj.heading = amCustomize.sidebar.options.supportHeading.visibility
359 }
360
361 if ('companyPhone' in amCustomize.sidebar.options) {
362 obj.phone = amCustomize.sidebar.options.companyPhone.visibility
363 }
364
365 if ('companyEmail' in amCustomize.sidebar.options) {
366 obj.email = amCustomize.sidebar.options.companyEmail.visibility
367 }
368
369 return obj
370 })
371
372 // * Fonts
373 const amFonts = ref(amSettings.customizedData ? amSettings.customizedData.fonts : defaultCustomizeSettings.fonts)
374 provide('amFonts', amFonts)
375
376 // * Dialog width
377 let dialogWrapperWidth = inject('dialogWrapperWidth', ref(''))
378
379 // * Form Sidebar Collapse
380 let sidebarCollapsed = ref(false)
381 provide('sidebarCollapsed', sidebarCollapsed)
382
383 let sidebarCollapseItemsClass = ref('')
384
385 watch(sidebarCollapsed ,(current) => {
386 if (current) {
387 setTimeout(() => {
388 sidebarCollapseItemsClass.value = 'am-collapsed'
389 dialogWrapperWidth.value = '592px'
390 }, 1000)
391 } else {
392 sidebarCollapseItemsClass.value = ''
393 dialogWrapperWidth.value = '760px'
394 }
395 })
396
397 let sidebarFooterRef = ref(null)
398 let sidebarFooterHeight = ref(0)
399
400 // * Form Sidebar Visibility
401 let sidebarVisibility = ref(amCustomize.sidebar ? amCustomize.sidebar.options.self.visibility : true)
402
403 // * Root Urls
404 const baseUrls = inject('baseUrls')
405
406 // * Define store
407 const store = useStore()
408
409 let ready = computed(() => store.getters['entities/getReady'])
410
411 let isRestored = ref(false)
412
413 watch(ready, (current) => {
414 if (current) {
415
416 nextTick(() => {
417 if(sidebarFooterRef.value) {
418 setTimeout(() => {
419 sidebarFooterHeight.value = sidebarFooterRef.value.offsetHeight
420 }, 200)
421 }
422 })
423
424 setShortcodeParams()
425
426 let preselected = store.getters['entities/getPreselected']
427 empty.value = store.getters['entities/getServices'].length === 0 ||
428 store.getters['entities/getEmployees'].length === 0 ||
429 (store.getters['entities/getPackages'].length === 0 && (shortcodeData.value.show === 'packages' || preselected.package.length > 0))
430
431 let restore = useRestore(store, shortcodeData.value)
432
433 if (restore) {
434 stepsArray.value.splice(0, stepsArray.value.length)
435
436 sidebarSteps.value.splice(0, sidebarSteps.value.length)
437
438 stepIndex.value = 0
439
440 restore.steps.forEach((key) => {
441 switch (key) {
442 case ('packageStep'):
443 stepsArray.value.push(packagesStep)
444 break
445
446 case ('bringingAnyone'):
447 stepsArray.value.push(bringingAnyone)
448 break
449
450 case ('initStep'):
451 stepsArray.value.push(initStep)
452 break
453
454 case ('packageInfoStep'):
455 stepsArray.value.push(packageInfoStep)
456 break
457
458 case ('packageAppointmentsStep'):
459 stepsArray.value.push(packageAppointmentsStep)
460 break
461
462 case ('packageAppointmentsListStep'):
463 stepsArray.value.push(packageAppointmentsListStep)
464 break
465
466 case ('extrasStep'):
467 stepsArray.value.push(extras)
468 break
469
470 case ('dateTimeStep'):
471 stepsArray.value.push(dateTimeStep)
472 break
473
474 case ('recurringStep'):
475 stepsArray.value.push(recurringStep)
476 break
477
478 case ('recurringSummary'):
479 stepsArray.value.push(recurringSummary)
480 break
481
482 case ('cartStep'):
483 stepsArray.value.push(cartStep)
484 break
485
486 case ('infoStep'):
487 stepsArray.value.push(infoStep)
488 break
489
490 case ('paymentStep'):
491 stepsArray.value.push(paymentStep)
492 break
493
494 case ('congratulations'):
495 stepsArray.value.push(congratulationsStep)
496 break
497 }
498
499 let sideBarItem = restore.sidebar.find(i => i.key === key)
500
501 sidebarDataUpdate()
502
503 if (typeof sideBarItem !== 'undefined') {
504 if (sideBarItem.data) {
505 sideBarItem.data.forEach((i) => {
506 sidebarDataCollector({
507 reference: i.reference,
508 position: i.position,
509 value: i.value
510 })
511 })
512 }
513 }
514
515 stepIndex.value++
516 })
517
518 store.commit('booking/setLoading', false)
519
520 let index = -1
521
522 if (restore.result === 'success') {
523 index = stepsArray.value.length - 1
524 } else if (restore.result === 'error' || restore.result === 'canceled') {
525 index = stepsArray.value.length - 2
526 }
527
528 for (let i = 0; i <= index; i++) {
529 stepsArray.value[i].finished = true
530 }
531
532 for (let i = 0; i <= index - 1; i++) {
533 sidebarSteps.value[i].finished = true
534 sidebarSteps.value[i].selected = false
535 }
536 if (restore.result === 'error' || restore.result === 'canceled') {
537 sidebarSteps.value[index].finished = false
538 sidebarSteps.value[index].selected = true
539 }
540
541 isRestored.value = true
542 emits('isRestored', isRestored.value)
543
544 stepIndex.value = index
545 }
546 }
547 })
548
549 const shortcodeData = inject('shortcodeData')
550
551 store.commit('entities/setPreselected', shortcodeData.value)
552
553 // * Get Entities from server
554 store.dispatch(
555 'entities/getEntities',
556 {
557 types: [
558 'employees',
559 'categories',
560 'locations',
561 'packages',
562 'entitiesRelations',
563 'customFields',
564 'taxes',
565 ],
566 licence: licence,
567 loadEntities: !shortcodeData.value.trigger ? (window.ameliaShortcodeData.filter(i => !i.hasApiCall).length === window.ameliaShortcodeData.length
568 ? true : shortcodeData.value.hasApiCall) : true,
569 showHidden: false,
570 isPanel: false,
571 }
572 )
573
574 // * Form Component Collection
575 const initStep = markRaw(InitStep)
576 const extras = markRaw(Extras)
577 const packageInfoStep = markRaw(PackageInfo)
578 const recurringStep = markRaw(RecurringStep)
579 const recurringSummary = markRaw(RecurringSummary)
580 const dateTimeStep = markRaw(DateTimeStep)
581 const packageAppointmentsStep = markRaw(PackageAppointmentsStep)
582 const packageAppointmentsListStep = markRaw(PackageAppointmentsListStep)
583 const congratulationsStep = markRaw(Congratulations)
584 const cartStep = markRaw(CartStep)
585 const infoStep = markRaw(InfoStep)
586 const paymentStep = markRaw(PaymentStep)
587 const packagesStep = markRaw(PackagesStep)
588 const bringingAnyone = markRaw(BringingAnyone)
589
590 // * Array of step components
591 const stepsArray = ref(
592 useCartStep(store) ? [
593 initStep,
594 dateTimeStep,
595 cartStep,
596 infoStep,
597 congratulationsStep
598 ] : [
599 initStep,
600 dateTimeStep,
601 infoStep,
602 congratulationsStep
603 ]
604 )
605
606 provide('stepsArray', stepsArray)
607
608 // * labels
609 const labels = inject('labels')
610
611 // * local language short code
612 const localLanguage = inject('localLanguage')
613
614 // * if local lang is in settings lang
615 let langDetection = computed(() => amSettings.general.usedLanguages.includes(localLanguage.value))
616
617 let cart = useCart(store)
618
619 // * Computed labels
620 let amLabels = computed(() => {
621 let computedLabels = reactive({...labels})
622
623 if (amSettings.customizedData) {
624 Object.keys(amSettings.customizedData.sbsNew).forEach(stepKey => {
625 if (stepKey !== 'colors' && amSettings.customizedData.sbsNew[stepKey].translations) {
626 let customizedLabels = amSettings.customizedData.sbsNew[stepKey].translations
627 Object.keys(customizedLabels).forEach(labelKey => {
628 if (customizedLabels[labelKey][localLanguage.value] && langDetection.value) {
629 computedLabels[labelKey] = customizedLabels[labelKey][localLanguage.value]
630 } else if (customizedLabels[labelKey].default) {
631 computedLabels[labelKey] = customizedLabels[labelKey].default
632 }
633 })
634 }
635 })
636 }
637 return computedLabels
638 })
639
640 provide('amLabels', amLabels)
641
642 let footerLabels = computed(() => {
643 let customLabels = {}
644 if (amSettings.customizedData) {
645 let customizedLabels = amSettings.customizedData.sbsNew[stepsArray.value[stepIndex.value].key] ?
646 amSettings.customizedData.sbsNew[stepsArray.value[stepIndex.value].key].translations :
647 null
648 if (amSettings.customizedData && customizedLabels) {
649 Object.keys(customizedLabels).forEach(labelKey => {
650 if (customizedLabels[labelKey][localLanguage.value] && langDetection.value) {
651 customLabels[labelKey] = customizedLabels[labelKey][localLanguage.value]
652 } else if (customizedLabels[labelKey].default) {
653 customLabels[labelKey] = customizedLabels[labelKey].default
654 }
655 })
656 }
657 }
658
659 return Object.keys(customLabels).length ? customLabels : labels
660 })
661
662 let primFooterBtnType = computed(() => {
663 let btnType = 'filled'
664 if (amSettings.customizedData && amSettings.customizedData.sbsNew[stepsArray.value[stepIndex.value].key]) {
665 btnType = amSettings.customizedData.sbsNew[stepsArray.value[stepIndex.value].key].options.primaryFooterButton.buttonType
666 }
667
668 return btnType
669 })
670
671 provide('primFooterBtnType', primFooterBtnType)
672
673 provide('primDescBtnType', primFooterBtnType)
674
675 let secFooterBtnType = computed(() => {
676 let btnType = 'text'
677 if (
678 amSettings.customizedData &&
679 amSettings.customizedData.sbsNew[stepsArray.value[stepIndex.value].key] &&
680 amSettings.customizedData.sbsNew[stepsArray.value[stepIndex.value].key].options.secondaryFooterButton
681 ) {
682 btnType = amSettings.customizedData.sbsNew[stepsArray.value[stepIndex.value].key].options.secondaryFooterButton.buttonType
683 }
684
685 return btnType
686 })
687
688 let addToCartBtnType = computed(() => {
689 if (amSettings.customizedData && amSettings.customizedData.sbsNew['cartStep']) {
690 return amSettings.customizedData.sbsNew['cartStep'].options['addToCart'].buttonType
691 }
692
693 return 'text'
694 })
695
696 let backToCartBtnType = computed(() => {
697 if (amSettings.customizedData && amSettings.customizedData.sbsNew['cartStep']) {
698 return amSettings.customizedData.sbsNew['cartStep'].options['backToCart'].buttonType
699 }
700
701 return 'text'
702 })
703
704 function dedicatedStepLabel (labelKey, stepKey) {
705 let customLabel = ''
706 if (amSettings.customizedData) {
707 let customizedLabels = amSettings.customizedData.sbsNew[stepKey] ?
708 amSettings.customizedData.sbsNew[stepKey].translations :
709 null
710 if (amSettings.customizedData && customizedLabels && customizedLabels[labelKey]) {
711 if (customLabel === '' && customizedLabels[labelKey][localLanguage.value] && langDetection.value) {
712 customLabel = customizedLabels[labelKey][localLanguage.value]
713 } else if (customLabel === '' && customizedLabels[labelKey].default) {
714 customLabel = customizedLabels[labelKey].default
715 }
716 }
717 }
718
719 return customLabel ? customLabel : labels[labelKey]
720 }
721
722 let bringingAnyoneOptions = computed(() => {
723 return useCapacity(
724 store.getters['entities/getEmployeeServices'](
725 store.getters['booking/getSelection']
726 )
727 )
728 })
729
730 function setShortcodeParams () {
731 let preselected = store.getters['entities/getPreselected']
732 if (preselected.category.length === 1) {
733 store.commit('booking/setCategoryId', parseInt(preselected.category[0]))
734 }
735 if (preselected.service.length === 1) {
736 store.commit('booking/setServiceId', parseInt(preselected.service[0]))
737 let service = store.getters['entities/getService'](parseInt(preselected.service[0]))
738 store.commit('booking/setCategoryId', service ? parseInt(service.categoryId) : null)
739 }
740 if (preselected.employee.length === 1) {
741 store.commit('booking/setEmployeeId', parseInt(preselected.employee[0]))
742 }
743 if (preselected.location.length === 1) {
744 store.commit('booking/setLocationId', parseInt(preselected.location[0]))
745 }
746 if (preselected.package.length === 1) {
747 store.commit('booking/setPackageId', parseInt(preselected.package[0]))
748 }
749
750 if (preselected.package.length === 1) {
751 stepsArray.value.splice(0, 1, packageInfoStep);
752 sidebarSteps.value.splice(0, 1)
753 sidebarDataUpdate()
754 let selectedPackage = store.getters["entities/filteredPackages"](store.getters['booking/getSelection'])[0]
755 if (selectedPackage) {
756 goToPackageStep(selectedPackage, false)
757 }
758 } else if (preselected.show === 'packages' || preselected.package.length > 1) {
759 stepsArray.value.splice(0, 1, packagesStep);
760 sidebarSteps.value.splice(0, 1)
761 store.commit('booking/setBookableType', 'package')
762 sidebarDataUpdate()
763 } else {
764 changeInitStepDataService()
765 store.commit('booking/setBookableType', 'appointment')
766 let employeeOptions = store.getters["entities/filteredEmployees"](store.getters['booking/getSelection']).length <= 1
767 let employeeVisibility = !amCustomize.initStep.options.employee.visibility
768 let locationOptions = store.getters['entities/filteredLocations'](store.getters['booking/getSelection']).length <= 1
769 let locationVisibility = !amCustomize.initStep.options.location.visibility
770
771 if (
772 preselected.service.length === 1 &&
773 (preselected.employee.length === 1 || employeeOptions || employeeVisibility) &&
774 (preselected.location.length === 1 || locationOptions || locationVisibility)
775 ) {
776 if (bringingAnyoneOptions.value.availability) {
777 stepsArray.value.splice(0, 1, bringingAnyone);
778 sidebarSteps.value.splice(0, 1)
779 } else {
780 stepsArray.value.splice(0, 1)
781 sidebarSteps.value.splice(0, 1)
782 }
783 sidebarDataUpdate()
784 }
785 }
786 }
787
788 function stepChanger (steps, stepsNamesToRemove, stepsToAdd, startIndex) {
789 let removeIndexes = steps.value.map(
790 (item, index) => (stepsNamesToRemove.includes(item.name)) ? index : null
791 ).filter(item => item !== null).reverse()
792
793 removeIndexes.forEach((item) => {
794 steps.value.splice(item, 1)
795 })
796
797 stepsToAdd.forEach((item) => {
798 if (steps.value.indexOf(item) === -1) {
799 steps.value.splice(startIndex + 1, 0, item)
800 }
801 })
802 }
803
804 provide('goToPackageStep', {goToPackageStep})
805
806 function goToPackageStep (pack, goToNextStep = true) {
807 store.commit('booking/setPackageId', pack.id)
808 store.commit('booking/setBookableType', 'package')
809 store.commit('booking/setMultipleAppointments', useBuildPackage(0, pack))
810 store.commit('booking/setMultipleAppointmentsIndex', 0)
811
812 let bookingCount = pack.bookable.reduce((partialSum, book) => partialSum + book.maximumScheduled, 0)
813
814 let removeSteps = []
815 let addSteps = []
816
817 if (stepsArray.value[0] !== extras) {
818 removeSteps.push('ExtrasStep')
819 }
820
821 if (stepsArray.value[0] !== dateTimeStep) {
822 removeSteps.push('DateTimeStep')
823 }
824
825 if (stepsArray.value[0] !== cartStep) {
826 removeSteps.push('CartStep')
827 }
828
829 if (bookingCount > 0) {
830 addSteps = addSteps.concat([packageAppointmentsListStep, packageAppointmentsStep, packageInfoStep])
831 } else {
832 addSteps.push(packageInfoStep)
833 }
834
835 stepChanger(
836 stepsArray,
837 removeSteps,
838 addSteps,
839 stepIndex.value
840 )
841
842 stepChanger(
843 sidebarSteps,
844 removeSteps,
845 [],
846 stepIndex.value
847 )
848
849 sidebarDataUpdate()
850
851 if (goToNextStep) {
852 nextStep()
853 }
854 }
855
856 function removePackageStep () {
857 store.commit('booking/setBookableType', 'appointment')
858
859 store.commit('booking/setMultipleAppointments', [
860 {
861 packageId: null,
862 serviceId: null,
863 index: 0,
864 services: {},
865 }
866 ])
867
868 store.commit('booking/setPackageId', null)
869
870 store.commit('booking/setMultipleAppointmentsIndex', 0)
871
872 useInitCartItem(store)
873
874 let addSteps = []
875
876 if (stepsArray.value[0] !== dateTimeStep) {
877 if (useCartStep(store)) {
878 addSteps.push(cartStep)
879 }
880
881 addSteps.push(dateTimeStep)
882 }
883
884 if (stepsArray.value[0] !== extras && selectedServiceExtras.value && selectedServiceExtras.value.length) {
885 addSteps.push(extras)
886 }
887
888 stepChanger(
889 stepsArray,
890 ['PackageInfoStep', 'PackageAppointmentsStep', 'PackageAppointmentsListStep'],
891 addSteps,
892 stepIndex.value - 1
893 )
894
895 stepChanger(
896 sidebarSteps,
897 ['PackageInfoStep', 'PackageAppointmentsStep', 'PackageAppointmentsListStep'],
898 [],
899 stepIndex.value
900 )
901
902 sidebarDataUpdate()
903 }
904
905 provide('goToRecurringStep', {goToRecurringStep})
906
907 provide('removeRecurringStep', {removeRecurringStep})
908
909 function goToRecurringStep () {
910 if (useCartStep(store)) {
911 removeCartStep()
912 }
913
914 let startIndex = 0
915
916 for (let i = 0; i < stepsArray.value.length; i++) {
917 if (stepsArray.value[i].name === 'DateTimeStep') {
918 startIndex = i
919
920 break
921 }
922 }
923
924 stepsArray.value.splice( startIndex + 1, 0, recurringStep)
925 stepsArray.value.splice( startIndex + 2, 0, recurringSummary)
926
927 sidebarDataUpdate()
928
929 nextStep()
930 }
931
932 function removeRecurringStep () {
933 for (let i = stepsArray.value.length - 1; i >= 0; i--) {
934 if (stepsArray.value[i].name === 'RecurringStep' || stepsArray.value[i].name === 'RecurringSummary') {
935 stepsArray.value.splice( i + 1, 1)
936 }
937 }
938
939 if (useCartStep(store)) {
940 addCartStep(stepIndex.value)
941 }
942
943 sidebarDataUpdate()
944 }
945
946 provide('addPaymentsStep', {addPaymentsStep})
947
948 provide('removePaymentsStep', {removePaymentsStep})
949
950 function addPaymentsStep () {
951 stepsArray.value.splice(stepsArray.value.length - 1, 0, paymentStep)
952
953 sidebarDataUpdate()
954 }
955
956 function removePaymentsStep () {
957 let removeSteps = ['PaymentStep']
958
959 stepChanger(
960 stepsArray,
961 removeSteps,
962 [],
963 stepIndex.value
964 )
965
966 stepChanger(
967 sidebarSteps,
968 removeSteps,
969 [],
970 stepIndex.value
971 )
972 }
973
974 function addCartStep (index) {
975 stepChanger(
976 stepsArray,
977 [],
978 [cartStep],
979 index
980 )
981
982 stepChanger(
983 sidebarSteps,
984 [],
985 [],
986 index
987 )
988 }
989
990 function removeCartStep () {
991 stepChanger(
992 stepsArray,
993 ['CartStep'],
994 [],
995 stepIndex.value
996 )
997
998 stepChanger(
999 sidebarSteps,
1000 ['CartStep'],
1001 [],
1002 stepIndex.value
1003 )
1004 }
1005
1006 /**
1007 * Detect if Selected Service has Extras
1008 * @type {any}
1009 */
1010 let selectedServiceExtras = computed(() => {
1011 let service = store.getters['entities/getService'](
1012 store.getters['booking/getServiceId']
1013 )
1014
1015 return service ? service.extras : []
1016 })
1017
1018 /**
1019 * Add or Remove steps from Steps Array
1020 */
1021 function changeInitStepDataService () {
1022 if (selectedServiceExtras.value.length && !stepsArray.value.find(step => step.name === 'ExtrasStep')) {
1023 stepsArray.value.splice( stepIndex.value + 1, 0, extras)
1024
1025 sidebarDataUpdate()
1026 }
1027
1028 if (sidebarSteps.value.find(step => step.name === 'ExtrasStep') && !Object.keys(selectedServiceExtras.value).length) {
1029 stepsArray.value.splice(1, 1)
1030 sidebarSteps.value.splice(1, 1)
1031 }
1032
1033 useInitCartItem(store)
1034 }
1035
1036 provide('initDataChanges', {
1037 changeInitStepDataService
1038 })
1039
1040 // * Step index
1041 const stepIndex = ref(0)
1042 // * StepIndex provide
1043 provide('stepIndex', stepIndex)
1044
1045 // * Monitoring step index for step selection
1046 watch(stepIndex, (currStepIndex, prevStepIndex) => {
1047 if (currStepIndex < sidebarSteps.value.length) {
1048 sidebarSteps.value[prevStepIndex].selected = false
1049 sidebarSteps.value[currStepIndex].selected = true
1050 }
1051
1052 if (currStepIndex === sidebarSteps.value.length) {
1053 sidebarSteps.value[prevStepIndex].selected = false
1054 }
1055 })
1056
1057 let goBackToPackageBooking = ref(false)
1058 provide('goBackToPackageBooking', goBackToPackageBooking)
1059
1060 /**
1061 * Move to previous Form Step
1062 */
1063 function previousStep () {
1064 footerBtnDisabledUpdater(false)
1065
1066 if (!navigateInsideStep.value) {
1067 if (stepsArray.value[stepIndex.value].name === packageInfoStep.name) {
1068 removePackageStep()
1069 }
1070
1071 if (stepsArray.value[stepIndex.value].name === recurringStep.name) {
1072 stepsArray.value.splice(stepIndex.value, 2)
1073 sidebarSteps.value.splice(stepIndex.value, 2)
1074
1075 if (useCartStep(store)) {
1076 stepsArray.value.splice(stepIndex.value, 0, cartStep)
1077
1078 stepChanger(
1079 sidebarSteps,
1080 [],
1081 [],
1082 stepIndex.value
1083 )
1084
1085 sidebarDataUpdate()
1086 }
1087 }
1088
1089 if (stepsArray.value[stepIndex.value].name === packageAppointmentsListStep.name) {
1090 goBackToPackageBooking.value = true
1091 }
1092
1093 stepIndex.value = stepIndex.value - 1
1094 }
1095
1096 headerButtonPreviousClicked.value = !headerButtonPreviousClicked.value
1097 }
1098
1099 /**
1100 * Move to next Form Step
1101 */
1102 function nextStep () {
1103 if (!navigateInsideStep.value) {
1104 sidebarSteps.value[stepIndex.value].finished = true
1105 stepIndex.value = stepIndex.value + 1
1106 }
1107 }
1108
1109 // * Footer states
1110 let loading = computed(() => store.getters['booking/getLoading'])
1111 let booked = computed(() => store.getters['booking/getBooked'])
1112 let paymentGateway = computed(() => store.getters['booking/getPaymentGateway'])
1113
1114 // * Footer btn flag
1115 let footerButtonClicked = ref(false)
1116 let footerBtnDisabled = ref(false)
1117
1118 let headerButtonPreviousClicked = ref(false)
1119
1120 /**
1121 * Footer btn clicked
1122 */
1123 function footerButtonClick () {
1124 footerButtonClicked.value = true
1125 }
1126
1127 /**
1128 * Footer btn reset
1129 */
1130 function footerButtonReset () {
1131 footerButtonClicked.value = false
1132 }
1133
1134 /**
1135 * Header btn previous clicked
1136 */
1137 function headerButtonPreviousClick () {
1138 headerButtonPreviousClicked.value = true
1139 }
1140
1141 /**
1142 * Header btn previous reset
1143 */
1144 function headerButtonPreviousReset () {
1145 headerButtonPreviousClicked.value = false
1146 }
1147
1148 function footerBtnDisabledUpdater (data) {
1149 footerBtnDisabled.value = data
1150 }
1151
1152 function secondButtonClick() {
1153 if (booked.value) {
1154 if (booked.value.customerCabinetUrl) {
1155 window.location.href = booked.value.customerCabinetUrl
1156 } else {
1157 window.location.href = amSettings.roles.customerCabinet.pageUrl
1158 }
1159 }
1160 }
1161
1162 provide('secondButton', {
1163 secondButtonClick
1164 })
1165
1166 let navigateInsideStep = ref(false)
1167
1168 provide('changingStepsFunctions', {
1169 nextStep,
1170 previousStep,
1171 footerButtonClick,
1172 footerButtonReset,
1173 footerBtnDisabledUpdater,
1174 headerButtonPreviousClick,
1175 headerButtonPreviousReset,
1176 footerBtnDisabled,
1177 footerButtonClicked,
1178 headerButtonPreviousClicked,
1179 navigateInsideStep,
1180 })
1181
1182 // * Array of Sidebar steps
1183 const sidebarSteps = ref([])
1184 provide('sidebarSteps', sidebarSteps)
1185
1186
1187 function checkIfAllNotFree () {
1188 let preselected = store.getters['entities/getPreselected']
1189
1190 if (preselected.show === 'packages' || preselected.package.length > 0) {
1191 let packages = store.getters['entities/getPackages']
1192 if (store.getters['booking/getPackageId']) {
1193 let selectedPackage = store.getters['entities/getPackage'](store.getters['booking/getPackageId'])
1194 if (selectedPackage) {
1195 packages = [selectedPackage]
1196 } else {
1197 return true
1198 }
1199 }
1200 return packages.length > 0 && packages.filter(p => p.price > 0).length === packages.length
1201 }
1202
1203 if (!store.getters['booking/getPackageId']) {
1204 let services = store.getters['booking/getServiceId']
1205 ? [store.getters['entities/getService'](store.getters['booking/getServiceId'])]
1206 : store.getters['entities/getServices']
1207
1208 let nonFreeServices = 0
1209 for (let service of services) {
1210 let employees = store.getters['booking/getEmployeeId']
1211 ? (store.getters['entities/getEmployee'](store.getters['booking/getEmployeeId']) ? [store.getters['entities/getEmployee'](store.getters['booking/getEmployeeId'])] : [])
1212 : store.getters['entities/getEmployees']
1213
1214 let duration = store.getters['booking/getBookingDuration']
1215
1216 let providers = employees.filter(eS => eS.serviceList.find(s => s.id === service.id && (s.price > 0 ||
1217 (s.customPricing && s.customPricing.enabled &&
1218 (Object.values(s.customPricing.durations).length === Object.values(s.customPricing.durations).filter(cp => cp.price > 0).length ||
1219 (duration && s.customPricing.durations[duration].price > 0)
1220 )
1221 ))
1222 ))
1223
1224 if (providers.length === employees.filter(eS => eS.serviceList.find(s => s.id === service.id)).length) {
1225 nonFreeServices++
1226 } else {
1227 let extras = store.getters['booking/getAllMultipleAppointments'].length
1228 ? store.getters['booking/getSelectedExtras']
1229 : []
1230
1231 if (extras.length > 0 && extras.reduce((partialSum, a) => partialSum + a.price, 0) > 0) {
1232 nonFreeServices++
1233 }
1234 }
1235 }
1236
1237 return services.length > 0 && nonFreeServices === services.length
1238 }
1239
1240 return store.getters['entities/getPackage'](store.getters['booking/getPackageId']).price > 0
1241 }
1242
1243 let keepPaymentStep = computed(() => useCart(store).length ? usePrepaidPrice(store) !== 0 : checkIfAllNotFree())
1244
1245 watchEffect(() => {
1246 if (!isRestored.value && !keepPaymentStep.value) {
1247 removePaymentsStep()
1248 } else if (!isRestored.value) {
1249 if (stepsArray.value.indexOf(paymentStep) === -1) {
1250 addPaymentsStep()
1251 }
1252 }
1253 })
1254
1255 /**
1256 * Collecting and rearranging selected data in form sidebar based on item position in form
1257 * @param data
1258 */
1259 function sidebarDataCollector (data) {
1260 // Determines are selected data already exists
1261 if (sidebarSteps.value[stepIndex.value].stepSelectedData.filter(item => item.reference === data.reference).length) {
1262 sidebarSteps.value[stepIndex.value].stepSelectedData.forEach((item, index, array) => {
1263 // Handles changing value of existing data
1264 if ((item.reference === data.reference) && data.value && data.value !== item.value) {
1265 item.value = data.value
1266 }
1267
1268 // Removes un-selected form data from sidebar array
1269 if ((item.reference === data.reference) && !data.value) {
1270 array.splice(index, 1)
1271 }
1272 })
1273 } else {
1274 if (data.value) {
1275 sidebarSteps.value[stepIndex.value].stepSelectedData.push(data)
1276 }
1277 }
1278
1279 // Rearranges data in sidebar based on item position in the form
1280 sidebarSteps.value[stepIndex.value].stepSelectedData.sort((a, b) => {
1281 return a.position - b.position
1282 })
1283 }
1284
1285 /**
1286 * Function that update SideBar Data Array when some component are dynamically added
1287 */
1288 function sidebarDataUpdate () {
1289 stepsArray.value.forEach((item, index) => {
1290 if (item.name === 'CongratulationsStep') {
1291 return
1292 }
1293 if (!sidebarSteps.value.find(block => block.labelKey === item.sidebarData.label)) {
1294 let labelKey = item.sidebarData.label
1295 let step = {
1296 name: item.name,
1297 key: item.key,
1298 label: amLabels.value[labelKey],
1299 labelKey: labelKey,
1300 icon: item.sidebarData.icon,
1301 stepSelectedData: [],
1302 finished: false,
1303 selected: index === stepIndex.value,
1304 }
1305 sidebarSteps.value.splice(index, 0, step)
1306 }
1307 })
1308 }
1309 provide('sidebarStepsFunctions', {
1310 sidebarDataCollector
1311 })
1312
1313 // * Cart
1314 function addToCart () {
1315 sidebarSteps.value.forEach((item) => {
1316 item.finished = false
1317 item.selected = false
1318 })
1319
1320 stepsArray.value.forEach((item) => {
1321 item.finished = false
1322 item.selected = false
1323 })
1324
1325 stepIndex.value = 0
1326
1327 useInitSelection(store, true)
1328
1329 useAddToCart(store)
1330
1331 useInitCartItem(store)
1332 }
1333
1334 function backToCart () {
1335 let currentCartItem = store.getters['booking/getCurrentCartItem']
1336
1337 let items = store.getters['booking/getAllMultipleAppointments']
1338
1339 if (currentCartItem) {
1340 store.commit('booking/setCartItem', currentCartItem)
1341
1342 store.commit('booking/setCartItemIndex', items.length - 1)
1343
1344 store.commit('booking/setCurrentCartItem', null)
1345 } else {
1346 items.pop()
1347
1348 store.commit('booking/setCartItemIndex', items.length - 1)
1349
1350 store.commit('booking/setServiceId', items[items.length - 1].serviceId)
1351
1352 store.commit('booking/setEmployeeId', items[items.length - 1].services[items[items.length - 1].serviceId].providerId)
1353
1354 store.commit('booking/setLocationId', items[items.length - 1].services[items[items.length - 1].serviceId].locationId)
1355 }
1356
1357 useGoToCartStep(stepsArray, stepIndex)
1358 }
1359
1360 // * Colors block
1361 let amColors = computed(() => {
1362 return amSettings.customizedData ? amSettings.customizedData.sbsNew.colors : defaultCustomizeSettings.sbsNew.colors
1363 })
1364 provide('amColors', amColors);
1365
1366 let cssVars = computed(() => {
1367 return {
1368 '--am-c-primary': amColors.value.colorPrimary,
1369 '--am-c-success': amColors.value.colorSuccess,
1370 '--am-c-error': amColors.value.colorError,
1371 '--am-c-warning': amColors.value.colorWarning,
1372 '--am-c-main-bgr': amColors.value.colorMainBgr,
1373 '--am-c-main-heading-text': amColors.value.colorMainHeadingText,
1374 '--am-c-main-text': amColors.value.colorMainText,
1375 '--am-c-sb-bgr': amColors.value.colorSbBgr,
1376 '--am-c-sb-text': amColors.value.colorSbText,
1377 '--am-c-inp-bgr': amColors.value.colorInpBgr,
1378 '--am-c-inp-border': amColors.value.colorInpBorder,
1379 '--am-c-inp-text': amColors.value.colorInpText,
1380 '--am-c-inp-placeholder': amColors.value.colorInpPlaceHolder,
1381 '--am-c-drop-bgr': amColors.value.colorDropBgr,
1382 '--am-c-drop-text': amColors.value.colorDropText,
1383 '--am-c-btn-prim': amColors.value.colorBtnPrim,
1384 '--am-c-btn-prim-text': amColors.value.colorBtnPrimText,
1385 '--am-c-btn-sec': amColors.value.colorBtnSec,
1386 '--am-c-btn-sec-text': amColors.value.colorBtnSecText,
1387 '--am-c-skeleton-op20': useColorTransparency(amColors.value.colorMainText, 0.2),
1388 '--am-c-skeleton-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
1389 '--am-c-skeleton-sb-op20': useColorTransparency(amColors.value.colorSbText, 0.2),
1390 '--am-c-skeleton-sb-op60': useColorTransparency(amColors.value.colorSbText, 0.6),
1391 '--am-font-family': amFonts.value.fontFamily,
1392
1393 // css properties
1394 // -mw- max width
1395 // -brad- border-radius
1396 '--am-mw-main': sidebarVisibility.value ? sidebarCollapsed.value ? '592px' : '760px' : '520px',
1397 '--am-brad-main': sidebarVisibility.value ? '0 0.5rem 0.5rem 0' : '0.5rem'
1398 }
1399 })
1400
1401 function activateCustomFontStyles () {
1402 let head = document.head || document.getElementsByTagName('head')[0]
1403 if (head.querySelector('#amCustomFont')) {
1404 head.querySelector('#amCustomFont').remove()
1405 }
1406
1407 let css = `@font-face {font-family: '${amFonts.value.fontFamily}'; src: url(${amFonts.value.fontUrl});}`
1408 let style = document.createElement('style')
1409 head.appendChild(style)
1410 style.setAttribute('type', 'text/css')
1411 style.setAttribute('id', 'amCustomFont')
1412 style.appendChild(document.createTextNode(css))
1413 }
1414
1415 if (amFonts.value.customFontSelected) activateCustomFontStyles()
1416
1417 // * Design Properties
1418 let amDesignProperties = computed(() => {
1419 return {
1420 colorInputBorderRadius: '6px',
1421 }
1422 })
1423 provide('amDesignProperties', amDesignProperties);
1424
1425 onMounted(() => {
1426 useRenderAction(
1427 'renderForm',
1428 {
1429 ameliaContainer,
1430 containerWidth,
1431 empty,
1432 amCustomize,
1433 amFonts,
1434 sidebarCollapsed,
1435 sidebarCollapseItemsClass,
1436 sidebarFooterRef,
1437 sidebarFooterHeight,
1438 sidebarVisibility
1439 },
1440 )
1441 })
1442 </script>
1443
1444 <style lang="scss">
1445 @import '../../../assets/scss/public/overides/overides';
1446 @import '../../../assets/scss/common/reset/reset';
1447 @import '../../../assets/scss/common/icon-fonts/style';
1448 @import '../../../assets/scss/common/skeleton/skeleton.scss';
1449
1450 :root {
1451 // Colors
1452 // shortcuts
1453 // -c- color
1454 // -bgr- background
1455 // -prim- primary
1456 // -sec- secondary
1457 // primitive colors
1458 --am-c-primary: #{$blue-1000};
1459 --am-c-success: #{$green-1000};
1460 --am-c-error: #{$red-900};
1461 --am-c-warning: #{$yellow-1000};
1462 // main container colors - right part of the form
1463 --am-c-main-bgr: #{$am-white};
1464 --am-c-main-heading-text: #{$shade-800};
1465 --am-c-main-text: #{$shade-900};
1466 // sidebar container colors - left part of the form
1467 --am-c-sb-bgr: #17295A;
1468 --am-c-sb-text: #{$am-white};
1469 // input global colors - usage input, textarea, checkbox, radio button, select input, adv select input
1470 --am-c-inp-bgr: #{$am-white};
1471 --am-c-inp-border: #{$shade-250};
1472 --am-c-inp-text: #{$shade-900};
1473 --am-c-inp-placeholder: #{$shade-500};
1474 // dropdown global colors - usage select dropdown, adv select dropdown
1475 --am-c-drop-bgr: #{$am-white};
1476 --am-c-drop-text: #{$shade-1000};
1477 // button global colors
1478 --am-c-btn-prim: #{$blue-900};
1479 --am-c-btn-prim-text: #{$am-white};
1480 --am-c-btn-sec: #{$am-white};
1481 --am-c-btn-sec-text: #{$shade-900};
1482
1483 // Properties
1484 // shortcuts
1485 // -h- height
1486 // -fs- font size
1487 // -rad- border radius
1488 --am-h-input: 40px;
1489 --am-fs-input: 15px;
1490 --am-rad-input: 6px;
1491 --am-fs-label: 15px;
1492 --am-fs-btn: 15px;
1493
1494 // Font
1495 --am-font-family: 'Amelia Roboto', sans-serif;
1496 }
1497
1498 // am -- amelia
1499 // fs -- form steps
1500 // sb -- sidebar
1501 .amelia-v2-booking {
1502 background-color: transparent;
1503
1504 #amelia-container {
1505 background-color: transparent;
1506 * {
1507 font-family: var(--am-font-family);
1508 font-style: initial;
1509 box-sizing: border-box;
1510 word-break: break-word;
1511 }
1512
1513 &.am-fs {
1514 // Container Wrapper
1515 &__wrapper {
1516 display: flex;
1517 justify-content: center;
1518 max-width: var(--am-mw-main);
1519 width: 100%;
1520 height: 560px;
1521 margin: 100px auto;
1522 border-radius: 8px;
1523 box-shadow: 0 30px 40px rgba(0, 0, 0, 0.12);
1524 transition: max-width 0.3s ease-in-out;
1525
1526 &.am-collapsed {
1527 transition-delay: 1s;
1528 }
1529
1530 .el-form {
1531 &-item {
1532 display: block;
1533 font-family: var(--am-font-family);
1534 font-size: var(--am-fs-label);
1535 margin-bottom: 24px;
1536
1537 &__label {
1538 flex: 0 0 auto;
1539 text-align: left;
1540 font-size: var(--am-fs-label);
1541 line-height: 1.3;
1542 color: var(--am-c-main-text);
1543 box-sizing: border-box;
1544 margin: 0;
1545
1546 &:before {
1547 color: var(--am-c-error);
1548 }
1549 }
1550
1551 &__content {
1552 display: flex;
1553 flex-wrap: wrap;
1554 align-items: center;
1555 flex: 1;
1556 position: relative;
1557 font-size: var(--am-fs-input);
1558 min-width: 0;
1559 color: var(--am-c-main-text);
1560 }
1561
1562 &__error {
1563 font-size: 12px;
1564 color: var(--am-c-error);
1565 padding-top: 4px;
1566 }
1567 }
1568 }
1569
1570 * {
1571 font-family: var(--am-font-family);
1572 box-sizing: border-box;
1573 }
1574 }
1575 }
1576 }
1577
1578 .am-no-services {
1579 box-shadow: 0 30px 40px rgba(0, 0, 0, 0.12);
1580 margin: 100px auto;
1581 text-align: center;
1582 padding: 56px;
1583 max-width: 760px;
1584 height: 460px;
1585 width: 100%;
1586
1587 p {
1588 margin-bottom: 8px;
1589 padding: 0;
1590 }
1591
1592 &-oops {
1593 font-size: 24px;
1594 line-height: 1.5;
1595 font-weight: 400;
1596 color: #354052;
1597 margin: 0;
1598 }
1599
1600 &-text {
1601 font-size: 16px;
1602 line-height: 1.5;
1603 font-weight: 400;
1604 color: #354052;
1605 &-2 {
1606 color: #354052;
1607 font-size: 14px;
1608 }
1609 }
1610
1611 a {
1612 font-size: 14px;
1613 }
1614
1615 * {
1616 font-family: 'Amelia Roboto', sans-serif;
1617 box-sizing: border-box;
1618 }
1619 }
1620 }
1621 </style>
1622