PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.4
Booking for Appointments and Events Calendar – Amelia v2.4.4
2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / v3 / src / views / admin / customize / steps / StepForm / DateTimeStep.vue
ameliabooking / v3 / src / views / admin / customize / steps / StepForm Last commit date
common 3 days ago BringingAnyone.vue 3 days ago CartStep.vue 3 days ago Congratulations.vue 3 days ago DateTimeStep.vue 3 days ago EmployeeStep.vue 3 days ago Extras.vue 3 days ago InfoStep.vue 3 days ago InitStep.vue 3 days ago LocationStep.vue 3 days ago PackageAppointmentsListStep.vue 3 days ago PackageAppointmentsStep.vue 3 days ago PackageInfoStep.vue 3 days ago PackageStep.vue 3 days ago PaymentStep.vue 3 days ago RecurringStep.vue 3 days ago RecurringSummary.vue 3 days ago ServiceStep.vue 3 days ago
DateTimeStep.vue
420 lines
1 <template>
2 <div ref="dateTimeRef" class="am-fs-dt__calendar">
3 <AmAdvancedSlotCalendar
4 v-if="showCalendar"
5 :id="0"
6 :slots="calendarEvents"
7 :calendar-minimum-date="moment().format('YYYY-MM-DD hh:mm')"
8 :calendar-maximum-date="moment().add(1, 'year').format('YYYY-MM-DD hh:mm')"
9 :time-zone="
10 features.timeZones &&
11 amCustomize[pageRenderKey].dateTimeStep.options.timeZoneVisibility.visibility
12 "
13 :show-busy-slots="
14 amCustomize[pageRenderKey].dateTimeStep.options.busyTimeSlotsVisibility.visibility
15 "
16 :show-calendar-date-busyness="
17 amCustomize[pageRenderKey].dateTimeStep.options.calendarDateBusynessVisibility
18 ?.visibility ?? true
19 "
20 :show-estimated-pricing="
21 amCustomize[pageRenderKey].dateTimeStep.options.estimatedPricingVisibility.visibility
22 "
23 :show-indicator-pricing="
24 amCustomize[pageRenderKey].dateTimeStep.options.indicatorPricingVisibility.visibility
25 "
26 :show-slot-pricing="
27 amCustomize[pageRenderKey].dateTimeStep.options.slotPricingVisibility.visibility
28 "
29 :show-people-waiting="
30 amCustomize[pageRenderKey].dateTimeStep.options?.peopleWaitingVisibility?.visibility
31 "
32 :label-slots-selected="labelsDisplay('date_time_slots_selected', 'dateTimeStep')"
33 :label-waiting-list="labelsDisplay('waiting_list', 'dateTimeStep')"
34 :period-pricing="periodPricing"
35 :busyness="previewCalendarBusyness"
36 @selected-date="setSelectedDate"
37 @unselect-date="unselectDate"
38 @selected-time="setSelectedTime"
39 ></AmAdvancedSlotCalendar>
40
41 <!-- Recurring Appointment -->
42 <AmSlidePopup :visibility="recurringPopupVisibility" class="am-fs-dt__calendar__recurring">
43 <div class="am-fs-dt__rec_popup">
44 <p>
45 {{ labelsDisplay('repeat_appointment', 'recurringPopup') }}
46 </p>
47 <p v-if="amCustomize[pageRenderKey].recurringPopup.options.content.visibility">
48 {{ labelsDisplay('repeat_appointment_quest', 'recurringPopup') }}
49 </p>
50 </div>
51 <template #footer>
52 <AmButton
53 category="secondary"
54 :type="amCustomize[pageRenderKey].recurringPopup.options.secondaryButton.buttonType"
55 >
56 {{ labelsDisplay('no', 'recurringPopup') }}
57 </AmButton>
58 <AmButton
59 :type="amCustomize[pageRenderKey].recurringPopup.options.primaryButton.buttonType"
60 >
61 {{ labelsDisplay('yes', 'recurringPopup') }}
62 </AmButton>
63 </template>
64 </AmSlidePopup>
65 <!--/ Recurring Appointment -->
66 </div>
67 </template>
68
69 <script setup>
70 import AmSlidePopup from '../../../../_components/slide-popup/AmSlidePopup.vue'
71 import AmButton from '../../../../_components/button/AmButton.vue'
72 import AmAdvancedSlotCalendar from '../../../../_components/advanced-slot-calendar/AmAdvancedSlotCalendar.vue'
73 import moment from 'moment'
74 import { useReactiveCustomize } from '../../../../../assets/js/admin/useReactiveCustomize.js'
75
76 import { ref, provide, inject, computed, onMounted, watchEffect } from 'vue'
77
78 const amSettings = inject('settings')
79
80 let langKey = inject('langKey')
81 let amLabels = inject('labels')
82
83 let subStepName = inject('subStepName')
84 let pageRenderKey = inject('pageRenderKey')
85 const { amCustomize } = useReactiveCustomize()
86 // * Plugin Licence
87 let licence = inject('licence')
88
89 // * Features
90 let features = inject('features')
91
92 // * Container Width
93 // let cWidth = inject('containerWidth', 0)
94 // let checkScreen = computed(() => cWidth.value < 560 || (cWidth.value - 240 < 520))
95
96 /*****************
97 * Calendar Data *
98 ****************/
99 let showCalendar = ref(false)
100
101 let periodPricing = ref({})
102
103 function getCustomPeriodsPricing() {
104 let result = {}
105 let today = moment()
106
107 let current = today.clone()
108
109 for (let i = 0; i <= 31; i++) {
110 let type =
111 current.day() === 6 || current.day() === 0
112 ? 'high'
113 : current.day() === 1 || current.day() === 2
114 ? 'low'
115 : 'mid'
116
117 result[current.format('YYYY-MM-DD')] = {
118 type: type,
119 slots: {
120 '09:00': {
121 type: type === 'mid' ? 'low' : type,
122 price: type === 'mid' ? 5 : type === 'low' ? 5 : 15,
123 },
124 '09:30': {
125 type: type === 'mid' ? 'low' : type,
126 price: type === 'mid' ? 5 : type === 'low' ? 5 : 15,
127 },
128 '10:00': {
129 type: type,
130 price: type === 'mid' ? 10 : type === 'low' ? 5 : 15,
131 },
132 '10:30': {
133 type: type,
134 price: type === 'mid' ? 10 : type === 'low' ? 5 : 15,
135 },
136 '11:00': {
137 type: type,
138 price: type === 'mid' ? 10 : type === 'low' ? 5 : 15,
139 },
140 '11:30': {
141 type: type,
142 price: type === 'mid' ? 10 : type === 'low' ? 5 : 15,
143 },
144 '12:00': {
145 type: type === 'mid' ? 'high' : type,
146 price: type === 'mid' ? 15 : type === 'high' ? 15 : 5,
147 },
148 '12:30': {
149 type: type === 'mid' ? 'high' : type,
150 price: type === 'mid' ? 15 : type === 'high' ? 15 : 5,
151 },
152 },
153 }
154
155 current.add(1, 'day')
156 }
157
158 return {
159 price: {
160 low: 5,
161 mid: 10,
162 high: 15,
163 },
164 dates: result,
165 }
166 }
167
168 let dateTimeRef = ref(null)
169 provide('formWrapper', dateTimeRef)
170
171 let calendarEvents = ref([])
172
173 let calendarEventDate = ref('')
174
175 let calendarServiceDuration = ref('0')
176
177 let calendarEventSlots = ref([])
178
179 let calendarEventBusySlots = ref([])
180
181 let calendarWaitingListSlots = ref([])
182
183 let calendarWaitingListTimes = ref(
184 !licence.isBasic &&
185 !licence.isStarter &&
186 !licence.isLite &&
187 amSettings.featuresIntegrations?.waitingListAppointments?.enabled
188 ? ['10:30']
189 : [],
190 )
191
192 watchEffect(() => {
193 calendarEventBusySlots.value = amCustomize.value[pageRenderKey.value].dateTimeStep.options
194 .busyTimeSlotsVisibility.visibility
195 ? ['08:00', '08:30', '09:30', '12:30', '14:00']
196 : []
197 })
198
199 let previewCalendarBusyness = computed(() => {
200 const opts = amCustomize.value[pageRenderKey.value].dateTimeStep.options
201 if (!(opts.calendarDateBusynessVisibility?.visibility ?? true)) {
202 return {}
203 }
204 const base = moment().startOf('day')
205 return {
206 [base.clone().add(6, 'days').format('YYYY-MM-DD')]: 40,
207 [base.clone().add(20, 'days').format('YYYY-MM-DD')]: 82,
208 }
209 })
210
211 let today = moment().format('YYYY-MM-DD')
212
213 for (let i = 0; i <= 31; i++) {
214 let block = {
215 display: 'background',
216 extendedProps: {
217 slots: { '09:00': [7, 3] },
218 slotsAvailable: 1,
219 slotsTotal: 100,
220 },
221 start: moment(today).add(i, 'd').format('YYYY-MM-DD'),
222 title: 'e',
223 }
224
225 calendarEvents.value.push(block)
226 }
227
228 let calendarEventSlot = ref('')
229 let calendarStartDate = ref(moment().format('YYYY-MM-DD'))
230 let calendarChangeSideBar = ref(true)
231
232 provide('calendarEvents', calendarEvents)
233 provide('calendarEventDate', calendarEventDate)
234 provide('calendarEventSlots', calendarEventSlots)
235 provide('calendarEventBusySlots', calendarEventBusySlots)
236 provide('calendarEventSlot', calendarEventSlot)
237 provide('calendarStartDate', calendarStartDate)
238 provide('calendarChangeSideBar', calendarChangeSideBar)
239 provide('calendarServiceDuration', calendarServiceDuration)
240 provide('calendarWaitingListSlots', calendarWaitingListSlots)
241 provide('calendarWaitingListTimes', calendarWaitingListTimes)
242
243 let calendarSlotDuration = 1800
244 provide('calendarSlotDuration', calendarSlotDuration)
245
246 // * Recurring popup
247 let recurringPopupVisibility = computed(() => {
248 return subStepName.value === 'recurringPopup'
249 })
250
251 // * Label computed function
252 function labelsDisplay(label, stepKey) {
253 let computedLabel = computed(() => {
254 return amCustomize.value[pageRenderKey.value][stepKey].translations &&
255 amCustomize.value[pageRenderKey.value][stepKey].translations[label] &&
256 amCustomize.value[pageRenderKey.value][stepKey].translations[label][langKey.value]
257 ? amCustomize.value[pageRenderKey.value][stepKey].translations[label][langKey.value]
258 : amLabels[label]
259 })
260
261 return computedLabel.value
262 }
263
264 onMounted(() => {
265 periodPricing.value =
266 !licence.isBasic && !licence.isStarter && !licence.isLite ? getCustomPeriodsPricing() : {}
267
268 showCalendar.value = true
269 })
270
271 function setSelectedDate(value) {
272 unselectDate()
273
274 for (let i = 0; i < 18; i++) {
275 if (i > 8 && i < 13) {
276 calendarEventSlots.value.push(`${i < 10 ? '0' + i : i}:00`)
277 calendarEventSlots.value.push(`${i < 10 ? '0' + i : i}:30`)
278 }
279 }
280
281 if (calendarEventSlots.value.length) {
282 setSelectedTime(calendarEventSlots.value[0])
283 }
284
285 calendarEventDate.value = value
286 }
287
288 function unselectDate() {
289 calendarEventBusySlots.value = amCustomize.value[pageRenderKey.value].dateTimeStep.options
290 .busyTimeSlotsVisibility.visibility
291 ? ['08:00', '08:30', '09:30', '12:30', '14:00']
292 : []
293
294 calendarEventSlots.value = []
295
296 calendarEventSlot.value = ''
297
298 calendarEventDate.value = ''
299 }
300
301 function setSelectedTime(value) {
302 calendarEventSlot.value = value
303 }
304 </script>
305
306 <script>
307 export default {
308 name: 'DateTimeStep',
309 key: 'dateTimeStep',
310 sidebarData: {
311 label: 'date_time',
312 icon: 'date-time',
313 stepSelectedData: [],
314 finished: false,
315 selected: false,
316 },
317 }
318 </script>
319
320 <style lang="scss">
321 // am -- amelia
322 // fs -- form steps
323
324 #amelia-app-backend-new #amelia-container {
325 // Amelia Form Steps
326 .am-fs {
327 // Container Wrapper
328 &__main {
329 &-heading {
330 &-inner {
331 display: flex;
332 align-items: center;
333
334 .am-heading-prev {
335 margin-right: 12px;
336 }
337 }
338 }
339
340 &-inner {
341 &#{&}-dt {
342 padding: 0 20px;
343 }
344 }
345 }
346
347 &-dt__rec_popup {
348 margin: 16px 0 48px 0;
349 & > p {
350 font-size: 15px;
351 line-height: 1.6;
352 color: var(--am-c-main-text);
353
354 &:first-child {
355 font-weight: 500;
356 margin-bottom: 7px;
357 }
358
359 &:last-child {
360 font-weight: 400;
361 }
362 }
363 }
364 }
365
366 // Skeleton
367 .am-skeleton-slots {
368 &-mobile {
369 padding: 16px;
370 }
371
372 &-filters {
373 display: flex;
374 flex-direction: row;
375 justify-content: space-between;
376 padding: 0 0 24px;
377
378 .el-skeleton__item {
379 height: 36px;
380 width: 20%;
381 }
382
383 :first-child {
384 width: 26%;
385 margin-right: 16px;
386 }
387
388 :last-child {
389 width: 16%;
390 margin-left: 16px;
391 }
392 }
393
394 &-weekdays {
395 padding-bottom: 12px;
396 display: flex;
397 flex-direction: row;
398 justify-content: space-around;
399
400 .el-skeleton__item {
401 max-width: 30px;
402 height: 24px;
403 }
404 }
405
406 &-days {
407 display: grid;
408 grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
409 gap: 8px;
410
411 .el-skeleton__item {
412 margin: 0 1.5px;
413 height: 40px;
414 max-width: 56px;
415 }
416 }
417 }
418 }
419 </style>
420