calendar/src/components/Shared/CalendarPicker.vue

166 lines
3.9 KiB
Vue

<template>
<NcSelect label="id"
:input-id="inputId"
:disabled="isDisabled"
:options="options"
:value="valueIds"
:multiple="multiple"
:clearable="clearable"
:filter-by="selectFilterBy"
@option:selected="change"
@option:deselected="remove">
<template #option="{ id }">
<CalendarPickerOption :color="getCalendarById(id).color"
:display-name="getCalendarById(id).displayName"
:is-shared-with-me="getCalendarById(id).isSharedWithMe"
:owner="getCalendarById(id).owner" />
</template>
<template #selected-option="{ id }">
<CalendarPickerOption :color="getCalendarById(id).color"
:display-name="getCalendarById(id).displayName"
:is-shared-with-me="getCalendarById(id).isSharedWithMe"
:owner="getCalendarById(id).owner" />
</template>
</NcSelect>
</template>
<script>
import { NcSelect } from '@nextcloud/vue'
import CalendarPickerOption from './CalendarPickerOption.vue'
import { randomId } from '../../utils/randomId.js'
export default {
name: 'CalendarPicker',
components: {
CalendarPickerOption,
NcSelect,
},
props: {
value: {
type: [Object, Array],
required: true,
},
calendars: {
type: Array,
required: true,
},
showCalendarOnSelect: {
type: Boolean,
default: false,
},
multiple: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: true,
},
inputId: {
type: String,
default: () => randomId(),
},
},
computed: {
isDisabled() {
// for pickers where multiple can be selected (zero or more) we don't want to disable the picker
// for calendars where only one calendar can be selected, disable if there are < 2
return this.disabled || (this.multiple ? this.calendars.length < 1 : this.calendars.length < 2)
},
valueIds() {
if (Array.isArray(this.value)) {
return this.value.map(({ id }) => id)
}
return this.value.id
},
options() {
return this.calendars.map((calendar) => ({
id: calendar.id,
displayName: calendar.displayName,
}))
},
},
methods: {
/**
* TODO: this should emit the calendar id instead
*
* @param {{id: string}|{id: string}[]} options All selected options (including the new one)
*/
change(options) {
if (!options || options.length === 0) {
return
}
// The new option will always be the last element
const newOption = Array.isArray(options) ? options[options.length - 1] : options
const newCalendar = this.getCalendarById(newOption.id)
if (this.showCalendarOnSelect && !newCalendar.enabled) {
this.$store.dispatch('toggleCalendarEnabled', {
calendar: newCalendar,
})
}
this.$emit('select-calendar', newCalendar)
},
remove(option) {
if (this.multiple) {
this.$emit('remove-calendar', this.getCalendarById(option))
}
},
/**
* @param {string} id The calendar id
* @return {object|undefined} The calendar object (if it exists)
*/
getCalendarById(id) {
return this.calendars.find((cal) => cal.id === id)
},
/**
* Decide whether the given option matches the given search term
*
* @param {object} option The calendar option
* @param {string} label The label of the calendar option
* @param {string} id The search term
* @param search
* @return {boolean} True if the search term matches
*/
selectFilterBy(option, label, search) {
return option.displayName.toLowerCase().indexOf(search) !== -1
},
},
}
</script>
<style lang="scss" scoped>
::v-deep .multiselect__tags {
margin: 3px 0;
}
.calendar-picker__tag {
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
padding: 0 5px;
}
.calendar-picker__tag + .calendar-picker__tag {
margin-left: 5px;
}
</style>
<style lang="scss">
.vs__search {
// Prevent search from collapsing the actual picked option
flex-basis: 0;
}
.vs__dropdown-menu {
z-index: 10000010 !important;
}
</style>