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 / RecurringStep.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
RecurringStep.vue
469 lines
1 <template>
2 <div
3 class="am-fs__rs"
4 :class="[{ 'am-fs__rs-mobile': checkScreen }, props.globalClass]"
5 :style="cssVars"
6 >
7 <template v-if="amCustomize[pageRenderKey].recurringStep.options.heading.visibility">
8 <p>{{ labelsDisplay('recurrence') }}</p>
9 <span class="am-fa__rs-light">{{ labelsDisplay('recurrence_choosing_time') }}</span>
10 </template>
11 <p>{{ `${labelsDisplay('repeat_every')}:` }}</p>
12 <div class="am-fs__rs-every">
13 <AmInputNumber v-model="repeatInterval" :min="1" :max="100" />
14 <AmSelect v-model="repeatType">
15 <AmOption
16 v-for="(type, i) in repeatTypes"
17 :key="i"
18 :label="type.label"
19 :value="type.value"
20 />
21 </AmSelect>
22 </div>
23 <div v-if="repeatType === 'weekly'">
24 <p>{{ `${labelsDisplay('recurrence_repeat_on')}:` }}</p>
25 <div class="am-fs__rs-on-week">
26 <div
27 v-for="(day, i) in weekDays"
28 :key="i"
29 :class="{
30 'am-fs__rs-on-week-selected': weekDays.find((i) => i.value === day.value).selected,
31 }"
32 @click="selectWeekDay(day.value)"
33 >
34 {{ day.label }}
35 </div>
36 </div>
37 </div>
38 <div v-if="repeatType === 'monthly'">
39 <p>{{ `${labelsDisplay('recurrence_repeat_on')}:` }}</p>
40 <div class="am-fs__rs-on-month">
41 <AmSelect v-model="repeatMonthly">
42 <AmOption
43 v-for="(type, i) in monthlyTypes"
44 :key="i"
45 :label="type.label"
46 :value="type.value"
47 />
48 </AmSelect>
49 </div>
50 </div>
51 <p>{{ `${labelsDisplay('recurrence_ends')}:` }}</p>
52 <span class="am-fa__rs-light">{{ labelsDisplay('recurrence_choose_ends') }}</span>
53 <div class="am-fs__rs-ends">
54 <div class="am-fs__rs-ends-choose">
55 <AmRadioGroup v-model="occurrenceType">
56 <AmRadio value="on">{{ labelsDisplay('recurrence_on') }}</AmRadio>
57 <AmRadio value="after">{{ labelsDisplay('recurrence_after') }}</AmRadio>
58 </AmRadioGroup>
59 </div>
60 <div class="am-fs__rs-ends-options">
61 <AmDatePickerFull
62 :calendar-minimum-date="moment().format('YYYY-MM-DD')"
63 :disabled="occurrenceType !== 'on'"
64 :input-placeholder="labelsDisplay('recurrence_select_date')"
65 @selected-date="selectedOccurrenceDate"
66 />
67 <div class="am-fs__rs-ends-after">
68 <AmInputNumber
69 v-model="occurrenceCount"
70 :disabled="occurrenceType !== 'after'"
71 :min="1"
72 :max="100"
73 />
74 <span>{{ labelsDisplay('occurrences') }}</span>
75 </div>
76 </div>
77 </div>
78 <div class="am-fs__rs-summary">
79 <p>{{ `${labelsDisplay('appointment_repeats')}:` }}</p>
80 <p>
81 {{ labelsDisplay('recurrence_every') }} {{ repeatInterval }}
82 {{
83 repeatTypes.find((item) => item.value === repeatType)
84 ? repeatTypes.find((item) => item.value === repeatType).label
85 : ''
86 }}
87 <span v-if="repeatType === 'weekly'" class="am-fa__rs-light"
88 >{{ labelsDisplay('repeats_on') }}
89 {{ weekDays.filter((i) => i.enabled).join(', ') }},</span
90 >
91 <span v-if="repeatType === 'monthly'" class="am-fa__rs-light">
92 {{ `${labelsDisplay('repeats_on')} ${monthlyTypes[repeatMonthly].label}, ` }}
93 </span>
94 <span class="am-fa__rs-light">
95 {{ labelsDisplay('repeats_from') }}
96 {{ moment().format('YYYY-MM-DD') }} {{ labelsDisplay('repeats_at') }}
97 {{ moment().format('hh:mm') }}</span
98 >
99 </p>
100 <p>
101 <span v-if="occurrenceType === 'after'" class="am-fa__rs-light"
102 >{{ labelsDisplay('number_of_recurrences') }} {{ occurrenceCount }}</span
103 >
104 <span v-else class="am-fa__rs-light"
105 >{{ labelsDisplay('ends_on') }} {{ occurrenceDate }}</span
106 >
107 </p>
108 </div>
109 </div>
110 </template>
111
112 <script setup>
113 import moment from 'moment'
114 import AmInputNumber from '../../../../_components/input-number/AmInputNumber'
115 import AmSelect from '../../../../_components/select/AmSelect'
116 import AmOption from '../../../../_components/select/AmOption'
117 import AmRadioGroup from '../../../../_components/radio/AmRadioGroup'
118 import AmRadio from '../../../../_components/radio/AmRadio'
119 import AmDatePickerFull from '../../../../_components/date-picker-full/AmDatePickerFull.vue'
120 import { computed, ref, inject } from 'vue'
121 import { useColorTransparency } from '../../../../../assets/js/common/colorManipulation.js'
122 import { useReactiveCustomize } from '../../../../../assets/js/admin/useReactiveCustomize.js'
123
124 let props = defineProps({
125 globalClass: {
126 type: String,
127 default: '',
128 },
129 })
130
131 // Container Width
132 let cWidth = inject('containerWidth', 0)
133 let checkScreen = computed(() => cWidth.value < 560)
134
135 let langKey = inject('langKey')
136 let amLabels = inject('labels')
137
138 let pageRenderKey = inject('pageRenderKey')
139 const { amCustomize } = useReactiveCustomize()
140
141 // * Label computed function
142 function labelsDisplay(label) {
143 let computedLabel = computed(() => {
144 return amCustomize.value[pageRenderKey.value].recurringStep.translations &&
145 amCustomize.value[pageRenderKey.value].recurringStep.translations[label] &&
146 amCustomize.value[pageRenderKey.value].recurringStep.translations[label][langKey.value]
147 ? amCustomize.value[pageRenderKey.value].recurringStep.translations[label][langKey.value]
148 : amLabels[label]
149 })
150
151 return computedLabel.value
152 }
153
154 /************
155 * Computed *
156 ***********/
157
158 let repeatType = ref('day')
159
160 let repeatInterval = ref(1)
161
162 let occurrenceType = ref('after')
163
164 let occurrenceDate = ref(moment().format('YYYY-MM-DD'))
165
166 let occurrenceCount = ref(1)
167
168 let repeatMonthly = ref(0)
169
170 const repeatTypes = computed(() => {
171 return [
172 {
173 label: labelsDisplay('recurrence_day'),
174 labelPlural: labelsDisplay('recurrence_days'),
175 value: 'daily',
176 },
177 {
178 label: labelsDisplay('recurrence_week'),
179 labelPlural: labelsDisplay('recurrence_weeks'),
180 value: 'weekly',
181 },
182 {
183 label: labelsDisplay('recurrence_month'),
184 labelPlural: labelsDisplay('recurrence_months'),
185 value: 'monthly',
186 },
187 ]
188 })
189
190 const monthlyTypes = computed(() => {
191 return [
192 {
193 label: labelsDisplay('recurrence_specific_date'),
194 value: 0,
195 },
196 {
197 label: labelsDisplay('recurrence_first'),
198 value: 1,
199 },
200 {
201 label: labelsDisplay('recurrence_second'),
202 value: 2,
203 },
204 {
205 label: labelsDisplay('recurrence_third'),
206 value: 3,
207 },
208 {
209 label: labelsDisplay('recurrence_fourth'),
210 value: 4,
211 },
212 {
213 label: labelsDisplay('recurrence_last'),
214 value: 5,
215 },
216 ]
217 })
218
219 const weekDays = ref([
220 { label: 'Mon', value: 'monday', selected: false },
221 { label: 'Tue', value: 'tuesday', selected: false },
222 { label: 'Wed', value: 'wednesday', selected: false },
223 { label: 'Thu', value: 'thursday', selected: false },
224 { label: 'Fri', value: 'friday', selected: false },
225 { label: 'Sat', value: 'saturday', selected: false },
226 { label: 'Sun', value: 'sunday', selected: false },
227 ])
228
229 function selectedOccurrenceDate(data) {
230 occurrenceDate.value = data
231 }
232
233 // let selectedDayInMonth = computed(() => moment(activeAppointment.date, "YYYY-MM-DD").format('dddd'))
234
235 /**************
236 * Navigation *
237 *************/
238
239 function selectWeekDay(value) {
240 let weekDay = weekDays.value.find((i) => i.value === value)
241 weekDay.selected = !weekDay.selected
242 }
243
244 // * Colors
245 let amColors = inject('amColors')
246 let cssVars = computed(() => {
247 return {
248 '--am-c-rs-text': amColors.value.colorMainText,
249 '--am-c-rs-text-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
250 '--am-c-rs-bgr': amColors.value.colorMainBgr,
251 '--am-c-rs-primary': amColors.value.colorPrimary,
252 '--am-c-rs-inp-border': amColors.value.colorInpBorder,
253 }
254 })
255 </script>
256
257 <script>
258 export default {
259 name: 'RecurringStep',
260 key: 'recurringStep',
261 sidebarData: {
262 label: 'recurring_step',
263 icon: 'calendar-recurring',
264 stepSelectedData: [],
265 finished: false,
266 selected: false,
267 },
268 }
269 </script>
270
271 <style lang="scss">
272 #amelia-app-backend-new {
273 #amelia-container {
274 // rs - Recurring Step
275 .am-fs__rs {
276 & > * {
277 $count: 10;
278 @for $i from 0 through $count {
279 &:nth-child(#{$i + 1}) {
280 animation: 600ms cubic-bezier(0.45, 1, 0.4, 1.2) #{$i * 100}ms am-animation-slide-up;
281 animation-fill-mode: both;
282 }
283 }
284 }
285
286 p {
287 margin-top: 16px;
288 font-weight: 500;
289 font-size: 15px;
290 line-height: 24px;
291 /* $shade-900 */
292 color: var(--am-c-rs-text);
293 margin-bottom: 4px;
294 }
295
296 span.am-fa__rs-light {
297 font-weight: 400;
298 font-size: 14px;
299 line-height: 20px;
300 /* $shade-500 */
301 color: var(--am-c-rs-text-op60);
302 }
303
304 &-every {
305 display: flex;
306 .am-select {
307 width: 103px;
308 }
309 & > div {
310 &:first-child {
311 margin-right: 8px;
312 }
313 }
314 }
315
316 &-on-week {
317 display: flex;
318 width: 100%;
319 justify-content: space-between;
320 /* $shade-900 */
321 color: var(--am-c-rs-text);
322 & > div {
323 font-weight: 400;
324 font-size: 15px;
325 line-height: 24px;
326 text-align: center;
327 margin: 0;
328 cursor: pointer;
329 /* $shade-250 */
330 border: 1px solid var(--am-c-rs-inp-border);
331 box-shadow: 0 1px 1px rgba(115, 134, 169, 0.06);
332 border-radius: 4px;
333 width: 52px;
334 padding: 8px 0;
335 align-content: center;
336
337 &.am-fs__rs-on-week-selected {
338 /* $blue-900 */
339 background: var(--am-c-rs-primary);
340 /* $blue-1000 */
341 border: 1px solid var(--am-c-rs-primary);
342 /* $white */
343 color: var(--am-c-rs-bgr);
344 }
345 }
346 }
347 &-ends {
348 display: flex;
349 align-items: center;
350 margin: 16px 0;
351 gap: 12px;
352 max-width: 100%;
353
354 &-choose {
355 display: flex;
356 flex: 0 0 auto;
357
358 .am-radio-group {
359 display: flex;
360 gap: 16px;
361
362 .am-radio-wrapper {
363 display: flex;
364 height: 40px;
365 align-items: center;
366
367 .am-radio {
368 display: flex;
369 align-items: center;
370
371 .el-radio__input,
372 .el-radio__label {
373 align-self: center;
374 }
375 }
376 }
377 }
378 }
379
380 &-options {
381 display: flex;
382 flex-direction: column;
383 gap: 16px;
384 max-width: 100%;
385 width: 100%;
386
387 .am-input-wrapper {
388 max-width: 174px;
389 width: 100%;
390 }
391 }
392
393 &-after {
394 display: flex;
395 gap: 12px;
396 width: 100%;
397
398 .am-input-number {
399 max-width: 174px;
400 width: 100%;
401 }
402
403 & > span {
404 flex: 0 0 auto;
405 font-weight: 400;
406 font-size: 15px;
407 line-height: 40px;
408 text-align: center;
409 /* $shade-900 */
410 color: var(--am-c-rs-text);
411 }
412 }
413 }
414 &-summary {
415 p,
416 span {
417 font-weight: 400;
418 font-size: 14px;
419 line-height: 20px;
420 /* $shade-600 */
421 color: var(--am-c-rs-text-op60);
422 margin: 0;
423 }
424 }
425
426 &-mobile {
427 .el-radio {
428 &__label {
429 white-space: nowrap;
430 }
431 }
432
433 .am-fs__rs-every {
434 & > div {
435 max-width: 162px;
436 width: 100%;
437 }
438 & .am-select {
439 width: 100%;
440 }
441 }
442
443 .am-fs__rs-ends {
444 &-after {
445 .am-input-wrapper {
446 max-width: 40px;
447
448 .el-input__inner {
449 text-align: center;
450 padding: 6px;
451 }
452 }
453 //.el-input-number {
454 // max-width: 60%;
455 //}
456 }
457 }
458 }
459
460 &-on-month {
461 .am-select-wrapper {
462 max-width: 180px;
463 }
464 }
465 }
466 }
467 }
468 </style>
469