Server IP : 85.193.89.191 / Your IP : 3.137.185.59 Web Server : Apache System : Linux 956367-cx40159.tmweb.ru 3.10.0-1160.105.1.el7.x86_64 #1 SMP Thu Dec 7 15:39:45 UTC 2023 x86_64 User : bitrix ( 600) PHP Version : 8.1.27 Disable Function : NONE MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /home/bitrix/www/bitrix/js/calendar/resourcebooking/src/ |
Upload File : |
import {Type, Loc, Dom, Tag, Text, BookingUtil} from "./resourcebooking"; import {EventEmitter, BaseEvent} from 'main.core.events'; import {UserSelector} from "./controls/userselector"; import {ResourceSelector} from "./controls/resourceselector"; import {ServiceSelector} from "./controls/serviceselector"; import {DurationSelector} from "./controls/durationselector"; import {DateSelector} from "./controls/dateselector"; import {TimeSelector} from "./controls/timeselector"; import {StatusInformer} from "./controls/statusinformer"; export class LiveFieldController extends EventEmitter { constructor(params) { super(params); this.setEventNamespace('BX.Calendar.LiveFieldController'); this.params = params; this.actionAgent = params.actionAgent || BX.ajax.runAction; this.timeFrom = params.timeFrom || 7; this.timeTo = params.timeTo || 20; this.inputName = params.field.name + '[]'; this.DATE_FORMAT = BookingUtil.getDateFormat(); this.DATETIME_FORMAT = BookingUtil.getDateTimeFormat(); this.userIndex = null; this.timezoneOffset = null; this.timezoneOffsetLabel = null; this.userFieldParams = null; this.loadedDates = []; this.externalSiteContext = Type.isFunction(params.actionAgent); this.accessibility = { user : {}, resource: {} }; this.busySlotMatrix = { user : {}, resource: {} }; this.DOM = { wrap: this.params.wrap, valueInputs: [] }; } init() { const settingsData = this.getSettingsData(); if (!settingsData.users || !settingsData.resources) { throw new Error('Can\'t init resourcebooking field, because \'settings_data\' parameter is not provided or has incorrect structure'); return; } this.scale = parseInt(settingsData.time && settingsData.time.scale ? settingsData.time.scale : 60, 10); this.DOM.outerWrap = this.DOM.wrap.appendChild(Tag.render`<div class="calendar-resbook-webform-wrapper"></div>`); this.showMainLoader(); this.requireFormData().then(()=>{ this.hideMainLoader(); this.buildFormControls(); this.onChangeValues(); }); } check() { let result = true; if (this.usersDisplayed() && !this.getSelectedUser()) { this.userControl.showWarning(); result = false; } if (result && this.resourcesDisplayed() && !this.getSelectedResources()) { this.resourceControl.showWarning(); result = false; } if (result && !this.getCurrentDuration()) { if (this.durationControl) { this.durationControl.showWarning(); } else if (this.serviceControl) { this.serviceControl.showWarning(); } result = false; } if (result && ( !this.dateControl.getValue() || this.statusControl.isErrorSet() ) ) { this.dateControl.showWarning(); result = false; } if (result && this.timeSelectorDisplayed() && !this.timeControl.getValue()) { this.timeControl.showWarning(); result = false; } return result; } buildFormControls() { this.DOM.innerWrap = this.DOM.outerWrap.appendChild(Tag.render`<div class="calendar-resbook-webform-inner"></div>`); this.DOM.inputsWrap = this.DOM.innerWrap.appendChild(Tag.render`<div></div>`); if (!this.getFieldParams()) { this.statusControl = new StatusInformer({ outerWrap: this.DOM.innerWrap }); this.statusControl.refresh({}); this.statusControl.setError('[UF_NOT_FOUND] ' + Loc.getMessage('WEBF_RES_BOOKING_UF_WARNING')); } else { if (this.externalSiteContext && BX.ZIndexManager) { const stack = BX.ZIndexManager.getOrAddStack(document.body); stack.baseIndex = 100000; stack.sort(); } this.preparaAutoSelectValues(); this.displayUsersControl(); this.displayResourcesControl(); this.displayServicesControl(); this.displayDurationControl(); this.displayDateTimeControl(); if (this.selectedUserId || this.selectedResourceId) { this.refreshControlsState(); } } } refreshControlsState() { if (this.selectorCanBeShown('resources') && this.resourceControl && !this.resourceControl.isShown()) { this.resourceControl.display(); } // Show services if (this.selectorCanBeShown('services') && this.serviceControl && !this.serviceControl.isShown()) { this.serviceControl.display(); } // Show duration if (this.selectorCanBeShown('duration') && this.durationControl && !this.durationControl.isShown()) { this.durationControl.display(); } let settingsData = this.getSettingsData(); // Show date & time control if (this.selectorCanBeShown('date') && this.dateControl) { if (this.dateControl.isShown()) { this.dateControl.refresh( settingsData.date, { availableDateIndex: this.getAvailableDateIndex({ resources: this.getSelectedResources(), user: this.getSelectedUser(), duration: this.getCurrentDuration() }) } ); if (this.timeControl) { this.timeControl.refresh( settingsData.time, { slotIndex: this.getSlotIndex({date: this.dateControl.getValue()}), currentDate: this.dateControl.getValue() }); } } else { let startValue; if (settingsData.date.start === 'free') { startValue = this.getFreeDate({ resources: this.getSelectedResources(), user: this.getSelectedUser(), duration: this.getCurrentDuration() }); } else { startValue = new Date(); } this.dateControl.display({ selectedValue: startValue, availableDateIndex: this.getAvailableDateIndex({ resources: this.getSelectedResources(), user: this.getSelectedUser(), duration: this.getCurrentDuration() }) }); } } this.updateStatusControl(); this.onChangeValues(); BookingUtil.fireCustomEvent(window, 'crmWebFormFireResize'); } onChangeValues() { let allValuesValue = [], dateFromValue = '', dateFrom = this.getCurrentDate(), duration = this.getCurrentDuration() * 60,// Duration in minutes serviceName = this.getCurrentServiceName(), entries = []; // Clear inputs Dom.clean(this.DOM.inputsWrap); this.DOM.valueInputs = []; if (Type.isDate(dateFrom) && !this.statusControl.isErrorSet()) { let resources = this.getSelectedResources(); if (Type.isArray(resources)) { resources.forEach(function(resourceId) { entries = entries.concat({type: 'resource', id: resourceId}); }); } let selectedUser = this.getSelectedUser(); if (selectedUser) { entries = entries.concat({type: 'user', id: selectedUser}); } dateFromValue = BookingUtil.formatDate(this.DATETIME_FORMAT, dateFrom.getTime() / 1000); entries.forEach(function(entry) { let value = entry.type + '|' + entry.id + '|' + dateFromValue + '|' + duration + '|' + serviceName; allValuesValue.push(value); this.DOM.valueInputs.push(this.DOM.inputsWrap.appendChild( Tag.render` <input name="${Text.encode(this.inputName)}" value="${Text.encode(value)}" type="hidden" > ` )); }, this); } if (!entries.length) { allValuesValue.push('empty'); this.DOM.valueInputs.push(this.DOM.inputsWrap.appendChild( Tag.render` <input name="${Text.encode(this.inputName)}" value="empty" type="hidden" > ` )); } this.emit('change', allValuesValue); } showMainLoader() { if (this.DOM.wrap) { this.hideMainLoader(); let loaderWrap = Tag.render`<div class="calendar-resbook-webform-wrapper-loader-wrap"></div>`; loaderWrap.appendChild(BookingUtil.getLoader(160)); this.DOM.mainLoader = this.DOM.outerWrap.appendChild(loaderWrap); } } hideMainLoader() { Dom.remove(this.DOM.mainLoader); } showStatusLoader() { this.showMainLoader(); } hideStatusLoader() { this.hideMainLoader(); } requestAccessibilityData(params) { if (!this.requestedFormData) { this.showStatusLoader(); this.requestedFormData = true; let formDataParams = { from: params.date }; this.requireFormData(formDataParams).then(() => { this.hideStatusLoader(); this.refreshControlsState(); this.dateControl.refreshCurrentValue(); this.onChangeValues(); this.requestedFormData = false; }); } } requireFormData(params) { params = Type.isPlainObject(params) ? params : {}; return new Promise((resolve, reject) => { let data = { settingsData: this.getSettingsData() || null }; if (!this.userFieldParams) { data.fieldName = this.params.field.entity_field_name; } let dateFrom = Type.isDate(params.from) ? params.from : new Date(), dateTo; if (Type.isDate(params.to)) { dateTo = params.to; } else { dateTo = new Date(dateFrom.getTime()); dateTo.setDate(dateFrom.getDate() + 60); } data.from = BookingUtil.formatDate(this.DATE_FORMAT, dateFrom); data.to = BookingUtil.formatDate(this.DATE_FORMAT, dateTo); this.setLoadedDataLimits(dateFrom, dateTo); this.actionAgent('calendar.api.resourcebookingajax.getfillformdata', { data: data }).then((response) => { if (!Type.isPlainObject(response) || !response.data) { resolve(response); } else { if (Type.isNumber(response.data.timezoneOffset)) { this.timezoneOffset = response.data.timezoneOffset; this.timezoneOffsetLabel = response.data.timezoneOffsetLabel; } if (response.data.workTimeStart !== undefined && response.data.workTimeEnd !== undefined) { this.timeFrom = parseInt(response.data.workTimeStart); this.timeTo = parseInt(response.data.workTimeEnd); } if (response.data.fieldSettings) { this.userFieldParams = response.data.fieldSettings; } if (response.data.userIndex) { this.userIndex = response.data.userIndex; } this.handleAccessibilityData(response.data.usersAccessibility, 'user'); this.handleAccessibilityData(response.data.resourcesAccessibility, 'resource'); resolve(response.data); } }, (response) => { resolve(response); }); }); } setLoadedDataLimits(from, to) { this.loadedDataFrom = Type.isDate(from) ? from : BookingUtil.parseDate(from); this.loadedDataTo = Type.isDate(to) ? to : BookingUtil.parseDate(to); this.loadedDates = this.loadedDates || []; this.loadedDatesIndex = this.loadedDatesIndex || {}; let dateKey, date = new Date(this.loadedDataFrom.getTime()); while (true) { dateKey = BookingUtil.formatDate(this.DATE_FORMAT, date); this.loadedDatesIndex[dateKey] = this.loadedDates.length; this.loadedDates.push({ key: BookingUtil.formatDate(this.DATE_FORMAT, date), slots: {}, slotsCount: {} }); date.setDate(date.getDate() + 1); if (date.getTime() > this.loadedDataTo.getTime()) { break; } } } fillDataIndex(date, time, entityType, entityId) { let dateIndex = this.loadedDatesIndex[date]; if (this.loadedDates[dateIndex]) { if (!this.loadedDates[dateIndex].slots[time]) { this.loadedDates[dateIndex].slots[time] = {}; } if (this.loadedDates[dateIndex].slotsCount[entityType + entityId] === undefined) { this.loadedDates[dateIndex].slotsCount[entityType + entityId] = 0; } this.loadedDates[dateIndex].slots[time][entityType + entityId] = true; this.loadedDates[dateIndex].slotsCount[entityType + entityId]++; } } handleAccessibilityData(data, entityType) { if (Type.isPlainObject(data) && (entityType === 'user' || entityType === 'resource')) { // For each entry which has accessibility entries for (let entityId in data) { if (data.hasOwnProperty(entityId)) { data[entityId].forEach(function(entry) { if (!entry.from) { entry.from = BookingUtil.parseDate(entry.dateFrom); if (entry.from) { entry.from.setSeconds(0,0); entry.fromTimestamp = entry.from.getTime(); } } if (!entry.to) { entry.to = BookingUtil.parseDate(entry.dateTo); if (entry.to) { if (entry.fullDay) { entry.to.setHours(23, 59, 0, 0); } else { entry.to.setSeconds(0, 0); } entry.toTimestamp = entry.to.getTime(); } } if (entry.from && entry.to) { this.fillBusySlotMatrix(entry, entityType, entityId); } }, this); } } this.accessibility[entityType] = BookingUtil.mergeEx(this.accessibility[entityType], data); } } fillBusySlotMatrix(entry, entityType, entityId) { if (!this.busySlotMatrix[entityType][entityId]) { this.busySlotMatrix[entityType][entityId] = {}; } let fromDate = new Date(entry.from.getTime()), dateKey = BookingUtil.formatDate(this.DATE_FORMAT, fromDate), dateToKey = BookingUtil.formatDate(this.DATE_FORMAT, entry.to), timeValueFrom = fromDate.getHours() * 60 + fromDate.getMinutes(), duration = Math.round((entry.toTimestamp - entry.fromTimestamp) / 60000), // in minutes timeValueTo = timeValueFrom + duration, slots = this.getTimeSlots(), count = 0, i; if (duration > 0) { while (true) { if (!this.busySlotMatrix[entityType][entityId][dateKey]) { this.busySlotMatrix[entityType][entityId][dateKey] = {}; } for (i = 0; i < slots.length; i++) { if (timeValueFrom < (slots[i].time + this.scale) && timeValueTo > slots[i].time) { this.busySlotMatrix[entityType][entityId][dateKey][slots[i].time] = true; this.fillDataIndex(dateKey, slots[i].time, entityType, entityId); } } if (dateKey === dateToKey) { break; } else { fromDate.setDate(fromDate.getDate() + 1); dateKey = BookingUtil.formatDate(this.DATE_FORMAT, fromDate); timeValueFrom = 0; if (dateKey === dateToKey) { timeValueTo = entry.to.getHours() * 60 + entry.to.getMinutes(); } else { timeValueTo = 1440; // end of the day - 24 hours } } count++; if (count > 10000) // emergency exit { break; } } } } getCaption() { return this.params.field.caption; } getSettingsData() { return this.params.field.settings_data || {}; } getUserIndex() { return this.userIndex; } getFieldParams() { return this.userFieldParams; } getSettings() { return { caption: this.getCaption(), data: this.getSettingsData() }; } isUserSelectorInAutoMode() { return this.usersDisplayed() && this.getSettingsData().users.show === "N"; } isResourceSelectorInAutoMode() { return this.resourcesDisplayed() && this.getSettingsData().resources.show === "N"; } autoAdjustUserSelector() { let currentDate = this.dateControl.getValue(), timeValue = this.timeControl.getValue(); if (Type.isDate(currentDate) && timeValue) { let i, loadedDate = this.loadedDates[this.loadedDatesIndex[BookingUtil.formatDate(this.DATE_FORMAT, currentDate)]]; if (loadedDate.slots[timeValue]) { for (i = 0; i < this.userControl.values.length; i++) { if (!loadedDate.slots[timeValue]['user' + this.userControl.values[i]]) { this.userControl.setSelectedUser(this.userControl.values[i]); break; } } } } } autoAdjustResourceSelector() { let currentDate = this.dateControl.getValue(), timeValue = this.timeControl.getValue(); if (Type.isDate(currentDate) && timeValue) { let i, id, loadedDate = this.loadedDates[this.loadedDatesIndex[BookingUtil.formatDate(this.DATE_FORMAT, currentDate)]]; if (loadedDate.slots[timeValue]) { for (i = 0; i < this.resourceControl.resourceList.length; i++) { id = parseInt(this.resourceControl.resourceList[i].id); if (!loadedDate.slots[timeValue]['resource' + id]) { this.resourceControl.setSelectedResource(id); break; } } } } } preparaAutoSelectValues () { let settingsData = this.getSettingsData(), autoSelectUser = this.usersDisplayed() && (settingsData.users.defaultMode === 'auto' || settingsData.users.show === "N"), autoSelectResource = this.resourcesDisplayed() && (settingsData.resources.defaultMode === 'auto' || settingsData.resources.show === "N"), autoSelectDate = settingsData.date.start === 'free', maxStepsAuto = 60, date, i; this.selectedUserId = false; this.selectedResourceId = false; date = new Date(); // Walk through each date searching for free space for (i = 0; i <= maxStepsAuto; i++) { this.getFreeEntitiesForDate(date, { autoSelectUser: autoSelectUser, autoSelectResource: autoSelectResource, slotsAmount: this.getDefaultDurationSlotsAmount() }); if ((this.selectedUserId || !autoSelectUser) && (this.selectedResourceId || !autoSelectResource)) { break; } if (!autoSelectDate) { break; } date.setDate(date.getDate() + 1); } } getFreeEntitiesForDate(date, params) { let settingsData = this.getSettingsData(), slotsAmount = params.slotsAmount || 1, i, userList, resList; if (params.autoSelectUser) { userList = this.getUsersValue(); for (i = 0; i < userList.length; i++) { if (this.checkSlotsForDate(date, slotsAmount, { user: parseInt(userList[i]) })) { this.selectedUserId = parseInt(userList[i]); break; } } } if (params.autoSelectResource) { resList = this.getResourceValue(); for (i = 0; i < resList.length; i++) { if (this.checkSlotsForDate(date, slotsAmount, { resources: [parseInt(resList[i])], user: this.selectedUserId || null })) { this.selectedResourceId = parseInt(resList[i]); break; } } } } displayUsersControl() { if (this.usersDisplayed()) { this.userControl = new UserSelector({ outerWrap: this.DOM.innerWrap, data: this.getSettingsData().users, userIndex: this.getUserIndex(), previewMode: false, autoSelectDefaultValue: this.selectedUserId, changeValueCallback: function(userId) { this.emit('BX.Calendar.Resourcebooking.LiveFieldController:userChanged', new BaseEvent({data: {userId: userId}})); this.refreshControlsState(); }.bind(this) }); this.userControl.display(); } } displayResourcesControl() { let valueIndex = {}, dataValue = [], fieldParams = this.getFieldParams(), settingsData = this.getSettingsData(); if (this.resourcesDisplayed()) { this.getResourceValue().forEach(function(id) { id = parseInt(id); if (id > 0) { valueIndex[id] = true; dataValue.push(id); } }); let resourceList = []; fieldParams.SELECTED_RESOURCES.forEach(function(res) { res.id = parseInt(res.id); if (valueIndex[res.id]) { resourceList.push(res); } }, this); this.resourceControl = new ResourceSelector({ outerWrap: this.DOM.innerWrap, data: { show: settingsData.resources.show, defaultMode: settingsData.resources.defaultMode, label: settingsData.resources.label, multiple: settingsData.resources.multiple, value: settingsData.resources.value }, resourceList: resourceList, autoSelectDefaultValue: this.selectedResourceId, changeValueCallback: function() { this.emit('BX.Calendar.Resourcebooking.LiveFieldController:resourceChanged'); this.refreshControlsState(); }.bind(this) }); if (this.selectorCanBeShown('resources')) { this.resourceControl.display(); } } } displayServicesControl() { let fieldParams = this.getFieldParams(), settingsData = this.getSettingsData(); if (fieldParams.USE_SERVICES === 'Y' && settingsData.services.value) { let dataValueRaw = this.getServicesValue(); this.serviceControl = new ServiceSelector({ outerWrap: this.DOM.innerWrap, data: settingsData.services, serviceList: fieldParams.SERVICE_LIST, selectedValue: dataValueRaw.length > 0 ? dataValueRaw[0] : null, changeValueCallback: function() { this.emit('BX.Calendar.Resourcebooking.LiveFieldController:serviceChanged'); this.refreshControlsState(); }.bind(this) }); if (this.selectorCanBeShown('services')) { this.serviceControl.display(); } } } displayDurationControl() { let fieldParams = this.getFieldParams(), settingsData = this.getSettingsData(); if (!this.serviceControl) { this.durationControl = new DurationSelector({ outerWrap: this.DOM.innerWrap, data: settingsData.duration, fullDay: fieldParams.FULL_DAY === 'Y', changeValueCallback: function() { this.emit('BX.Calendar.Resourcebooking.LiveFieldController:durationChanged'); this.refreshControlsState(); }.bind(this) }); if (this.selectorCanBeShown('duration')) { this.durationControl.display(); } } } displayDateTimeControl() { let timezone = false, startValue = null, settingsData = this.getSettingsData(), fieldParams = this.getFieldParams(); this.dateControl = new DateSelector({ outerWrap: this.DOM.innerWrap, data: settingsData.date, previewMode: false, allowOverbooking: fieldParams.ALLOW_OVERBOOKING === "Y", changeValueCallback: this.handleDateChanging.bind(this), requestDataCallback: this.requestAccessibilityData.bind(this) }); if (this.timeSelectorDisplayed()) { if (fieldParams.USE_USER_TIMEZONE === 'N') { let userTimezoneOffset = -(new Date).getTimezoneOffset()*60; if (userTimezoneOffset !== this.timezoneOffset) { timezone = fieldParams.TIMEZONE; } } this.timeControl = new TimeSelector({ outerWrap: this.DOM.innerWrap, data: settingsData.time, previewMode: false, changeValueCallback: this.handleSelectedDateTimeChanging.bind(this), timeFrom: this.timeFrom, timeTo: this.timeTo, timezone: timezone, timezoneOffset: this.timezoneOffset, timezoneOffsetLabel: this.timezoneOffsetLabel }); } this.statusControl = new StatusInformer({ outerWrap: this.DOM.innerWrap, timezone: timezone, timezoneOffsetLabel: this.timezoneOffsetLabel }); if (this.selectorCanBeShown('date')) { this.statusControl.show(); if (settingsData.date.start === 'free') { startValue = this.getFreeDate({ resources: this.getSelectedResources(), user: this.getSelectedUser(), duration: this.getCurrentDuration() }); } this.dateControl.display({ selectedValue: startValue }); if (this.timeControl && !this.timeControl.isShown()) { this.timeControl.display(); } } else { this.statusControl.hide(); } } handleDateChanging(date, realDate) { this.emit('BX.Calendar.Resourcebooking.LiveFieldController:dateChanged'); if (this.timeSelectorDisplayed()) { if (realDate) { this.timeControl.show(); let timeValueFrom, currentDate = this.getCurrentDate(); if (currentDate) { timeValueFrom = currentDate.getHours() * 60 + currentDate.getMinutes(); } this.timeControl.refresh( this.getSettingsData().time, { slotIndex: this.getSlotIndex({date: realDate}), currentDate: realDate, selectedValue: timeValueFrom }); // this.timeControl.refresh( // this.getSettingsData().time, // { // slotIndex: this.getAvailableSlotIndex({ // date: realDate, // resources: this.getSelectedResources(), // user: this.getSelectedUser(), // duration: this.getCurrentDuration() // }), // currentDate: realDate, // selectedValue: timeValueFrom // }); } } else { this.handleSelectedDateTimeChanging(null, true); } this.onChangeValues(); } handleSelectedDateTimeChanging(value, useTimeout) { if (useTimeout !== false) { if (this.updateTimeStatusTimeout) { this.updateTimeStatusTimeout = clearTimeout(this.updateTimeStatusTimeout); } this.updateTimeStatusTimeout = setTimeout(function(){ this.handleSelectedDateTimeChanging(value, false); }.bind(this), 100); } else { if (this.isUserSelectorInAutoMode()) { this.autoAdjustUserSelector(); } if (this.isResourceSelectorInAutoMode()) { this.autoAdjustResourceSelector(); } this.updateStatusControl(); BookingUtil.fireCustomEvent(window, 'crmWebFormFireResize'); } this.onChangeValues(); } updateStatusControl() { if (this.statusControl && this.selectorCanBeShown('date')) { let currentDate = this.getCurrentDate(); if (this.dateControl.isItPastDate(currentDate)) { this.statusControl.setError(Loc.getMessage('WEBF_RES_BOOKING_PAST_DATE_WARNING')); } else { if (this.timeSelectorDisplayed()) { if (this.timeControl.hasAvailableSlots()) { let timeValue = this.timeControl.getValue(); this.statusControl.refresh({ dateFrom: timeValue ? currentDate : null, duration: timeValue ? this.getCurrentDuration() : null, fullDay: false }); } else { this.statusControl.hide(); } } else { this.statusControl.refresh({ dateFrom: this.dateControl.isDateAvailable(currentDate) ? currentDate : null, duration: this.getCurrentDuration(), fullDay: true }); } } } } getFreeDate(params) { let slotsAmount = Math.ceil(params.duration / this.scale), freeDate = null, date = this.loadedDataFrom; // Walk through each date searching for free space while (true) { if (this.checkSlotsForDate(date, slotsAmount, { resources: params.resources, user: params.user })) { freeDate = date; break; } date.setDate(date.getDate() + 1); if (date.getTime() >= this.loadedDataTo.getTime()) { break; } } return freeDate; } getAvailableDateIndex(params) { let userIsFree, resourcesAreFree, dateIndex = {}; if (this.timeSelectorDisplayed()) { let slotsAmount = Math.ceil(params.duration / this.scale); this.loadedDates.forEach(function(date) { dateIndex[date.key] = this.checkSlotsForDate(date.key, slotsAmount, { resources: params.resources, user: params.user }); }, this); } else { let i, daysGap, date, j, userKey = params.user ? 'user' + params.user : null, daysAmount = Math.ceil(params.duration / 1440); daysGap = 1; for (i = this.loadedDates.length; i--; i >= 0) { userIsFree = true; resourcesAreFree = true; date = this.loadedDates[i]; if (userKey) { // All day is free for user userIsFree = !date.slotsCount[userKey]; } if (userIsFree && params.resources && params.resources.length > 0) { for (j = 0; j < params.resources.length; j++) { resourcesAreFree = resourcesAreFree && !date.slotsCount['resource' + params.resources[j]]; if (!resourcesAreFree) { break; } } } if (userIsFree && resourcesAreFree) { daysGap++; } else { daysGap = 0; } dateIndex[date.key] = userIsFree && resourcesAreFree && daysAmount <= daysGap; } } return dateIndex; } getSlotIndex(params) { if (params.date) { params.date = this.dateControl.getValue(); } let slotIndex = {}; if (Type.isDate(params.date)) { if (this.getFieldParams().ALLOW_OVERBOOKING !== "Y" && (this.isUserSelectorInAutoMode() || this.isResourceSelectorInAutoMode())) { const fieldParams = this.getFieldParams(); let freeSlot, i, j, time, slotGap = 1, todayNowTime = 0, timeSlots = this.getTimeSlots(), dateKey = BookingUtil.formatDate(this.DATE_FORMAT, params.date), loadedDate = this.loadedDates[this.loadedDatesIndex[dateKey]], slotsAmount = Math.ceil(this.getCurrentDuration() / this.scale); if (this.checkIsTodayDate(dateKey)) { const today = new Date(); const deltaOffset = fieldParams.USE_USER_TIMEZONE === 'N' ? today.getTimezoneOffset() * 60 + this.timezoneOffset: 0; todayNowTime = today.getHours() * 60 + today.getMinutes() + (deltaOffset / 60); } // Prefill slotIndex timeSlots.forEach(function(slot){slotIndex[slot.time] = true;}, this); if (this.isUserSelectorInAutoMode()) { const userList = this.getUsersValue(); for (i = timeSlots.length; i--; i >= 0) { time = timeSlots[i].time; freeSlot = false; if (todayNowTime && time < todayNowTime) { slotIndex[time] = false; continue; } for (j = 0; j < userList.length; j++) { if (!loadedDate.slots[time] || !loadedDate.slots[time]['user' + userList[j]]) { freeSlot = true; break; } } slotIndex[time] = slotIndex[time] && freeSlot && slotsAmount <= slotGap; slotGap = freeSlot ? slotGap + 1 : 1; } } if (this.isResourceSelectorInAutoMode()) { const resList = this.getResourceValue(); for (i = timeSlots.length; i--; i >= 0) { time = timeSlots[i].time; freeSlot = false; if (todayNowTime && time < todayNowTime) { slotIndex[time] = false; continue; } for (j = 0; j < resList.length; j++) { if (!loadedDate.slots[time] || !loadedDate.slots[time]['resource' + resList[j]]) { freeSlot = true; break; } } slotIndex[time] = slotIndex[time] && freeSlot && slotsAmount <= slotGap; slotGap = freeSlot ? slotGap + 1 : 1; } } } else { slotIndex = this.getAvailableSlotIndex({ date: params.date || this.dateControl.getValue(), resources: this.getSelectedResources(), user: this.getSelectedUser(), duration: this.getCurrentDuration() }) } } return slotIndex; } getAvailableSlotIndex(params) { let todayNowTime = 0; const fieldParams = this.getFieldParams(); let dateKey, loadedDate, i, j, time, slotGap, userKey = params.user ? 'user' + params.user : null, slotsAmount = Math.ceil(params.duration / this.scale), userIsFree, resourcesAreFree, timeSlots = this.getTimeSlots(), allowOverbooking = fieldParams.ALLOW_OVERBOOKING === "Y", slotIndex = {}; // Prefill slotIndex timeSlots.forEach(function(slot){slotIndex[slot.time] = true;}, this); if (Type.isDate(params.date)) { dateKey = BookingUtil.formatDate(this.DATE_FORMAT, params.date); loadedDate = this.loadedDates[this.loadedDatesIndex[dateKey]]; slotGap = 1; if (this.checkIsTodayDate(dateKey)) { const today = new Date(); const deltaOffset = fieldParams.USE_USER_TIMEZONE === 'N' ? today.getTimezoneOffset() * 60 + this.timezoneOffset: 0; todayNowTime = today.getHours() * 60 + today.getMinutes() + (deltaOffset / 60); } for (i = timeSlots.length; i--; i >= 0) { time = timeSlots[i].time; if (todayNowTime && time < todayNowTime) { slotIndex[time] = false; continue; } if (allowOverbooking) { slotIndex[time] = slotsAmount <= slotGap; slotGap++; } else { userIsFree = true; resourcesAreFree = true; if (userKey) { // Time is free for user userIsFree = !loadedDate.slots[time] || !loadedDate.slots[time][userKey]; } if (params.resources && params.resources.length > 0) { for (j = 0; j < params.resources.length; j++) { resourcesAreFree = resourcesAreFree && (!loadedDate.slots[time] || !loadedDate.slots[time]['resource' + params.resources[j]]); if (!resourcesAreFree) { break; } } } slotIndex[time] = userIsFree && resourcesAreFree && slotsAmount <= slotGap; if (userIsFree && resourcesAreFree) { slotGap++; } else { slotGap = 1; } } } } return slotIndex; } checkSlotsForDate(date, slotsAmount, params) { let userIsFree = true, resourcesAreFree = true, dateKey = Type.isDate(date) ? BookingUtil.formatDate(this.DATE_FORMAT, date) : date; params = params || {}; if (this.usersDisplayed() && params.user) { if (this.busySlotMatrix.user[params.user] && !this.entityHasSlotsForDate({ entityType: 'user', entityId: params.user, dateKey: dateKey, slotsAmount: slotsAmount }) ) { userIsFree = false; } } if (this.resourcesDisplayed() && userIsFree && Type.isArray(params.resources) && params.resources.length > 0) { params.resources.forEach(function(resourceId) { if (resourcesAreFree && this.busySlotMatrix.resource[resourceId] && !this.entityHasSlotsForDate({ entityType: 'resource', entityId: resourceId, dateKey: dateKey, slotsAmount: slotsAmount }) ) { resourcesAreFree = false; } }, this); } return userIsFree && resourcesAreFree; } entityHasSlotsForDate(params) { let busySlotList, slots, i, freeSlotCount = 0, hasFreeSlots = false; if (this.busySlotMatrix[params.entityType][params.entityId] && this.busySlotMatrix[params.entityType][params.entityId][params.dateKey]) { busySlotList = this.busySlotMatrix[params.entityType][params.entityId][params.dateKey]; slots = this.getTimeSlots(); for (i = 0; i < slots.length; i++) { if (!busySlotList[slots[i].time]) { freeSlotCount++; if (freeSlotCount >= params.slotsAmount) { hasFreeSlots = true; break; } } else { freeSlotCount = 0; } } } else { hasFreeSlots = true; } return hasFreeSlots; } getSelectedResources() { let result = null; if (this.resourceControl) { result = this.resourceControl.getSelectedValues(); if (Type.isArray(result) && !result.length) { result = null; } } return result; } getSelectedUser() { let result = null; if (this.userControl) { result = this.userControl.getSelectedUser(); } return result; } getCurrentDuration() { let result = null; if (this.durationControl) { result = this.durationControl.getSelectedValue(); } else if (this.serviceControl) { let service = this.serviceControl.getSelectedService(true); if (service && service.duration) { result = parseInt(service.duration); } } return result; } getDefaultDurationSlotsAmount() { let settingsData = this.getSettingsData(), fieldParams = this.getFieldParams(), duration, i, slotsAmount; if (fieldParams.USE_SERVICES === 'Y' && settingsData.services.value) { const services = this.getServicesValue(); if (Type.isArray(fieldParams.SERVICE_LIST) && services.length > 0) { for (i = 0; i < fieldParams.SERVICE_LIST.length; i++) { if (BookingUtil.translit(fieldParams.SERVICE_LIST[i].name) === services[0]) { duration = parseInt(fieldParams.SERVICE_LIST[i].duration); break; } } } } else { duration = parseInt(settingsData.duration.defaultValue); } slotsAmount = Math.ceil(duration / this.scale); return slotsAmount; } getCurrentServiceName() { let result = ''; if (this.serviceControl) { let service = this.serviceControl.getSelectedService(true); if (service && service.name) { result = service.name; } } return result; } getCurrentDate() { let result = null; if (this.dateControl && this.dateControl.isShown()) { result = this.dateControl.getValue(); if (this.timeSelectorDisplayed()) { let hour, min, timeValue = this.timeControl.getValue(); if (timeValue) { hour = Math.floor(timeValue / 60); min = timeValue - hour * 60; result.setHours(hour, min, 0, 0); } } else { result.setHours(0, 0, 0, 0); } } return result; } getTimeSlots() { if (!this.slots) { this.slots = []; let slot; let finishTime, hourFrom, hourTo; let minTo, minFrom; let num = 0; let time = this.timeFrom * 60; while (time < this.timeTo * 60) { hourFrom = Math.floor(time / 60); minFrom = (time) - hourFrom * 60; finishTime = time + this.scale; hourTo = Math.floor(finishTime / 60); minTo = (finishTime) - hourTo * 60; slot = { time: time }; this.slots.push(slot); time += this.scale; num++; } } return this.slots; } usersDisplayed() { if (this.useUsers === undefined) { this.useUsers = this.getFieldParams()['USE_USERS'] === 'Y'; } return this.useUsers; } resourcesDisplayed() { if (this.useResources === undefined) { let fieldParams = this.getFieldParams(); this.useResources = !!(fieldParams.USE_RESOURCES === 'Y' && fieldParams.SELECTED_RESOURCES); } return this.useResources; } timeSelectorDisplayed() { if (this.useTime === undefined) { this.useTime = this.getFieldParams().FULL_DAY !== 'Y'; } return this.useTime; } selectorCanBeShown(type) { let result = false; if (type === 'resources') { if (this.resourcesDisplayed() && !this.usersDisplayed()) { result = true; } else if (this.usersDisplayed()) { result = this.getSelectedUser(); } } else if (type === 'date' || type === 'services' || type === 'duration') { if (this.usersDisplayed() && this.resourcesDisplayed()) { result = this.getSelectedUser() && this.getSelectedResources(); } else if (this.usersDisplayed()) { result = this.getSelectedUser(); } else if (this.resourcesDisplayed()) { result = this.getSelectedResources(); } } return result; } checkIsTodayDate(dateKey) { if (!this.todayDateKey) { let today = new Date(); this.todayDateKey = BookingUtil.formatDate(this.DATE_FORMAT, today); } return this.todayDateKey === dateKey; } getResourceValue() { const settingsData = this.getSettingsData(); let value = []; if (Type.isArray(settingsData.resources.value)) { value = settingsData.resources.value; } else if (Type.isString(settingsData.resources.value)) { value = settingsData.resources.value.split('|'); } return value; } getUsersValue() { const settingsData = this.getSettingsData(); let value = []; if (Type.isArray(settingsData.users.value)) { value = settingsData.users.value; } else if (Type.isString(settingsData.users.value)) { value = settingsData.users.value.split('|'); } return value; } getServicesValue() { const settingsData = this.getSettingsData(); let value = []; if (Type.isArray(settingsData.services.value)) { value = settingsData.services.value; } else if (Type.isString(settingsData.services.value)) { value = settingsData.services.value.split('|'); } return value; } }