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 |