mirror of https://github.com/nextcloud/calendar
217 lines
5.9 KiB
JavaScript
217 lines
5.9 KiB
JavaScript
/**
|
|
* @copyright Copyright (c) 2021 Richard Steinmetz <richard@steinmetz.cloud>
|
|
*
|
|
* @author Richard Steinmetz <richard@steinmetz.cloud>
|
|
*
|
|
* @license AGPL-3.0-or-later
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
import { generateUrl } from '@nextcloud/router'
|
|
import {
|
|
getEmptySlots,
|
|
vavailabilityToSlots,
|
|
} from '@nextcloud/calendar-availability-vue'
|
|
|
|
/** @class */
|
|
export default class AppointmentConfig {
|
|
|
|
/** @member {?number} */
|
|
id
|
|
|
|
/** @member {?string} */
|
|
token
|
|
|
|
/** @member {string} */
|
|
name
|
|
|
|
/** @member {string} */
|
|
description
|
|
|
|
/** @member {string} */
|
|
location
|
|
|
|
/** @member {string} */
|
|
visibility
|
|
|
|
/** @member {string} */
|
|
targetCalendarUri
|
|
|
|
/** @member {object} */
|
|
availability
|
|
|
|
/** @member {number} */
|
|
length
|
|
|
|
/** @member {number} */
|
|
increment
|
|
|
|
/** @member {number} */
|
|
preparationDuration
|
|
|
|
/** @member {number} */
|
|
followupDuration
|
|
|
|
/** @member {number} */
|
|
timeBeforeNextSlot
|
|
|
|
/** @member {?number} */
|
|
dailyMax
|
|
|
|
/** @member {?number} */
|
|
futureLimit
|
|
|
|
/** @member {?string[]} */
|
|
calendarFreeBusyUris
|
|
|
|
/** @member {bool} */
|
|
createTalkRoom
|
|
|
|
/**
|
|
* Create a new AppointmentConfig from the given plain object data
|
|
*
|
|
* @param {object} data Appointment config data to construct an instance from
|
|
* @param {?number} data.id Id
|
|
* @param {?string} data.token Token
|
|
* @param {string} data.name Name
|
|
* @param {string} data.description Description
|
|
* @param {string} data.location Location
|
|
* @param {string} data.visibility Visibility
|
|
* @param {string} data.targetCalendarUri Target calendar URI
|
|
* @param {object} data.availability Availability
|
|
* @param {number} data.length Length in seconds
|
|
* @param {number} data.increment Increment in seconds
|
|
* @param {number} data.preparationDuration Preparation duration in seconds
|
|
* @param {number} data.followupDuration Followup duration in seconds
|
|
* @param {number} data.timeBeforeNextSlot Time before next slot in seconds
|
|
* @param {?number} data.dailyMax Max daily slots
|
|
* @param {?number} data.futureLimit Limits how far in the future appointments can be booked
|
|
* @param {?string[]} data.calendarFreeBusyUris URIs of calendars to check for conflicts
|
|
* @param {bool} data.createTalkRoom Whether a Talk room should be created
|
|
*/
|
|
constructor(data) {
|
|
data ??= {}
|
|
this.id = data.id
|
|
this.token = data.token
|
|
this.name = data.name
|
|
this.description = data.description
|
|
this.location = data.location
|
|
this.visibility = data.visibility
|
|
this.targetCalendarUri = data.targetCalendarUri
|
|
this.availability = data.availability
|
|
this.length = tryParseInt(data.length) ?? 0
|
|
this.increment = tryParseInt(data.increment) ?? 0
|
|
this.preparationDuration = tryParseInt(data.preparationDuration)
|
|
this.followupDuration = tryParseInt(data.followupDuration)
|
|
this.timeBeforeNextSlot = tryParseInt(data.timeBeforeNextSlot)
|
|
this.dailyMax = tryParseInt(data.dailyMax)
|
|
this.futureLimit = tryParseInt(data.futureLimit)
|
|
this.calendarFreeBusyUris = data.calendarFreeBusyUris
|
|
this.createTalkRoom = data.createTalkRoom
|
|
}
|
|
|
|
/**
|
|
* Create a default appointment config instance
|
|
*
|
|
* @param {string} targetCalendarUri
|
|
* @param {ScheduleInbox} scheduleInbox
|
|
* @param {string} timezoneId fallback time zone when no schedule inbox availability is set
|
|
* @return {AppointmentConfig} Default appointment config instance
|
|
*/
|
|
static createDefault(targetCalendarUri, scheduleInbox, timezoneId) {
|
|
let slots = getEmptySlots()
|
|
if (scheduleInbox && scheduleInbox.availability) {
|
|
const converted = vavailabilityToSlots(scheduleInbox.availability)
|
|
slots = converted.slots
|
|
timezoneId = converted.timezoneId ?? timezoneId
|
|
} else {
|
|
// Set default availability to Mo-Fr 9-5
|
|
const tsAtTime = (hours, minutes) => Math.round((new Date()).setHours(hours, minutes, 0, 0) / 1000);
|
|
['MO', 'TU', 'WE', 'TH', 'FR'].forEach(day => slots[day].push({
|
|
start: tsAtTime(9, 0),
|
|
end: tsAtTime(17, 0),
|
|
}))
|
|
}
|
|
|
|
return new AppointmentConfig({
|
|
name: '',
|
|
description: '',
|
|
location: '',
|
|
targetCalendarUri,
|
|
availability: {
|
|
timezoneId,
|
|
slots,
|
|
},
|
|
visibility: 'PRIVATE',
|
|
length: 5 * 60,
|
|
increment: 15 * 60,
|
|
preparationDuration: 0,
|
|
followupDuration: 0,
|
|
timeBeforeNextSlot: 0,
|
|
calendarFreeBusyUris: [],
|
|
futureLimit: 2 * 30 * 24 * 60 * 60, // 2 months
|
|
})
|
|
|
|
}
|
|
|
|
/**
|
|
* Clone this instance
|
|
*
|
|
* @return {AppointmentConfig} A cloned version of this instance
|
|
*/
|
|
clone() {
|
|
return AppointmentConfig.fromJSON(JSON.stringify(this))
|
|
}
|
|
|
|
/**
|
|
* Parse a JSON string into a new AppointmentConfig instance
|
|
*
|
|
* @param {string} jsonString The JSON string to parse
|
|
* @return {AppointmentConfig} New instance parsed from given JSON string
|
|
*/
|
|
static fromJSON(jsonString) {
|
|
return new AppointmentConfig(JSON.parse(jsonString))
|
|
}
|
|
|
|
/**
|
|
* Get the absolute booking URL of this instance
|
|
*
|
|
* @return {string} Absolute URL
|
|
*/
|
|
get bookingUrl() {
|
|
const baseUrl = `${window.location.protocol}//${window.location.hostname}`
|
|
const relativeUrl = generateUrl('/apps/calendar/appointment/{token}', {
|
|
token: this.token,
|
|
})
|
|
return baseUrl + relativeUrl
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Try to parse an int from the given value or return undefined
|
|
*
|
|
* @param {string|number|null|undefined} value The value to parse
|
|
* @return {number|undefined} Parsed number or undefined
|
|
*/
|
|
function tryParseInt(value) {
|
|
if (value === null || value === undefined) {
|
|
return undefined
|
|
}
|
|
|
|
return parseInt(value)
|
|
}
|