cronofy-elements 1.48.1 → 1.49.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.gitkeep +0 -0
- package/dist/CronofyElements.js +2 -0
- package/{build/CronofyElements.v1.48.1.js.LICENSE.txt → dist/CronofyElements.js.LICENSE.txt} +0 -0
- package/package.json +10 -7
- package/.babelrc +0 -20
- package/.eslintrc.yaml +0 -43
- package/.prettierignore +0 -4
- package/.prettierrc +0 -7
- package/Makefile +0 -92
- package/brainstorm.md +0 -76
- package/build/CronofyElements.v1.48.1.js +0 -2
- package/build/npm/CronofyElements.js +0 -2
- package/compat.config.js +0 -25
- package/demo/agenda.ejs +0 -71
- package/demo/availability-viewer.ejs +0 -322
- package/demo/calendar-sync.ejs +0 -149
- package/demo/crossbrowser.ejs +0 -228
- package/demo/date-time-picker.ejs +0 -213
- package/demo/demo-styles.css +0 -134
- package/demo/index.ejs +0 -249
- package/demo/integration.ejs +0 -482
- package/demo/load-elements.ejs +0 -12
- package/demo/nav.ejs +0 -14
- package/demo/rules.ejs +0 -121
- package/demo/server.js +0 -425
- package/demo/slot-picker.ejs +0 -197
- package/git.README.md +0 -71
- package/notes.style.md +0 -197
- package/postcss.config.js +0 -3
- package/script/i18n-export +0 -11
- package/script/i18n-helpers/split_write.rb +0 -25
- package/script/i18n-import +0 -22
- package/script/i18n-reference-update +0 -241
- package/src/js/components/Agenda/Agenda.js +0 -243
- package/src/js/components/Agenda/AllDayEventsList.js +0 -37
- package/src/js/components/Agenda/Calendar.js +0 -100
- package/src/js/components/Agenda/CalendarHeader.js +0 -187
- package/src/js/components/Agenda/Event.js +0 -34
- package/src/js/components/Agenda/EventAllDay.js +0 -76
- package/src/js/components/Agenda/EventAttendees.js +0 -30
- package/src/js/components/Agenda/EventDetail.js +0 -111
- package/src/js/components/Agenda/EventMessages.js +0 -24
- package/src/js/components/Agenda/EventMeta.js +0 -48
- package/src/js/components/Agenda/EventTime.js +0 -34
- package/src/js/components/Agenda/EventWrapper.js +0 -271
- package/src/js/components/Agenda/Location.js +0 -29
- package/src/js/components/Agenda/Message.js +0 -22
- package/src/js/components/Agenda/TimedEventsList.js +0 -29
- package/src/js/components/AvailabilityRules/AddButton.js +0 -60
- package/src/js/components/AvailabilityRules/AvailabilityRules.js +0 -45
- package/src/js/components/AvailabilityRules/Calendar.js +0 -31
- package/src/js/components/AvailabilityRules/CalendarListItem.js +0 -53
- package/src/js/components/AvailabilityRules/CalendarProfiles.js +0 -67
- package/src/js/components/AvailabilityRules/CalendarSelector.js +0 -104
- package/src/js/components/AvailabilityRules/Calendars.js +0 -145
- package/src/js/components/AvailabilityRules/Checkmark.js +0 -51
- package/src/js/components/AvailabilityRules/DayLabels.js +0 -91
- package/src/js/components/AvailabilityRules/Footer.js +0 -109
- package/src/js/components/AvailabilityRules/Legend.js +0 -57
- package/src/js/components/AvailabilityRules/Loading.js +0 -53
- package/src/js/components/AvailabilityRules/RemoveButton.js +0 -57
- package/src/js/components/AvailabilityRules/Slot.js +0 -195
- package/src/js/components/AvailabilityRules/SlotDisplay.js +0 -27
- package/src/js/components/AvailabilityRules/Slots.js +0 -81
- package/src/js/components/AvailabilityRules/SlotsDisplay.js +0 -68
- package/src/js/components/AvailabilityRules/TimeExpander.js +0 -119
- package/src/js/components/AvailabilityRules/TimeLabels.js +0 -89
- package/src/js/components/AvailabilityRules/TimeZoneDisplay.js +0 -41
- package/src/js/components/AvailabilityRules/ToggleIcon.js +0 -41
- package/src/js/components/AvailabilityRules/Tooltip.js +0 -63
- package/src/js/components/AvailabilityRules/UnknownCalendar.js +0 -33
- package/src/js/components/AvailabilityRules/Week.js +0 -115
- package/src/js/components/AvailabilityRules/WeekGrid.js +0 -80
- package/src/js/components/AvailabilityRules/Wrapper.js +0 -414
- package/src/js/components/AvailabilityRules/contexts/drag-context.js +0 -15
- package/src/js/components/AvailabilityRules/scss/_base.buttons.scss +0 -58
- package/src/js/components/AvailabilityRules/scss/_base.theme.scss +0 -4
- package/src/js/components/AvailabilityRules/scss/_components.timezoneselector.scss +0 -74
- package/src/js/components/AvailabilityRules/scss/_generic.reset.scss +0 -13
- package/src/js/components/AvailabilityRules/scss/_settings.colours.scss +0 -12
- package/src/js/components/AvailabilityRules/scss/availabilityrules.scss +0 -5
- package/src/js/components/AvailabilityRules/utils/tz-utils.js +0 -44
- package/src/js/components/AvailabilityViewer/AvailabilityViewer.js +0 -524
- package/src/js/components/AvailabilityViewer/ColumnHeader.js +0 -35
- package/src/js/components/AvailabilityViewer/DayColumn.js +0 -36
- package/src/js/components/AvailabilityViewer/DayColumnDisplay.js +0 -33
- package/src/js/components/AvailabilityViewer/DayColumnWrapper.js +0 -29
- package/src/js/components/AvailabilityViewer/DayLabels.js +0 -41
- package/src/js/components/AvailabilityViewer/EmptyColumn.js +0 -29
- package/src/js/components/AvailabilityViewer/Footer.js +0 -36
- package/src/js/components/AvailabilityViewer/GridFreeSelect.js +0 -33
- package/src/js/components/AvailabilityViewer/HoverSlot.js +0 -35
- package/src/js/components/AvailabilityViewer/HoverTooltip.js +0 -34
- package/src/js/components/AvailabilityViewer/LabelColumn.js +0 -53
- package/src/js/components/AvailabilityViewer/LabelItem.js +0 -73
- package/src/js/components/AvailabilityViewer/Legend.js +0 -79
- package/src/js/components/AvailabilityViewer/Loading.js +0 -57
- package/src/js/components/AvailabilityViewer/MonthLabels.js +0 -43
- package/src/js/components/AvailabilityViewer/Navigation.js +0 -138
- package/src/js/components/AvailabilityViewer/Overlay.js +0 -60
- package/src/js/components/AvailabilityViewer/Preloading.js +0 -66
- package/src/js/components/AvailabilityViewer/SelectedSlot.js +0 -106
- package/src/js/components/AvailabilityViewer/SelectedSlots.js +0 -72
- package/src/js/components/AvailabilityViewer/SelectionMask.js +0 -44
- package/src/js/components/AvailabilityViewer/Slot.js +0 -237
- package/src/js/components/AvailabilityViewer/SlotFreeSelect.js +0 -115
- package/src/js/components/AvailabilityViewer/Slots.js +0 -57
- package/src/js/components/AvailabilityViewer/TimeExpander.js +0 -93
- package/src/js/components/AvailabilityViewer/TimeLines.js +0 -74
- package/src/js/components/AvailabilityViewer/TimeSelector.js +0 -243
- package/src/js/components/AvailabilityViewer/TimeSelectorTrigger.js +0 -42
- package/src/js/components/AvailabilityViewer/TimeZoneDisplay.js +0 -28
- package/src/js/components/AvailabilityViewer/ToggleIcon.js +0 -41
- package/src/js/components/AvailabilityViewer/Tooltip.js +0 -65
- package/src/js/components/AvailabilityViewer/Week.js +0 -255
- package/src/js/components/AvailabilityViewer/WeekWrapper.js +0 -132
- package/src/js/components/AvailabilityViewer/contexts/page-context.js +0 -17
- package/src/js/components/AvailabilityViewer/contexts/page-reducer.js +0 -28
- package/src/js/components/AvailabilityViewer/contexts/selection-context.js +0 -25
- package/src/js/components/AvailabilityViewer/contexts/selection-reducer.js +0 -18
- package/src/js/components/CalendarSync/Active.js +0 -57
- package/src/js/components/CalendarSync/AddToggle.js +0 -72
- package/src/js/components/CalendarSync/CalendarSync.js +0 -215
- package/src/js/components/CalendarSync/EditToggle.js +0 -71
- package/src/js/components/CalendarSync/Footer.js +0 -31
- package/src/js/components/CalendarSync/Inactive.js +0 -66
- package/src/js/components/CalendarSync/Loading.js +0 -52
- package/src/js/components/CalendarSync/Pending.js +0 -74
- package/src/js/components/CalendarSync/ProfileStatus.js +0 -33
- package/src/js/components/CalendarSync/Profiles.js +0 -109
- package/src/js/components/CalendarSync/ProviderLogo.js +0 -28
- package/src/js/components/CalendarSync/Providers.js +0 -80
- package/src/js/components/CalendarSync/RemoveLink.js +0 -96
- package/src/js/components/CalendarSync/SelectProvider.js +0 -25
- package/src/js/components/CalendarSync/contexts/status-reducer.js +0 -74
- package/src/js/components/DateTimePicker/Calendar.js +0 -127
- package/src/js/components/DateTimePicker/CalendarHeader.js +0 -80
- package/src/js/components/DateTimePicker/Confirm.js +0 -106
- package/src/js/components/DateTimePicker/DateTimePicker.js +0 -131
- package/src/js/components/DateTimePicker/DayButton.js +0 -38
- package/src/js/components/DateTimePicker/DayHeadings.js +0 -33
- package/src/js/components/DateTimePicker/Details.js +0 -33
- package/src/js/components/DateTimePicker/Error.js +0 -39
- package/src/js/components/DateTimePicker/Loading.js +0 -20
- package/src/js/components/DateTimePicker/LoadingCalendar.js +0 -21
- package/src/js/components/DateTimePicker/NoSlotsFound.js +0 -16
- package/src/js/components/DateTimePicker/SequencedSlotButton.js +0 -97
- package/src/js/components/DateTimePicker/SlotButton.js +0 -55
- package/src/js/components/DateTimePicker/SlotsList.js +0 -45
- package/src/js/components/DateTimePicker/Wrapper.js +0 -281
- package/src/js/components/DateTimePicker/contexts/status-context.js +0 -19
- package/src/js/components/DateTimePicker/contexts/status-reducer.js +0 -276
- package/src/js/components/DateTimePicker/contexts/theme-context.js +0 -33
- package/src/js/components/DateTimePicker/helpers/theming.js +0 -49
- package/src/js/components/DateTimePicker/scss/_base.buttons.scss +0 -58
- package/src/js/components/DateTimePicker/scss/_base.layout.scss +0 -28
- package/src/js/components/DateTimePicker/scss/_base.theme.scss +0 -17
- package/src/js/components/DateTimePicker/scss/_components.calendargrid.scss +0 -78
- package/src/js/components/DateTimePicker/scss/_components.calendarheader.scss +0 -71
- package/src/js/components/DateTimePicker/scss/_components.confirm.scss +0 -40
- package/src/js/components/DateTimePicker/scss/_components.details.scss +0 -20
- package/src/js/components/DateTimePicker/scss/_components.error.scss +0 -34
- package/src/js/components/DateTimePicker/scss/_components.loading.scss +0 -36
- package/src/js/components/DateTimePicker/scss/_components.slotslist.scss +0 -43
- package/src/js/components/DateTimePicker/scss/_components.timezoneselector.scss +0 -73
- package/src/js/components/DateTimePicker/scss/_generic.reset.scss +0 -18
- package/src/js/components/DateTimePicker/scss/_settings.colours.scss +0 -17
- package/src/js/components/DateTimePicker/scss/datetimepicker.scss +0 -5
- package/src/js/components/DateTimePicker/utils/calendar-keyboard.js +0 -109
- package/src/js/components/DateTimePicker/utils/calendar.js +0 -125
- package/src/js/components/DateTimePicker/utils/slots.js +0 -288
- package/src/js/components/SlotPicker/Confirm.js +0 -160
- package/src/js/components/SlotPicker/Days.js +0 -58
- package/src/js/components/SlotPicker/Slot.js +0 -72
- package/src/js/components/SlotPicker/SlotPicker.js +0 -292
- package/src/js/components/SlotPicker/Slots.js +0 -66
- package/src/js/components/SlotPicker/TimeSlots.js +0 -91
- package/src/js/components/generic/Button.js +0 -26
- package/src/js/components/generic/Container.js +0 -33
- package/src/js/components/generic/Error.js +0 -77
- package/src/js/components/generic/Loading.js +0 -51
- package/src/js/components/generic/LoadingSpinner.js +0 -30
- package/src/js/components/generic/ShadowScrollbars.js +0 -70
- package/src/js/components/generic/TimeZoneSelector.js +0 -158
- package/src/js/components/generic/TransitionSlide.js +0 -72
- package/src/js/contexts/i18n-context.js +0 -25
- package/src/js/contexts/log-context.js +0 -18
- package/src/js/contexts/tz-context.js +0 -18
- package/src/js/env.example.js +0 -8
- package/src/js/helpers/colors.js +0 -33
- package/src/js/helpers/comparators.AvailabilityViewer.js +0 -27
- package/src/js/helpers/connections.js +0 -370
- package/src/js/helpers/events.js +0 -166
- package/src/js/helpers/functional.js +0 -4
- package/src/js/helpers/generator.js +0 -107
- package/src/js/helpers/i18n.js +0 -153
- package/src/js/helpers/init.Agenda.js +0 -55
- package/src/js/helpers/init.AvailabilityRules.js +0 -195
- package/src/js/helpers/init.AvailabilityViewer.js +0 -215
- package/src/js/helpers/init.CalendarSync.js +0 -83
- package/src/js/helpers/init.DateTimePicker.js +0 -219
- package/src/js/helpers/init.SlotPicker.js +0 -89
- package/src/js/helpers/init.js +0 -308
- package/src/js/helpers/logging.js +0 -78
- package/src/js/helpers/mocks.js +0 -871
- package/src/js/helpers/slots.js +0 -340
- package/src/js/helpers/slots.rules.js +0 -220
- package/src/js/helpers/theming.js +0 -93
- package/src/js/helpers/translations.js +0 -42
- package/src/js/helpers/tz-list.js +0 -136
- package/src/js/helpers/utils.AvailabilityRules.js +0 -110
- package/src/js/helpers/utils.AvailabilityViewer.js +0 -789
- package/src/js/helpers/utils.CalendarSync.js +0 -199
- package/src/js/helpers/utils.js +0 -76
- package/src/js/hooks/useWindowSize.js +0 -20
- package/src/js/main.js +0 -133
- package/src/js/next.js +0 -37
- package/src/js/styles/_settings.utils.scss +0 -82
- package/src/js/styles/colors.js +0 -13
- package/src/js/styles/global.js +0 -49
- package/src/js/styles/utils.js +0 -81
- package/src/js/translations/de/agenda.json +0 -12
- package/src/js/translations/de/availability_rules.json +0 -18
- package/src/js/translations/de/availability_viewer.json +0 -14
- package/src/js/translations/de/calendar_sync.json +0 -14
- package/src/js/translations/de/core.json +0 -15
- package/src/js/translations/de/date_time_picker.json +0 -14
- package/src/js/translations/de/slot_picker.json +0 -9
- package/src/js/translations/de/time_zones.json +0 -135
- package/src/js/translations/en/agenda.json +0 -12
- package/src/js/translations/en/availability_rules.json +0 -18
- package/src/js/translations/en/availability_viewer.json +0 -14
- package/src/js/translations/en/calendar_sync.json +0 -14
- package/src/js/translations/en/core.json +0 -23
- package/src/js/translations/en/date_time_picker.json +0 -15
- package/src/js/translations/en/slot_picker.json +0 -9
- package/src/js/translations/en/time_zones.json +0 -17
- package/src/js/translations/es/agenda.json +0 -12
- package/src/js/translations/es/availability_rules.json +0 -18
- package/src/js/translations/es/availability_viewer.json +0 -14
- package/src/js/translations/es/calendar_sync.json +0 -14
- package/src/js/translations/es/core.json +0 -15
- package/src/js/translations/es/date_time_picker.json +0 -14
- package/src/js/translations/es/slot_picker.json +0 -9
- package/src/js/translations/es/time_zones.json +0 -203
- package/src/js/translations/fr/agenda.json +0 -12
- package/src/js/translations/fr/availability_rules.json +0 -18
- package/src/js/translations/fr/availability_viewer.json +0 -14
- package/src/js/translations/fr/calendar_sync.json +0 -14
- package/src/js/translations/fr/core.json +0 -15
- package/src/js/translations/fr/date_time_picker.json +0 -14
- package/src/js/translations/fr/slot_picker.json +0 -9
- package/src/js/translations/fr/time_zones.json +0 -161
- package/src/js/translations/fr-CA/agenda.json +0 -12
- package/src/js/translations/fr-CA/availability_rules.json +0 -18
- package/src/js/translations/fr-CA/availability_viewer.json +0 -14
- package/src/js/translations/fr-CA/calendar_sync.json +0 -14
- package/src/js/translations/fr-CA/core.json +0 -23
- package/src/js/translations/fr-CA/date_time_picker.json +0 -14
- package/src/js/translations/fr-CA/slot_picker.json +0 -9
- package/src/js/translations/fr-CA/time_zones.json +0 -163
- package/src/js/translations/it/agenda.json +0 -12
- package/src/js/translations/it/availability_rules.json +0 -18
- package/src/js/translations/it/availability_viewer.json +0 -14
- package/src/js/translations/it/calendar_sync.json +0 -14
- package/src/js/translations/it/core.json +0 -15
- package/src/js/translations/it/date_time_picker.json +0 -14
- package/src/js/translations/it/slot_picker.json +0 -9
- package/src/js/translations/it/time_zones.json +0 -126
- package/src/js/translations/ja/agenda.json +0 -12
- package/src/js/translations/ja/availability_rules.json +0 -18
- package/src/js/translations/ja/availability_viewer.json +0 -14
- package/src/js/translations/ja/calendar_sync.json +0 -14
- package/src/js/translations/ja/core.json +0 -15
- package/src/js/translations/ja/date_formats.json +0 -5
- package/src/js/translations/ja/date_time_picker.json +0 -14
- package/src/js/translations/ja/slot_picker.json +0 -9
- package/src/js/translations/ja/time_zones.json +0 -435
- package/src/js/translations/nl/agenda.json +0 -12
- package/src/js/translations/nl/availability_rules.json +0 -18
- package/src/js/translations/nl/availability_viewer.json +0 -14
- package/src/js/translations/nl/calendar_sync.json +0 -14
- package/src/js/translations/nl/core.json +0 -15
- package/src/js/translations/nl/date_time_picker.json +0 -14
- package/src/js/translations/nl/slot_picker.json +0 -9
- package/src/js/translations/nl/time_zones.json +0 -118
- package/src/js/translations/ru/agenda.json +0 -12
- package/src/js/translations/ru/availability_rules.json +0 -18
- package/src/js/translations/ru/availability_viewer.json +0 -14
- package/src/js/translations/ru/calendar_sync.json +0 -14
- package/src/js/translations/ru/core.json +0 -15
- package/src/js/translations/ru/date_time_picker.json +0 -14
- package/src/js/translations/ru/slot_picker.json +0 -9
- package/src/js/translations/ru/time_zones.json +0 -435
- package/src/js/translations/sv/agenda.json +0 -12
- package/src/js/translations/sv/availability_rules.json +0 -18
- package/src/js/translations/sv/availability_viewer.json +0 -14
- package/src/js/translations/sv/calendar_sync.json +0 -14
- package/src/js/translations/sv/core.json +0 -15
- package/src/js/translations/sv/date_time_picker.json +0 -14
- package/src/js/translations/sv/slot_picker.json +0 -9
- package/src/js/translations/sv/time_zones.json +0 -136
- package/tests/AvailabilityRules/AvailabilityRules.test.js +0 -39
- package/tests/AvailabilityRules/__snapshots__/AvailabilityRules.test.js.snap +0 -1045
- package/tests/AvailabilityViewer/Navigation.test.js +0 -130
- package/tests/AvailabilityViewer/contexts/page-reducer.test.js +0 -87
- package/tests/AvailabilityViewer/reducer.test.js +0 -73
- package/tests/CalendarSync/Active.test.js +0 -25
- package/tests/CalendarSync/AddToggle.test.js +0 -57
- package/tests/CalendarSync/EditToggle.test.js +0 -57
- package/tests/CalendarSync/Inactive.test.js +0 -26
- package/tests/CalendarSync/Pending.test.js +0 -25
- package/tests/CalendarSync/ProviderLogo.test.js +0 -95
- package/tests/CalendarSync/__snapshots__/Active.test.js.snap +0 -61
- package/tests/CalendarSync/__snapshots__/Inactive.test.js.snap +0 -78
- package/tests/CalendarSync/__snapshots__/Pending.test.js.snap +0 -90
- package/tests/CalendarSync/__snapshots__/ProviderLogo.test.js.snap +0 -267
- package/tests/CalendarSync/init.CalendarSync.test.js +0 -302
- package/tests/CalendarSync/mocks/theme.js +0 -14
- package/tests/CalendarSync/status-reducer.test.js +0 -435
- package/tests/DateTimePicker/SequencedSlotButton.test.js +0 -157
- package/tests/DateTimePicker/SlotButton.test.js +0 -118
- package/tests/DateTimePicker/contexts/status-reducer.test.js +0 -1036
- package/tests/DateTimePicker/dummy-data.js +0 -883
- package/tests/DateTimePicker/utils.test.js +0 -515
- package/tests/colors.test.js +0 -70
- package/tests/components/TimezoneSelector.test.js +0 -124
- package/tests/components/main.test.js +0 -203
- package/tests/components/rtl-utils.js +0 -32
- package/tests/connections.test.js +0 -684
- package/tests/events.test.js +0 -472
- package/tests/generator.test.js +0 -74
- package/tests/i18n.test.js +0 -255
- package/tests/init.Agenda.test.js +0 -122
- package/tests/init.AvailabilityRules.test.js +0 -279
- package/tests/init.AvailabilityViewer.test.js +0 -740
- package/tests/init.SlotPicker.test.js +0 -166
- package/tests/init.test.js +0 -231
- package/tests/logging.test.js +0 -235
- package/tests/mocks/i18n.js +0 -3
- package/tests/mocks/theme.js +0 -3
- package/tests/setupJest.js +0 -8
- package/tests/slots.rules.test.js +0 -195
- package/tests/slots.test.js +0 -278
- package/tests/utils.AvailabilityRules.test.js +0 -221
- package/tests/utils.AvailabilityViewer.test.js +0 -1800
- package/tests/utils.CalendarSync.test.js +0 -277
- package/tests/utils.test.js +0 -119
- package/webpack.config.js +0 -114
|
@@ -1,789 +0,0 @@
|
|
|
1
|
-
import moment from "moment-timezone";
|
|
2
|
-
import {
|
|
3
|
-
createEmptySlotsForPeriod,
|
|
4
|
-
getMonthsDescription,
|
|
5
|
-
roundPeriod,
|
|
6
|
-
keyFormat,
|
|
7
|
-
shortKeyFormat,
|
|
8
|
-
} from "./slots";
|
|
9
|
-
import { objectToArray } from "./utils";
|
|
10
|
-
import { timeLabels } from "./slots";
|
|
11
|
-
|
|
12
|
-
// Use the slot's "start" time-string as the
|
|
13
|
-
// key (for quicker/simpler look-up later)
|
|
14
|
-
export const addKeysToSlots = rawSlots => {
|
|
15
|
-
if (rawSlots) {
|
|
16
|
-
return rawSlots.reduce((acc, curr) => {
|
|
17
|
-
acc[curr.start] = curr;
|
|
18
|
-
return acc;
|
|
19
|
-
}, {});
|
|
20
|
-
} else {
|
|
21
|
-
return {};
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const sortKeys = keys =>
|
|
26
|
-
keys.sort((a, b) => {
|
|
27
|
-
if (moment.utc(a) < moment.utc(b)) {
|
|
28
|
-
return -1;
|
|
29
|
-
}
|
|
30
|
-
if (moment.utc(a) > moment.utc(b)) {
|
|
31
|
-
return 1;
|
|
32
|
-
}
|
|
33
|
-
return 0;
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
export const getMinMaxDates = (queryPeriods = false) => {
|
|
37
|
-
if (!queryPeriods || Object.keys(queryPeriods).length < 1) {
|
|
38
|
-
return {
|
|
39
|
-
min: moment.utc().format("YYYY-MM-DD"),
|
|
40
|
-
max: moment.utc().add(1, "days").format("YYYY-MM-DD"),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const startDates = sortKeys(Object.keys(queryPeriods));
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
min: moment
|
|
48
|
-
.utc(queryPeriods[startDates[0]].start, "YYYY-MM-DDTHH:mm:00Z")
|
|
49
|
-
.local()
|
|
50
|
-
.format("YYYY-MM-DD"),
|
|
51
|
-
max: moment
|
|
52
|
-
.utc(queryPeriods[startDates[startDates.length - 1]].end, "YYYY-MM-DDTHH:mm:00Z")
|
|
53
|
-
.local()
|
|
54
|
-
.format("YYYY-MM-DD"),
|
|
55
|
-
};
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export const buildDayPeriod = (startTime, endTime, day, tzid) => {
|
|
59
|
-
const localStart = `${day}T${startTime}`;
|
|
60
|
-
const localEnd = `${day}T${endTime}`;
|
|
61
|
-
const UTCStart = moment.tz(localStart, "YYYY-MM-DDTHH:mm", tzid).utc();
|
|
62
|
-
const UTCEnd = moment.tz(localEnd, "YYYY-MM-DDTHH:mm", tzid).utc();
|
|
63
|
-
|
|
64
|
-
const is24Hours = startTime === endTime;
|
|
65
|
-
if (is24Hours) {
|
|
66
|
-
UTCEnd.add(1, "days");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// An end-time of midnight will always be at the *end* of our
|
|
70
|
-
// target day (a.k.a. the very start of the following day)
|
|
71
|
-
const localMidnight = moment(`${day}T00:00`, "YYYY-MM-DDTHH:mm");
|
|
72
|
-
if (UTCEnd.diff(localMidnight, "minutes") === 0) {
|
|
73
|
-
UTCEnd.add(1, "days");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const start = UTCStart.format("YYYY-MM-DDTHH:mm[:00Z]");
|
|
77
|
-
const end = UTCEnd.format("YYYY-MM-DDTHH:mm[:00Z]");
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
start,
|
|
81
|
-
end,
|
|
82
|
-
};
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export const getDaysForWeek = startDate => {
|
|
86
|
-
const start = startDate.clone();
|
|
87
|
-
return [
|
|
88
|
-
start.format("YYYY-MM-DD"),
|
|
89
|
-
start.add(1, "days").format("YYYY-MM-DD"),
|
|
90
|
-
start.add(1, "days").format("YYYY-MM-DD"),
|
|
91
|
-
start.add(1, "days").format("YYYY-MM-DD"),
|
|
92
|
-
start.add(1, "days").format("YYYY-MM-DD"),
|
|
93
|
-
start.add(1, "days").format("YYYY-MM-DD"),
|
|
94
|
-
start.add(1, "days").format("YYYY-MM-DD"),
|
|
95
|
-
];
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export const getDayOffset = (day, target = "sunday") => {
|
|
99
|
-
const dayNumbers = {
|
|
100
|
-
sunday: 0,
|
|
101
|
-
monday: 1,
|
|
102
|
-
tuesday: 2,
|
|
103
|
-
wednesday: 3,
|
|
104
|
-
thursday: 4,
|
|
105
|
-
friday: 5,
|
|
106
|
-
saturday: 6,
|
|
107
|
-
};
|
|
108
|
-
const diff = dayNumbers[day] - dayNumbers[target];
|
|
109
|
-
const adjustedDiff = diff < 0 ? diff + 7 : diff;
|
|
110
|
-
return adjustedDiff;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
export const getStartDate = (dateObject, targetDayName) => {
|
|
114
|
-
// Belt and braces: we *need* this value to be a lowercase day-name in English
|
|
115
|
-
// regardless of whatever locale or format moment might try to give us if left
|
|
116
|
-
// to its own devices.
|
|
117
|
-
const dateDayName = dateObject.clone().locale("en").format("dddd").toLowerCase();
|
|
118
|
-
|
|
119
|
-
const offset = getDayOffset(dateDayName, targetDayName);
|
|
120
|
-
return dateObject.subtract(offset, "days");
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
export const getPageCount = (weekStartDate, end, count = 1) => {
|
|
124
|
-
const weekEndDate = weekStartDate.clone().add(7, "days");
|
|
125
|
-
const endDiff = end.diff(weekEndDate, "days");
|
|
126
|
-
if (endDiff < 0) {
|
|
127
|
-
return count;
|
|
128
|
-
}
|
|
129
|
-
return getPageCount(weekEndDate, end, count + 1);
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export const getAllWeekDays = ({ startDate, endDate, startDay = "sunday", tzid }) => {
|
|
133
|
-
const start = moment.tz(startDate, "YYYY-MM-DD", tzid);
|
|
134
|
-
const end = moment.tz(endDate, "YYYY-MM-DD", tzid);
|
|
135
|
-
|
|
136
|
-
const weekStartDate = getStartDate(start, startDay);
|
|
137
|
-
|
|
138
|
-
const weekCount = getPageCount(weekStartDate, end);
|
|
139
|
-
|
|
140
|
-
let weeks = [];
|
|
141
|
-
for (let i = 0; i < weekCount; i++) {
|
|
142
|
-
weeks.push(...getDaysForWeek(weekStartDate.clone().add(i * 7, "days")));
|
|
143
|
-
}
|
|
144
|
-
return weeks;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
export const getWeeksInfo = weekdays => {
|
|
148
|
-
const current = 1;
|
|
149
|
-
const total = Math.ceil(weekdays.length / 7);
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
set: true,
|
|
153
|
-
days: weekdays,
|
|
154
|
-
total,
|
|
155
|
-
current,
|
|
156
|
-
hasNext: current < total,
|
|
157
|
-
hasPrev: false,
|
|
158
|
-
};
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
export const checkWeekdaysSlotAvailability = (
|
|
162
|
-
weekdaysEmpties,
|
|
163
|
-
availablePeriods,
|
|
164
|
-
selectedSlots,
|
|
165
|
-
duration,
|
|
166
|
-
interval,
|
|
167
|
-
unrestricted
|
|
168
|
-
) => {
|
|
169
|
-
const slotsPerSelection = duration / interval;
|
|
170
|
-
|
|
171
|
-
const relativeSlot = (slot, offset) => slot.clone().add(offset * interval, "minutes");
|
|
172
|
-
|
|
173
|
-
const slotKey = slot => slot.format(shortKeyFormat);
|
|
174
|
-
|
|
175
|
-
const allAvailableSlots = {};
|
|
176
|
-
Object.values(availablePeriods).forEach(ap => {
|
|
177
|
-
let slotStart = moment.utc(ap.start);
|
|
178
|
-
const apEnd = moment.utc(ap.end);
|
|
179
|
-
|
|
180
|
-
while (slotStart < apEnd) {
|
|
181
|
-
allAvailableSlots[slotKey(slotStart)] = ap;
|
|
182
|
-
slotStart = relativeSlot(slotStart, 1);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
const allSlotsInSelections = {};
|
|
187
|
-
Object.keys(selectedSlots).forEach(selected => {
|
|
188
|
-
const selectedSlot = moment.utc(selected, keyFormat);
|
|
189
|
-
for (let i = 0; i < slotsPerSelection; i++) {
|
|
190
|
-
const slot = relativeSlot(selectedSlot, i);
|
|
191
|
-
allSlotsInSelections[slotKey(slot)] = slot;
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
const slotSelectable = slot => {
|
|
196
|
-
if (allSlotsInSelections[slot.start]) {
|
|
197
|
-
return false;
|
|
198
|
-
} else if (unrestricted) {
|
|
199
|
-
return true;
|
|
200
|
-
} else {
|
|
201
|
-
return !!allAvailableSlots[slot.start];
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const newParsedSlot = (start, lastSelectableMoment) => {
|
|
206
|
-
const startKey = slotKey(start);
|
|
207
|
-
const slotEnd = start.clone().add(duration, "minutes");
|
|
208
|
-
const endKey = slotKey(slotEnd);
|
|
209
|
-
const availableSlot = allAvailableSlots[startKey];
|
|
210
|
-
const visiblyAvailable = !!availableSlot && startKey <= lastSelectableMoment;
|
|
211
|
-
const participants = !!availableSlot ? availableSlot.participants : [];
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
startMoment: start,
|
|
215
|
-
start: startKey,
|
|
216
|
-
end: endKey,
|
|
217
|
-
available: false, // Can it actually be selected?
|
|
218
|
-
visiblyAvailable: visiblyAvailable, // is it availble in the calendar
|
|
219
|
-
blocked: false,
|
|
220
|
-
selected: false,
|
|
221
|
-
target: false,
|
|
222
|
-
targetOffset: 0,
|
|
223
|
-
participants: participants,
|
|
224
|
-
};
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
// If a slot is `available` then it can be selected by a user.
|
|
228
|
-
//
|
|
229
|
-
// If a slot is `visiblyAvailable`, it cannot be directly selected, but
|
|
230
|
-
// should be displayed as "available" (because it falls in the duration
|
|
231
|
-
// overflow)
|
|
232
|
-
//
|
|
233
|
-
// If a slot is `blocked` it would normally be available, but is currently
|
|
234
|
-
// unselectable becasue of an existing user selection (this is a dynamic
|
|
235
|
-
// effect, and not set here).
|
|
236
|
-
|
|
237
|
-
return weekdaysEmpties.map(day => {
|
|
238
|
-
const parsedSlots = {};
|
|
239
|
-
const lastSlotOfTheDay = day.slots[day.slots.length - 1];
|
|
240
|
-
const lastSelectableMoment = lastSlotOfTheDay.end;
|
|
241
|
-
|
|
242
|
-
// Pre-generate all the slot objects for the day
|
|
243
|
-
day.slots.forEach(slot => {
|
|
244
|
-
const slotStart = moment.utc(slot.start, keyFormat);
|
|
245
|
-
const newSlot = newParsedSlot(slotStart, lastSelectableMoment);
|
|
246
|
-
parsedSlots[slot.start] = newSlot;
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
// March foward through each slot, seeing if the window of slots ahead of it can be selected
|
|
250
|
-
day.slots.forEach(slot => {
|
|
251
|
-
const parsedSlot = parsedSlots[slot.start];
|
|
252
|
-
|
|
253
|
-
// Even if this one is available, the slot would overun the end of the element
|
|
254
|
-
if (parsedSlot.end > lastSelectableMoment) return;
|
|
255
|
-
|
|
256
|
-
// If we click this Slot, which other slots will need to be selected?
|
|
257
|
-
const additionalSlotsForSelection = [];
|
|
258
|
-
for (let i = 0; i < slotsPerSelection; i++) {
|
|
259
|
-
const windowSlot = relativeSlot(parsedSlot.startMoment, i);
|
|
260
|
-
const windowParsedSlot = parsedSlots[slotKey(windowSlot)];
|
|
261
|
-
if (windowParsedSlot) additionalSlotsForSelection.push(windowParsedSlot);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Are all of the slots we need selectable?
|
|
265
|
-
if (additionalSlotsForSelection.every(slotSelectable)) {
|
|
266
|
-
// Yes, set all of the slots in the window to use the current slot as their parent
|
|
267
|
-
additionalSlotsForSelection.forEach((windowParsedSlot, offset) => {
|
|
268
|
-
if (offset === 0) {
|
|
269
|
-
// Slot is the start of a selectable group
|
|
270
|
-
windowParsedSlot.available = true;
|
|
271
|
-
windowParsedSlot.target = false;
|
|
272
|
-
windowParsedSlot.targetOffset = false;
|
|
273
|
-
} else {
|
|
274
|
-
// Slot is the part of a selectable group
|
|
275
|
-
windowParsedSlot.target = slot.start;
|
|
276
|
-
windowParsedSlot.targetOffset = slotsPerSelection - offset;
|
|
277
|
-
}
|
|
278
|
-
parsedSlots[windowParsedSlot.start] = windowParsedSlot;
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
const daySlots = Object.values(parsedSlots);
|
|
284
|
-
return {
|
|
285
|
-
day: day.day,
|
|
286
|
-
slots: daySlots,
|
|
287
|
-
};
|
|
288
|
-
});
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
export const checkWeekdaysSlotAvailabilityFreeSelect = (weekdaysEmpties, availablePeriods) => {
|
|
292
|
-
return weekdaysEmpties.map(day => ({
|
|
293
|
-
...day,
|
|
294
|
-
slots: day.slots.map(slot => {
|
|
295
|
-
const withinPeriod = Object.keys(availablePeriods).map(periodKey => {
|
|
296
|
-
const period = availablePeriods[periodKey];
|
|
297
|
-
return slot.start >= period.start && slot.end <= period.end;
|
|
298
|
-
});
|
|
299
|
-
const result = withinPeriod.reduce((bool, acc) => {
|
|
300
|
-
if (bool) {
|
|
301
|
-
return true;
|
|
302
|
-
} else {
|
|
303
|
-
return acc;
|
|
304
|
-
}
|
|
305
|
-
}, false);
|
|
306
|
-
return { ...slot, visiblyAvailable: result };
|
|
307
|
-
}),
|
|
308
|
-
}));
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
export const generatePageSlots = (
|
|
312
|
-
{ availablePeriods, selectedSlots, limits, pages, tzid, unrestricted, freeSelect = false },
|
|
313
|
-
getEmpties = createEmptySlotsForPeriod,
|
|
314
|
-
buildPeriod = buildDayPeriod
|
|
315
|
-
) => {
|
|
316
|
-
const weekdaysEmpties = pages.days.reduce((acc, day) => {
|
|
317
|
-
const dayPeriod = buildPeriod(limits.start, limits.end, day, tzid);
|
|
318
|
-
|
|
319
|
-
// Make sure the period starts on a round value (according to the duration)
|
|
320
|
-
const roundedPeriod = roundPeriod(dayPeriod, limits.duration);
|
|
321
|
-
|
|
322
|
-
acc.push({
|
|
323
|
-
day: day,
|
|
324
|
-
slots: getEmpties(roundedPeriod, limits.interval, tzid),
|
|
325
|
-
});
|
|
326
|
-
return acc;
|
|
327
|
-
}, []);
|
|
328
|
-
|
|
329
|
-
let allSlots = [];
|
|
330
|
-
if (freeSelect) {
|
|
331
|
-
allSlots = checkWeekdaysSlotAvailabilityFreeSelect(weekdaysEmpties, availablePeriods);
|
|
332
|
-
} else {
|
|
333
|
-
const currentPage = pages.current || 1;
|
|
334
|
-
const day0 = (currentPage - 1) * 7;
|
|
335
|
-
const day7 = currentPage * 7;
|
|
336
|
-
const daysToProcess = weekdaysEmpties.slice(day0, day7);
|
|
337
|
-
allSlots = checkWeekdaysSlotAvailability(
|
|
338
|
-
daysToProcess,
|
|
339
|
-
availablePeriods,
|
|
340
|
-
selectedSlots,
|
|
341
|
-
limits.duration,
|
|
342
|
-
limits.interval,
|
|
343
|
-
unrestricted
|
|
344
|
-
);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
return {
|
|
348
|
-
pages,
|
|
349
|
-
slots: allSlots,
|
|
350
|
-
};
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
export const createExportableSelection = slots => objectToArray(slots).map(item => item.value.slot);
|
|
354
|
-
|
|
355
|
-
export const checkBlockedSlots = ({ slots, selected, duration = 60, interval = 60 }) => {
|
|
356
|
-
const intervalsPerSlot = duration / interval;
|
|
357
|
-
|
|
358
|
-
let precedingBlocks = [];
|
|
359
|
-
let selectedBlocks = [];
|
|
360
|
-
|
|
361
|
-
// We just need the `start` string values (used as the keys for the selected
|
|
362
|
-
// slots object).
|
|
363
|
-
const selectedKeys = Object.keys(selected);
|
|
364
|
-
|
|
365
|
-
selectedKeys.map(key => {
|
|
366
|
-
const blockSource = moment(key, "YYYY-MM-DDTHH:mm:00Z");
|
|
367
|
-
for (let i = 1; i < intervalsPerSlot; i++) {
|
|
368
|
-
// Get the `start` string for any slots directly covered
|
|
369
|
-
// by the current selection.
|
|
370
|
-
const selectedKey = blockSource
|
|
371
|
-
.clone()
|
|
372
|
-
.utc()
|
|
373
|
-
.add(i * interval, "minutes")
|
|
374
|
-
.format("YYYY-MM-DDTHH:mm[:00Z]");
|
|
375
|
-
selectedBlocks.push(selectedKey);
|
|
376
|
-
|
|
377
|
-
// Get the `start` string for any preceding slots that would
|
|
378
|
-
// overlap the selected slot.
|
|
379
|
-
const precedingOverlapKey = blockSource
|
|
380
|
-
.clone()
|
|
381
|
-
.utc()
|
|
382
|
-
.subtract(i * interval, "minutes")
|
|
383
|
-
.format("YYYY-MM-DDTHH:mm[:00Z]");
|
|
384
|
-
precedingBlocks.push(precedingOverlapKey);
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
const blockedSlots = slots.map(day => ({
|
|
389
|
-
...day,
|
|
390
|
-
slots: day.slots.map(slot => {
|
|
391
|
-
// Is this slot a `preceding` slot? (if so, it should be blocked).
|
|
392
|
-
const precedingBlockStatus = precedingBlocks.includes(slot.start);
|
|
393
|
-
|
|
394
|
-
// Is this slot at the end of an available period *and* with the overlap
|
|
395
|
-
// region of a selected slot? (if so, it should be blocked).
|
|
396
|
-
const followingBlockStatus = slot.target && selectedBlocks.includes(slot.target);
|
|
397
|
-
|
|
398
|
-
const blockStatus = precedingBlockStatus || followingBlockStatus || false;
|
|
399
|
-
return {
|
|
400
|
-
...slot,
|
|
401
|
-
blocked: blockStatus,
|
|
402
|
-
};
|
|
403
|
-
}),
|
|
404
|
-
}));
|
|
405
|
-
return blockedSlots;
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
export const generateStaticPages = (queryPeriods, startDay, tzid) => {
|
|
409
|
-
const periodsWithKeys = addKeysToSlots(queryPeriods);
|
|
410
|
-
const minMax = getMinMaxDates(periodsWithKeys);
|
|
411
|
-
const weekdays = getAllWeekDays({
|
|
412
|
-
startDate: minMax.min,
|
|
413
|
-
endDate: minMax.max,
|
|
414
|
-
startDay: startDay,
|
|
415
|
-
tzid: tzid,
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
const weeks = getWeeksInfo(weekdays);
|
|
419
|
-
return weeks;
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
export const divideDaysIntoWeeks = (days, currentPage) =>
|
|
423
|
-
[...days].slice((currentPage - 1) * 7, currentPage * 7);
|
|
424
|
-
|
|
425
|
-
// compare 2 periods (objects with start/end as moment instances).
|
|
426
|
-
// If they overlap, return that overlapping period as an object
|
|
427
|
-
// with start/end as "YYYY-MM-DDTHH:mm:00Z" strings.
|
|
428
|
-
// If they don't, return false.
|
|
429
|
-
export const periodOverlap = (testPeriod, wrapper) => {
|
|
430
|
-
// If `testPeriod` ends before `wrapper` starts, then there's no overlap
|
|
431
|
-
const endsBefore = testPeriod.end.diff(wrapper.start, "hours");
|
|
432
|
-
if (endsBefore <= 0) return false;
|
|
433
|
-
|
|
434
|
-
// If `wrapper` starts after `testPeriod` ends, then there's no overlap
|
|
435
|
-
const startsAfter = testPeriod.start.diff(wrapper.end, "hours");
|
|
436
|
-
if (startsAfter >= 0) return false;
|
|
437
|
-
|
|
438
|
-
const startDiff = wrapper.start.diff(testPeriod.start, "minutes");
|
|
439
|
-
const endDiff = testPeriod.end.diff(wrapper.end, "minutes");
|
|
440
|
-
|
|
441
|
-
const newStart =
|
|
442
|
-
startDiff < 0
|
|
443
|
-
? testPeriod.start.format("YYYY-MM-DDTHH:mm[:00Z]")
|
|
444
|
-
: wrapper.start.format("YYYY-MM-DDTHH:mm[:00Z]");
|
|
445
|
-
const newEnd =
|
|
446
|
-
endDiff < 0
|
|
447
|
-
? testPeriod.end.format("YYYY-MM-DDTHH:mm[:00Z]")
|
|
448
|
-
: wrapper.end.format("YYYY-MM-DDTHH:mm[:00Z]");
|
|
449
|
-
const newPeriod = { start: newStart, end: newEnd };
|
|
450
|
-
return newPeriod;
|
|
451
|
-
};
|
|
452
|
-
|
|
453
|
-
export const cropQuery = (query, extent, ignoreWeeks = false) => {
|
|
454
|
-
let days;
|
|
455
|
-
if (ignoreWeeks) {
|
|
456
|
-
days = extent.days;
|
|
457
|
-
} else {
|
|
458
|
-
days = divideDaysIntoWeeks(extent.days, extent.currentPage);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// These are the bounds within which our query should live:
|
|
462
|
-
const bounds = days.map(day => {
|
|
463
|
-
const localStart = extent.startTime;
|
|
464
|
-
const localEnd = extent.endTime;
|
|
465
|
-
|
|
466
|
-
const startTime = moment.tz(`${day}T${localStart}`, "YYYY-MM-DDTHH:mm", extent.tzid).utc();
|
|
467
|
-
|
|
468
|
-
const endTimeRaw = moment.tz(`${day}T${localEnd}`, "YYYY-MM-DDTHH:mm", extent.tzid).utc();
|
|
469
|
-
|
|
470
|
-
// If the endTime is an earlier hour than the startTime, that means
|
|
471
|
-
// the period overflows a day boundary.
|
|
472
|
-
const isEndBeforeStart = startTime.diff(endTimeRaw, "minutes") > 0;
|
|
473
|
-
|
|
474
|
-
const endTime =
|
|
475
|
-
isEndBeforeStart || extent.startTime === extent.endTime
|
|
476
|
-
? endTimeRaw.add(1, "days")
|
|
477
|
-
: endTimeRaw;
|
|
478
|
-
|
|
479
|
-
return {
|
|
480
|
-
start: startTime,
|
|
481
|
-
end: endTime,
|
|
482
|
-
};
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
const croppedPeriods = bounds.reduce((periodsAccumulator, day) => {
|
|
486
|
-
const newPeriods = query.query_periods
|
|
487
|
-
.map(period => {
|
|
488
|
-
const periodStart = moment.utc(period.start, "YYYY-MM-DDTHH:mm:00Z");
|
|
489
|
-
const periodEnd = moment.utc(period.end, "YYYY-MM-DDTHH:mm:00Z");
|
|
490
|
-
const overlap = periodOverlap({ start: periodStart, end: periodEnd }, day);
|
|
491
|
-
|
|
492
|
-
return overlap;
|
|
493
|
-
})
|
|
494
|
-
.filter(period => period);
|
|
495
|
-
|
|
496
|
-
return [...periodsAccumulator, ...newPeriods];
|
|
497
|
-
}, []);
|
|
498
|
-
|
|
499
|
-
return { ...query, query_periods: croppedPeriods };
|
|
500
|
-
};
|
|
501
|
-
|
|
502
|
-
export const calculateDisplayText = (i18n, slot, status) => {
|
|
503
|
-
const startObject = moment.tz(slot.start, "YYYY-MM-DDTHH:mm:00Z", status.tzid);
|
|
504
|
-
const endObject = moment.tz(slot.end, "YYYY-MM-DDTHH:mm:00Z", status.tzid);
|
|
505
|
-
const startTime = i18n.f(startObject, "LT").replace(" ", "");
|
|
506
|
-
const endTime = i18n.f(endObject, "LT").replace(" ", "");
|
|
507
|
-
|
|
508
|
-
let text;
|
|
509
|
-
switch (status.mode) {
|
|
510
|
-
case "multi_select":
|
|
511
|
-
case "no_confirm":
|
|
512
|
-
text = `${startTime} - ${endTime}`;
|
|
513
|
-
break;
|
|
514
|
-
case "free_select":
|
|
515
|
-
text = "";
|
|
516
|
-
break;
|
|
517
|
-
default:
|
|
518
|
-
text = i18n.t("confirm");
|
|
519
|
-
}
|
|
520
|
-
return {
|
|
521
|
-
time: `${startTime} - ${endTime}`,
|
|
522
|
-
text,
|
|
523
|
-
};
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
export const buildPeriodsFromSlots = slots => {
|
|
527
|
-
const sortedSlots = slots.sort((a, b) => {
|
|
528
|
-
if (a.start < b.start) {
|
|
529
|
-
return -1;
|
|
530
|
-
}
|
|
531
|
-
if (a.start > b.start) {
|
|
532
|
-
return 1;
|
|
533
|
-
}
|
|
534
|
-
return 0;
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
const periods = sortedSlots.reduce((acc, curr, i) => {
|
|
538
|
-
const prev = slots[i - 1];
|
|
539
|
-
|
|
540
|
-
if (!prev) {
|
|
541
|
-
// This is the last slot, so just add it to the array
|
|
542
|
-
return [
|
|
543
|
-
...acc,
|
|
544
|
-
{
|
|
545
|
-
start: curr.start,
|
|
546
|
-
end: curr.end,
|
|
547
|
-
},
|
|
548
|
-
];
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
if (curr.start === prev.end) {
|
|
552
|
-
// This slot abuts the one that came before, so
|
|
553
|
-
// let's remove the previous one and combine it with
|
|
554
|
-
// the current one.
|
|
555
|
-
const lastItem = acc.pop(); // Note: we're relying on pop() mutating acc here
|
|
556
|
-
const combo = {
|
|
557
|
-
start: lastItem.start,
|
|
558
|
-
end: curr.end,
|
|
559
|
-
};
|
|
560
|
-
return [...acc, combo];
|
|
561
|
-
}
|
|
562
|
-
// The slots don't abut, so just add this one
|
|
563
|
-
return [
|
|
564
|
-
...acc,
|
|
565
|
-
{
|
|
566
|
-
start: curr.start,
|
|
567
|
-
end: curr.end,
|
|
568
|
-
},
|
|
569
|
-
];
|
|
570
|
-
}, []);
|
|
571
|
-
|
|
572
|
-
return periods;
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
export const addSlotStarts = (start, interval, count) => {
|
|
576
|
-
const times = [];
|
|
577
|
-
for (let i = 0; i <= count; i++) {
|
|
578
|
-
const time = start.clone().add(i * interval, "minutes");
|
|
579
|
-
times.push(time.format("YYYY-MM-DDTHH:mm[:00Z]"));
|
|
580
|
-
}
|
|
581
|
-
return times;
|
|
582
|
-
};
|
|
583
|
-
|
|
584
|
-
// Given a start and end slot-time, caluculate the start-times
|
|
585
|
-
// of all slots that fall between those times
|
|
586
|
-
export const tweenSlots = ({ start, end, tzid, interval }) => {
|
|
587
|
-
const first = start < end ? start : end;
|
|
588
|
-
const last = start > end ? start : end;
|
|
589
|
-
|
|
590
|
-
const startTime = moment.utc(first, "YYYY-MM-DDTHH:mm:00Z");
|
|
591
|
-
const endTime = moment.utc(last, "YYYY-MM-DDTHH:mm:00Z");
|
|
592
|
-
const diff = endTime.diff(startTime, "minutes");
|
|
593
|
-
|
|
594
|
-
const firstDate = startTime.clone().tz(tzid);
|
|
595
|
-
const lastDate = endTime.clone().tz(tzid);
|
|
596
|
-
if (firstDate.format("YYYY-MM-DD") !== lastDate.format("YYYY-MM-DD")) {
|
|
597
|
-
// The selection spans mulitple days
|
|
598
|
-
const localFirstTime = startTime.clone().tz(tzid).format("HH:mm");
|
|
599
|
-
const localLastTime = endTime.clone().tz(tzid).format("HH:mm");
|
|
600
|
-
const sortedLocalFirstTime =
|
|
601
|
-
localFirstTime < localLastTime ? localFirstTime : localLastTime;
|
|
602
|
-
const sortedLocalLastTime = localFirstTime > localLastTime ? localFirstTime : localLastTime;
|
|
603
|
-
|
|
604
|
-
const timeDiff = moment(sortedLocalLastTime, "HH:mm").diff(
|
|
605
|
-
moment(sortedLocalFirstTime, "HH:mm"),
|
|
606
|
-
"minutes"
|
|
607
|
-
);
|
|
608
|
-
const dayTweenCount = timeDiff / interval;
|
|
609
|
-
|
|
610
|
-
const dayDiff = lastDate
|
|
611
|
-
.clone()
|
|
612
|
-
.endOf("day")
|
|
613
|
-
.diff(firstDate.clone().startOf("day"), "hours");
|
|
614
|
-
const dayCount = Math.floor(dayDiff / 24);
|
|
615
|
-
const dates = [firstDate.format("YYYY-MM-DD")];
|
|
616
|
-
for (let i = 1; i < dayCount; i++) {
|
|
617
|
-
const tweenDay = firstDate.clone().add(i, "days");
|
|
618
|
-
dates.push(tweenDay.format("YYYY-MM-DD"));
|
|
619
|
-
}
|
|
620
|
-
dates.push(lastDate.format("YYYY-MM-DD"));
|
|
621
|
-
|
|
622
|
-
const daysTweens = dates.map(day => {
|
|
623
|
-
const dayStart = moment
|
|
624
|
-
.tz(`${day} ${sortedLocalFirstTime}`, "YYYY-MM-DD HH:mm", tzid)
|
|
625
|
-
.utc();
|
|
626
|
-
|
|
627
|
-
const dayTweens = addSlotStarts(dayStart, interval, dayTweenCount);
|
|
628
|
-
|
|
629
|
-
return dayTweens;
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
const flattenedTweens = [].concat.apply([], daysTweens);
|
|
633
|
-
|
|
634
|
-
return flattenedTweens;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
const tweenCount = diff / interval;
|
|
638
|
-
const tweens = addSlotStarts(startTime, interval, tweenCount);
|
|
639
|
-
return tweens;
|
|
640
|
-
};
|
|
641
|
-
|
|
642
|
-
export const calculateTimeString = (slot, i18n, tzid) => {
|
|
643
|
-
const startTimeString = i18n
|
|
644
|
-
.f(moment(slot.start, "YYYY-MM-DDTHH:mm:00Z").tz(tzid), "LT")
|
|
645
|
-
.replace(" ", "");
|
|
646
|
-
const endTimeString = i18n
|
|
647
|
-
.f(moment(slot.end, "YYYY-MM-DDTHH:mm:00Z").tz(tzid), "LT")
|
|
648
|
-
.replace(" ", "");
|
|
649
|
-
const timeString = `${startTimeString} - ${endTimeString}`;
|
|
650
|
-
return timeString;
|
|
651
|
-
};
|
|
652
|
-
|
|
653
|
-
export const getSelectedSlots = slots => {
|
|
654
|
-
const flattenedSlots = [].concat.apply(
|
|
655
|
-
[],
|
|
656
|
-
slots.map(day => day.slots)
|
|
657
|
-
);
|
|
658
|
-
const selectedSlotsByDay = flattenedSlots.filter(slot => slot.selected);
|
|
659
|
-
return selectedSlotsByDay;
|
|
660
|
-
};
|
|
661
|
-
|
|
662
|
-
export const checkSelectedState = (newSlots, oldSlots) => {
|
|
663
|
-
let selectedTimes = [];
|
|
664
|
-
oldSlots.map(day =>
|
|
665
|
-
day.slots.map(slot => {
|
|
666
|
-
if (slot.selected) {
|
|
667
|
-
selectedTimes.push(slot.start);
|
|
668
|
-
}
|
|
669
|
-
})
|
|
670
|
-
);
|
|
671
|
-
const mergedSlots = newSlots.map(day => ({
|
|
672
|
-
...day,
|
|
673
|
-
slots: day.slots.map(slot => {
|
|
674
|
-
if (selectedTimes.includes(slot.start)) {
|
|
675
|
-
return {
|
|
676
|
-
...slot,
|
|
677
|
-
selected: true,
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
return slot;
|
|
681
|
-
}),
|
|
682
|
-
}));
|
|
683
|
-
return mergedSlots;
|
|
684
|
-
};
|
|
685
|
-
|
|
686
|
-
export const condenseTimeLabel = label =>
|
|
687
|
-
label
|
|
688
|
-
.replace(/[^0-9][0-9]{2} ?/g, "")
|
|
689
|
-
.replace(/m/i, "")
|
|
690
|
-
.replace(" ", "");
|
|
691
|
-
|
|
692
|
-
export const cropDaysToWindow = (rawDays, windowSize = 34) => {
|
|
693
|
-
const days = rawDays.slice(0, windowSize);
|
|
694
|
-
const overflow = rawDays.slice(windowSize - 1, rawDays.length);
|
|
695
|
-
|
|
696
|
-
return { days, overflow };
|
|
697
|
-
};
|
|
698
|
-
|
|
699
|
-
export const getAllLabels = ({ days, limits, tzid, i18n, locale }) => {
|
|
700
|
-
// For each week that the AV could potentially show we
|
|
701
|
-
// want to calculate:
|
|
702
|
-
// 1. An array of days in that week
|
|
703
|
-
// 2. An array of time label info (start-time | end-time | is-hour?)
|
|
704
|
-
// 3. The appropriate month label for the week
|
|
705
|
-
|
|
706
|
-
// Generate an array with one empty item for each week.
|
|
707
|
-
const emptyWeeks = Array.from(new Array(Math.ceil(days.length / 7)));
|
|
708
|
-
|
|
709
|
-
// Add the days to each week.
|
|
710
|
-
const weeksWithDays = emptyWeeks.map((_, i) => {
|
|
711
|
-
const start = i * 7;
|
|
712
|
-
const end = start + 7;
|
|
713
|
-
const weeklyDays = days.slice(start, end);
|
|
714
|
-
const dayObjects = weeklyDays.map(day => {
|
|
715
|
-
const dayObject = moment.tz(day, "YYYY-MM-DD", tzid);
|
|
716
|
-
return {
|
|
717
|
-
date: day,
|
|
718
|
-
number: i18n.f(dayObject, "D"),
|
|
719
|
-
name: i18n.f(dayObject, "ddd"),
|
|
720
|
-
};
|
|
721
|
-
});
|
|
722
|
-
return { days: dayObjects };
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
// Add the time labels to each week.
|
|
726
|
-
const weeksWithTimes = weeksWithDays.map(week => {
|
|
727
|
-
// `days[1]` is the second day in the week (Monday) so that even on
|
|
728
|
-
// weeks where there is a DST transition on a Sunday, the labels are
|
|
729
|
-
// accurate for the main bulk of the days shown.
|
|
730
|
-
return {
|
|
731
|
-
...week,
|
|
732
|
-
times: timeLabels(limits, week.days[1].date, tzid),
|
|
733
|
-
};
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
// Add a month label to each week [TODO]
|
|
737
|
-
const weeksWithMonths = weeksWithTimes.map(week => {
|
|
738
|
-
const simpleDaysArray = week.days.map(day => day.date);
|
|
739
|
-
return {
|
|
740
|
-
...week,
|
|
741
|
-
month: getMonthsDescription(simpleDaysArray, locale),
|
|
742
|
-
};
|
|
743
|
-
});
|
|
744
|
-
|
|
745
|
-
return weeksWithMonths;
|
|
746
|
-
};
|
|
747
|
-
|
|
748
|
-
// Do the days stored in our `allLabels` state match the days
|
|
749
|
-
// in our `pages` context?
|
|
750
|
-
export const checkIfDaysMatch = (days, allLabels) => {
|
|
751
|
-
if (typeof allLabels !== "object" || allLabels.length <= 0) {
|
|
752
|
-
// We have no saved days, so they definitely do not match
|
|
753
|
-
return false;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
// First and last days from `pages`
|
|
757
|
-
const firstDay = days[0];
|
|
758
|
-
const lastDay = days[days.length - 1];
|
|
759
|
-
|
|
760
|
-
// First and last days from `allLabels`
|
|
761
|
-
const firstSavedDay = allLabels[0].days[0].date;
|
|
762
|
-
const lastSavedWeek = allLabels[allLabels.length - 1].days;
|
|
763
|
-
const lastSavedDay = lastSavedWeek[lastSavedWeek.length - 1].date;
|
|
764
|
-
|
|
765
|
-
return firstDay === firstSavedDay && lastDay === lastSavedDay;
|
|
766
|
-
};
|
|
767
|
-
|
|
768
|
-
export const checkIfLimitsMatch = ({ start, end }, times, tzid = "Etc/UTC") => {
|
|
769
|
-
// Get the first start time in `HH:mm` format
|
|
770
|
-
const startTime = moment
|
|
771
|
-
.tz(times[0].start, "YYYY-MM-DDTHH:mm:00Z", tzid)
|
|
772
|
-
.local()
|
|
773
|
-
.format("HH:mm");
|
|
774
|
-
|
|
775
|
-
// Get the last end time in `HH:mm` format
|
|
776
|
-
const rawEndTime = moment
|
|
777
|
-
.tz(times[times.length - 1].end, "YYYY-MM-DDTHH:mm:00Z", tzid)
|
|
778
|
-
.local()
|
|
779
|
-
.format("HH:mm");
|
|
780
|
-
|
|
781
|
-
// Account for limits.end being "24:00"
|
|
782
|
-
const endTime = rawEndTime === "00:00" ? "24:00" : rawEndTime;
|
|
783
|
-
|
|
784
|
-
const startMatches = startTime === start;
|
|
785
|
-
const endMatches = endTime === end;
|
|
786
|
-
|
|
787
|
-
// The limits match the time-labels if *both* start and end match.
|
|
788
|
-
return startMatches && endMatches;
|
|
789
|
-
};
|