mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
UBER-668 UBER-669 UBER-670 UBER-671 (#3566)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
32fd80c971
commit
afc881a7c6
@ -14,7 +14,15 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import activity from '@hcengineering/activity'
|
import activity from '@hcengineering/activity'
|
||||||
import { Calendar, Event, ReccuringEvent, ReccuringInstance, RecurringRule, calendarId } from '@hcengineering/calendar'
|
import {
|
||||||
|
Calendar,
|
||||||
|
CalendarEventPresenter,
|
||||||
|
Event,
|
||||||
|
ReccuringEvent,
|
||||||
|
ReccuringInstance,
|
||||||
|
RecurringRule,
|
||||||
|
calendarId
|
||||||
|
} from '@hcengineering/calendar'
|
||||||
import { Contact } from '@hcengineering/contact'
|
import { Contact } from '@hcengineering/contact'
|
||||||
import { DateRangeMode, Domain, IndexKind, Markup, Ref, Timestamp } from '@hcengineering/core'
|
import { DateRangeMode, Domain, IndexKind, Markup, Ref, Timestamp } from '@hcengineering/core'
|
||||||
import {
|
import {
|
||||||
@ -22,6 +30,7 @@ import {
|
|||||||
Builder,
|
Builder,
|
||||||
Collection,
|
Collection,
|
||||||
Index,
|
Index,
|
||||||
|
Mixin,
|
||||||
Model,
|
Model,
|
||||||
Prop,
|
Prop,
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
@ -35,13 +44,14 @@ import {
|
|||||||
} from '@hcengineering/model'
|
} from '@hcengineering/model'
|
||||||
import attachment from '@hcengineering/model-attachment'
|
import attachment from '@hcengineering/model-attachment'
|
||||||
import contact from '@hcengineering/model-contact'
|
import contact from '@hcengineering/model-contact'
|
||||||
import core, { TAttachedDoc } from '@hcengineering/model-core'
|
import core, { TAttachedDoc, TClass } from '@hcengineering/model-core'
|
||||||
import { TSpaceWithStates } from '@hcengineering/model-task'
|
import { TSpaceWithStates } from '@hcengineering/model-task'
|
||||||
import view, { createAction } from '@hcengineering/model-view'
|
import view, { createAction } from '@hcengineering/model-view'
|
||||||
import workbench from '@hcengineering/model-workbench'
|
import workbench from '@hcengineering/model-workbench'
|
||||||
import notification from '@hcengineering/notification'
|
import notification from '@hcengineering/notification'
|
||||||
import setting from '@hcengineering/setting'
|
import setting from '@hcengineering/setting'
|
||||||
import calendar from './plugin'
|
import calendar from './plugin'
|
||||||
|
import { AnyComponent } from '@hcengineering/ui'
|
||||||
|
|
||||||
export * from '@hcengineering/calendar'
|
export * from '@hcengineering/calendar'
|
||||||
export { calendarId } from '@hcengineering/calendar'
|
export { calendarId } from '@hcengineering/calendar'
|
||||||
@ -115,8 +125,13 @@ export class TReccuringInstance extends TEvent implements ReccuringInstance {
|
|||||||
virtual?: boolean
|
virtual?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mixin(calendar.mixin.CalendarEventPresenter, core.class.Class)
|
||||||
|
export class TCalendarEventPresenter extends TClass implements CalendarEventPresenter {
|
||||||
|
presenter!: AnyComponent
|
||||||
|
}
|
||||||
|
|
||||||
export function createModel (builder: Builder): void {
|
export function createModel (builder: Builder): void {
|
||||||
builder.createModel(TCalendar, TReccuringEvent, TReccuringInstance, TEvent)
|
builder.createModel(TCalendar, TReccuringEvent, TReccuringInstance, TEvent, TCalendarEventPresenter)
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
workbench.class.Application,
|
workbench.class.Application,
|
||||||
@ -131,6 +146,10 @@ export function createModel (builder: Builder): void {
|
|||||||
calendar.app.Calendar
|
calendar.app.Calendar
|
||||||
)
|
)
|
||||||
|
|
||||||
|
builder.mixin(calendar.class.Event, core.class.Class, calendar.mixin.CalendarEventPresenter, {
|
||||||
|
presenter: calendar.component.CalendarEventPresenter
|
||||||
|
})
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
view.class.Viewlet,
|
view.class.Viewlet,
|
||||||
core.space.Model,
|
core.space.Model,
|
||||||
|
@ -28,7 +28,8 @@ export default mergeIds(calendarId, calendar, {
|
|||||||
IntegrationConnect: '' as AnyComponent,
|
IntegrationConnect: '' as AnyComponent,
|
||||||
CreateCalendar: '' as AnyComponent,
|
CreateCalendar: '' as AnyComponent,
|
||||||
EventPresenter: '' as AnyComponent,
|
EventPresenter: '' as AnyComponent,
|
||||||
CalendarIntegrationIcon: '' as AnyComponent
|
CalendarIntegrationIcon: '' as AnyComponent,
|
||||||
|
CalendarEventPresenter: '' as AnyComponent
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
SaveEventReminder: '' as Ref<Action>,
|
SaveEventReminder: '' as Ref<Action>,
|
||||||
|
@ -172,7 +172,6 @@ export { default as Panel } from './components/Panel.svelte'
|
|||||||
export { default as MonthCalendar } from './components/calendar/MonthCalendar.svelte'
|
export { default as MonthCalendar } from './components/calendar/MonthCalendar.svelte'
|
||||||
export { default as YearCalendar } from './components/calendar/YearCalendar.svelte'
|
export { default as YearCalendar } from './components/calendar/YearCalendar.svelte'
|
||||||
export { default as WeekCalendar } from './components/calendar/WeekCalendar.svelte'
|
export { default as WeekCalendar } from './components/calendar/WeekCalendar.svelte'
|
||||||
export { default as DayCalendar } from './components/calendar/DayCalendar.svelte'
|
|
||||||
|
|
||||||
export { default as FocusHandler } from './components/FocusHandler.svelte'
|
export { default as FocusHandler } from './components/FocusHandler.svelte'
|
||||||
export { default as ListView } from './components/ListView.svelte'
|
export { default as ListView } from './components/ListView.svelte'
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { Event } from '@hcengineering/calendar'
|
||||||
|
import { addZero } from '@hcengineering/ui'
|
||||||
|
|
||||||
|
export let event: Event
|
||||||
|
export let oneRow: boolean = false
|
||||||
|
export let narrow: boolean = false
|
||||||
|
export let size: { width: number; height: number }
|
||||||
|
|
||||||
|
$: startDate = new Date(event.date)
|
||||||
|
$: endDate = new Date(event.dueDate)
|
||||||
|
|
||||||
|
const getTime = (date: Date): string => {
|
||||||
|
return `${addZero(date.getHours())}:${addZero(date.getMinutes())}`
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if !narrow}
|
||||||
|
<b class="overflow-label">{event.title}</b>
|
||||||
|
{/if}
|
||||||
|
{#if !oneRow}
|
||||||
|
<span class="overflow-label text-sm">{getTime(startDate)}-{getTime(endDate)}</span>
|
||||||
|
{/if}
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Calendar, Event, getAllEvents } from '@hcengineering/calendar'
|
import { Calendar, Event, generateEventId, getAllEvents } from '@hcengineering/calendar'
|
||||||
import { PersonAccount } from '@hcengineering/contact'
|
import { PersonAccount } from '@hcengineering/contact'
|
||||||
import {
|
import {
|
||||||
Class,
|
Class,
|
||||||
@ -30,27 +30,25 @@
|
|||||||
import {
|
import {
|
||||||
AnyComponent,
|
AnyComponent,
|
||||||
Button,
|
Button,
|
||||||
CalendarItem,
|
|
||||||
DayCalendar,
|
|
||||||
DropdownLabelsIntl,
|
DropdownLabelsIntl,
|
||||||
IconBack,
|
IconBack,
|
||||||
IconForward,
|
IconForward,
|
||||||
MILLISECONDS_IN_DAY,
|
|
||||||
MonthCalendar,
|
MonthCalendar,
|
||||||
YearCalendar,
|
YearCalendar,
|
||||||
areDatesEqual,
|
areDatesEqual,
|
||||||
getMonday,
|
getMonday,
|
||||||
showPopup
|
showPopup
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { CalendarMode } from '../index'
|
import { CalendarMode, DayCalendar } from '../index'
|
||||||
import calendar from '../plugin'
|
import calendar from '../plugin'
|
||||||
import Day from './Day.svelte'
|
import Day from './Day.svelte'
|
||||||
import EventElement from './EventElement.svelte'
|
|
||||||
|
|
||||||
export let _class: Ref<Class<Doc>> = calendar.class.Event
|
export let _class: Ref<Class<Doc>> = calendar.class.Event
|
||||||
export let query: DocumentQuery<Event> | undefined = undefined
|
export let query: DocumentQuery<Event> | undefined = undefined
|
||||||
export let options: FindOptions<Event> | undefined = undefined
|
export let options: FindOptions<Event> | undefined = undefined
|
||||||
export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent
|
export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent
|
||||||
|
export let dragItem: Doc | undefined = undefined
|
||||||
|
export let dragEventClass: Ref<Class<Event>> = calendar.class.Event
|
||||||
export let allowedModes: CalendarMode[] = [
|
export let allowedModes: CalendarMode[] = [
|
||||||
CalendarMode.Days,
|
CalendarMode.Days,
|
||||||
CalendarMode.Week,
|
CalendarMode.Week,
|
||||||
@ -117,7 +115,6 @@
|
|||||||
const calendarsQuery = createQuery()
|
const calendarsQuery = createQuery()
|
||||||
|
|
||||||
let calendars: Calendar[] = []
|
let calendars: Calendar[] = []
|
||||||
const offsetTZ = new Date().getTimezoneOffset() * 60 * 1000
|
|
||||||
|
|
||||||
calendarsQuery.query(calendar.class.Calendar, { createdBy: me._id }, (res) => {
|
calendarsQuery.query(calendar.class.Calendar, { createdBy: me._id }, (res) => {
|
||||||
calendars = res
|
calendars = res
|
||||||
@ -233,6 +230,50 @@
|
|||||||
ddItems = ddItems
|
ddItems = ddItems
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dragItemId = 'drag_item' as Ref<Event>
|
||||||
|
|
||||||
|
function dragEnter (e: CustomEvent<any>) {
|
||||||
|
if (dragItem !== undefined) {
|
||||||
|
const current = raw.find((p) => p._id === dragItemId)
|
||||||
|
if (current !== undefined) {
|
||||||
|
current.attachedTo = dragItem._id
|
||||||
|
current.attachedToClass = dragItem._class
|
||||||
|
current.date = e.detail.date.getTime()
|
||||||
|
current.dueDate = new Date(e.detail.date).setMinutes(new Date(e.detail.date).getMinutes() + 30)
|
||||||
|
} else {
|
||||||
|
const me = getCurrentAccount() as PersonAccount
|
||||||
|
raw.push({
|
||||||
|
_id: dragItemId,
|
||||||
|
allDay: false,
|
||||||
|
eventId: generateEventId(),
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
access: 'owner',
|
||||||
|
attachedTo: dragItem._id,
|
||||||
|
attachedToClass: dragItem._class,
|
||||||
|
_class: dragEventClass,
|
||||||
|
collection: 'events',
|
||||||
|
space: dragItem.space,
|
||||||
|
modifiedBy: me._id,
|
||||||
|
participants: [me.person],
|
||||||
|
modifiedOn: Date.now(),
|
||||||
|
date: e.detail.date.getTime(),
|
||||||
|
dueDate: new Date(e.detail.date).setMinutes(new Date(e.detail.date).getMinutes() + 30)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
raw = raw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: clear(dragItem)
|
||||||
|
|
||||||
|
function clear (dragItem: Doc | undefined) {
|
||||||
|
if (dragItem === undefined) {
|
||||||
|
raw = raw.filter((p) => p._id !== dragItemId)
|
||||||
|
objects = getAllEvents(raw, from, to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$: getDdItems(allowedModes)
|
$: getDdItems(allowedModes)
|
||||||
|
|
||||||
let ddItems: {
|
let ddItems: {
|
||||||
@ -247,55 +288,6 @@
|
|||||||
{ id: 'month', label: calendar.string.ModeMonth, mode: CalendarMode.Month },
|
{ id: 'month', label: calendar.string.ModeMonth, mode: CalendarMode.Month },
|
||||||
{ id: 'year', label: calendar.string.ModeYear, mode: CalendarMode.Year }
|
{ id: 'year', label: calendar.string.ModeYear, mode: CalendarMode.Year }
|
||||||
]
|
]
|
||||||
|
|
||||||
const toCalendar = (
|
|
||||||
events: Event[],
|
|
||||||
date: Date,
|
|
||||||
days: number = 1,
|
|
||||||
startHour: number = 0,
|
|
||||||
endHour: number = 24
|
|
||||||
): CalendarItem[] => {
|
|
||||||
const result: CalendarItem[] = []
|
|
||||||
for (let day = 0; day < days; day++) {
|
|
||||||
const startDay = new Date(MILLISECONDS_IN_DAY * day + date.getTime()).setHours(0, 0, 0, 0)
|
|
||||||
const startDate = new Date(MILLISECONDS_IN_DAY * day + date.getTime()).setHours(startHour, 0, 0, 0)
|
|
||||||
const lastDate = new Date(MILLISECONDS_IN_DAY * day + date.getTime()).setHours(endHour, 0, 0, 0)
|
|
||||||
events.forEach((event) => {
|
|
||||||
const eventStart = event.allDay ? event.date + offsetTZ : event.date
|
|
||||||
const eventEnd = event.allDay ? event.dueDate + offsetTZ : event.dueDate
|
|
||||||
if ((eventStart < lastDate && eventEnd > startDate) || (eventStart === eventEnd && eventStart === startDay)) {
|
|
||||||
result.push({
|
|
||||||
_id: event._id,
|
|
||||||
allDay: event.allDay,
|
|
||||||
date: eventStart,
|
|
||||||
dueDate: eventEnd,
|
|
||||||
day,
|
|
||||||
access: event.access
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const sd = date.setHours(0, 0, 0, 0)
|
|
||||||
const ld = new Date(MILLISECONDS_IN_DAY * (days - 1) + date.getTime()).setHours(23, 59, 59, 999)
|
|
||||||
events
|
|
||||||
.filter((ev) => ev.allDay)
|
|
||||||
.sort((a, b) => b.dueDate - b.date - (a.dueDate - a.date))
|
|
||||||
.forEach((event) => {
|
|
||||||
const eventStart = event.date + offsetTZ
|
|
||||||
const eventEnd = event.dueDate + offsetTZ
|
|
||||||
if ((eventStart < ld && eventEnd > sd) || (eventStart === eventEnd && eventStart === sd)) {
|
|
||||||
result.push({
|
|
||||||
_id: event._id,
|
|
||||||
allDay: event.allDay,
|
|
||||||
date: eventStart,
|
|
||||||
dueDate: eventEnd,
|
|
||||||
day: -1,
|
|
||||||
access: event.access
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="calendar-header">
|
<div class="calendar-header">
|
||||||
@ -383,7 +375,7 @@
|
|||||||
</MonthCalendar>
|
</MonthCalendar>
|
||||||
{:else if mode === CalendarMode.Week}
|
{:else if mode === CalendarMode.Week}
|
||||||
<DayCalendar
|
<DayCalendar
|
||||||
events={toCalendar(objects, currentDate, 7)}
|
events={objects}
|
||||||
{mondayStart}
|
{mondayStart}
|
||||||
displayedDaysCount={7}
|
displayedDaysCount={7}
|
||||||
startFromWeekStart={false}
|
startFromWeekStart={false}
|
||||||
@ -391,18 +383,12 @@
|
|||||||
bind:currentDate
|
bind:currentDate
|
||||||
on:create={(e) => showCreateDialog(e.detail.date, e.detail.withTime)}
|
on:create={(e) => showCreateDialog(e.detail.date, e.detail.withTime)}
|
||||||
on:drop
|
on:drop
|
||||||
>
|
on:dragenter={dragEnter}
|
||||||
<svelte:fragment slot="event" let:id let:size>
|
/>
|
||||||
{@const event = objects.find((event) => event._id === id)}
|
|
||||||
{#if event}
|
|
||||||
<EventElement {event} {size} />
|
|
||||||
{/if}
|
|
||||||
</svelte:fragment>
|
|
||||||
</DayCalendar>
|
|
||||||
{:else if mode === CalendarMode.Day || mode === CalendarMode.Days}
|
{:else if mode === CalendarMode.Day || mode === CalendarMode.Days}
|
||||||
{#key mode}
|
{#key mode}
|
||||||
<DayCalendar
|
<DayCalendar
|
||||||
events={toCalendar(objects, currentDate, mode === CalendarMode.Days ? 3 : 1)}
|
events={objects}
|
||||||
{mondayStart}
|
{mondayStart}
|
||||||
displayedDaysCount={mode === CalendarMode.Days ? 3 : 1}
|
displayedDaysCount={mode === CalendarMode.Days ? 3 : 1}
|
||||||
startFromWeekStart={false}
|
startFromWeekStart={false}
|
||||||
@ -410,14 +396,8 @@
|
|||||||
bind:currentDate
|
bind:currentDate
|
||||||
on:create={(e) => showCreateDialog(e.detail.date, e.detail.withTime)}
|
on:create={(e) => showCreateDialog(e.detail.date, e.detail.withTime)}
|
||||||
on:drop
|
on:drop
|
||||||
>
|
on:dragenter={dragEnter}
|
||||||
<svelte:fragment slot="event" let:id let:size>
|
/>
|
||||||
{@const event = objects.find((event) => event._id === id)}
|
|
||||||
{#if event}
|
|
||||||
<EventElement {event} {size} />
|
|
||||||
{/if}
|
|
||||||
</svelte:fragment>
|
|
||||||
</DayCalendar>
|
|
||||||
{/key}
|
{/key}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -13,28 +13,29 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { Event } from '@hcengineering/calendar'
|
||||||
import { Timestamp } from '@hcengineering/core'
|
import { Timestamp } from '@hcengineering/core'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
|
||||||
import ui, {
|
import ui, {
|
||||||
resizeObserver,
|
|
||||||
deviceOptionsStore as deviceInfo,
|
|
||||||
Scroller,
|
|
||||||
Label,
|
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
|
CalendarItem,
|
||||||
|
IconDownOutline,
|
||||||
IconUpOutline,
|
IconUpOutline,
|
||||||
IconDownOutline
|
Label,
|
||||||
} from '../..'
|
|
||||||
import {
|
|
||||||
MILLISECONDS_IN_DAY,
|
MILLISECONDS_IN_DAY,
|
||||||
|
Scroller,
|
||||||
addZero,
|
addZero,
|
||||||
|
areDatesEqual,
|
||||||
|
deviceOptionsStore as deviceInfo,
|
||||||
day as getDay,
|
day as getDay,
|
||||||
getMonday,
|
getMonday,
|
||||||
getWeekDayName,
|
getWeekDayName,
|
||||||
areDatesEqual
|
resizeObserver
|
||||||
} from './internal/DateUtils'
|
} from '@hcengineering/ui'
|
||||||
import { CalendarItem } from '../../types'
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
|
import calendar from '../plugin'
|
||||||
|
import EventElement from './EventElement.svelte'
|
||||||
|
|
||||||
export let events: CalendarItem[]
|
export let events: Event[]
|
||||||
export let mondayStart = true
|
export let mondayStart = true
|
||||||
export let selectedDate: Date = new Date()
|
export let selectedDate: Date = new Date()
|
||||||
export let currentDate: Date = selectedDate
|
export let currentDate: Date = selectedDate
|
||||||
@ -54,6 +55,59 @@
|
|||||||
}
|
}
|
||||||
const rem = (n: number): number => n * fontSize
|
const rem = (n: number): number => n * fontSize
|
||||||
|
|
||||||
|
const offsetTZ = new Date().getTimezoneOffset() * 60 * 1000
|
||||||
|
|
||||||
|
const toCalendar = (
|
||||||
|
events: Event[],
|
||||||
|
date: Date,
|
||||||
|
days: number = 1,
|
||||||
|
startHour: number = 0,
|
||||||
|
endHour: number = 24
|
||||||
|
): CalendarItem[] => {
|
||||||
|
const result: CalendarItem[] = []
|
||||||
|
for (let day = 0; day < days; day++) {
|
||||||
|
const startDay = new Date(MILLISECONDS_IN_DAY * day + date.getTime()).setHours(0, 0, 0, 0)
|
||||||
|
const startDate = new Date(MILLISECONDS_IN_DAY * day + date.getTime()).setHours(startHour, 0, 0, 0)
|
||||||
|
const lastDate = new Date(MILLISECONDS_IN_DAY * day + date.getTime()).setHours(endHour, 0, 0, 0)
|
||||||
|
events.forEach((event) => {
|
||||||
|
const eventStart = event.allDay ? event.date + offsetTZ : event.date
|
||||||
|
const eventEnd = event.allDay ? event.dueDate + offsetTZ : event.dueDate
|
||||||
|
if ((eventStart < lastDate && eventEnd > startDate) || (eventStart === eventEnd && eventStart === startDay)) {
|
||||||
|
result.push({
|
||||||
|
_id: event._id,
|
||||||
|
allDay: event.allDay,
|
||||||
|
date: eventStart,
|
||||||
|
dueDate: eventEnd,
|
||||||
|
day,
|
||||||
|
access: event.access
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const sd = date.setHours(0, 0, 0, 0)
|
||||||
|
const ld = new Date(MILLISECONDS_IN_DAY * (days - 1) + date.getTime()).setHours(23, 59, 59, 999)
|
||||||
|
events
|
||||||
|
.filter((ev) => ev.allDay)
|
||||||
|
.sort((a, b) => b.dueDate - b.date - (a.dueDate - a.date))
|
||||||
|
.forEach((event) => {
|
||||||
|
const eventStart = event.date + offsetTZ
|
||||||
|
const eventEnd = event.dueDate + offsetTZ
|
||||||
|
if ((eventStart < ld && eventEnd > sd) || (eventStart === eventEnd && eventStart === sd)) {
|
||||||
|
result.push({
|
||||||
|
_id: event._id,
|
||||||
|
allDay: event.allDay,
|
||||||
|
date: eventStart,
|
||||||
|
dueDate: eventEnd,
|
||||||
|
day: -1,
|
||||||
|
access: event.access
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
$: calendarEvents = toCalendar(events, currentDate, displayedDaysCount, startHour, displayedHours + startHour)
|
||||||
|
|
||||||
$: fontSize = $deviceInfo.fontSize
|
$: fontSize = $deviceInfo.fontSize
|
||||||
$: docHeight = $deviceInfo.docHeight
|
$: docHeight = $deviceInfo.docHeight
|
||||||
$: cellHeight = 4 * fontSize
|
$: cellHeight = 4 * fontSize
|
||||||
@ -88,7 +142,7 @@
|
|||||||
let calendarWidth: number = 0
|
let calendarWidth: number = 0
|
||||||
let calendarRect: DOMRect
|
let calendarRect: DOMRect
|
||||||
let colWidth: number = 0
|
let colWidth: number = 0
|
||||||
let newEvents = events
|
let newEvents = calendarEvents
|
||||||
let grid: CalendarGrid[] = Array<CalendarGrid>(displayedDaysCount)
|
let grid: CalendarGrid[] = Array<CalendarGrid>(displayedDaysCount)
|
||||||
let alldays: CalendarItem[] = []
|
let alldays: CalendarItem[] = []
|
||||||
let alldaysGrid: CalendarADGrid[] = Array<CalendarADGrid>(displayedDaysCount)
|
let alldaysGrid: CalendarADGrid[] = Array<CalendarADGrid>(displayedDaysCount)
|
||||||
@ -105,8 +159,8 @@
|
|||||||
let shortAlldays: { id: string; day: number; fixRow?: boolean }[] = []
|
let shortAlldays: { id: string; day: number; fixRow?: boolean }[] = []
|
||||||
let moreCounts: number[] = Array<number>(displayedDaysCount)
|
let moreCounts: number[] = Array<number>(displayedDaysCount)
|
||||||
|
|
||||||
$: if (newEvents !== events) {
|
$: if (newEvents !== calendarEvents) {
|
||||||
newEvents = events
|
newEvents = calendarEvents
|
||||||
grid = new Array<CalendarGrid>(displayedDaysCount)
|
grid = new Array<CalendarGrid>(displayedDaysCount)
|
||||||
alldaysGrid = new Array<CalendarADGrid>(displayedDaysCount)
|
alldaysGrid = new Array<CalendarADGrid>(displayedDaysCount)
|
||||||
alldays = []
|
alldays = []
|
||||||
@ -187,12 +241,12 @@
|
|||||||
adMaxRow++
|
adMaxRow++
|
||||||
}
|
}
|
||||||
const prepareAllDays = () => {
|
const prepareAllDays = () => {
|
||||||
alldays = events.filter((ev) => ev.day === -1)
|
alldays = calendarEvents.filter((ev) => ev.allDay)
|
||||||
adRows = []
|
adRows = []
|
||||||
for (let i = 0; i < displayedDaysCount; i++) alldaysGrid[i] = { alldays: [null] }
|
for (let i = 0; i < displayedDaysCount; i++) alldaysGrid[i] = { alldays: [null] }
|
||||||
adMaxRow = 1
|
adMaxRow = 1
|
||||||
alldays.forEach((event) => {
|
alldays.forEach((event) => {
|
||||||
const days = events
|
const days = calendarEvents
|
||||||
.filter((ev) => ev.allDay && ev.day !== -1 && event._id === ev._id)
|
.filter((ev) => ev.allDay && ev.day !== -1 && event._id === ev._id)
|
||||||
.map((ev) => {
|
.map((ev) => {
|
||||||
return ev.day
|
return ev.day
|
||||||
@ -288,7 +342,8 @@
|
|||||||
result.bottom =
|
result.bottom =
|
||||||
cellHeight * (displayedHours - startHour - endTime.hours - 1) +
|
cellHeight * (displayedHours - startHour - endTime.hours - 1) +
|
||||||
((60 - endTime.mins) / 60) * cellHeight +
|
((60 - endTime.mins) / 60) * cellHeight +
|
||||||
getGridOffset(endTime.mins, true)
|
getGridOffset(endTime.mins, true) +
|
||||||
|
(showHeader ? 0 : rem(2.5))
|
||||||
let cols = 1
|
let cols = 1
|
||||||
let index: number = 0
|
let index: number = 0
|
||||||
grid[event.day].columns.forEach((col, i) =>
|
grid[event.day].columns.forEach((col, i) =>
|
||||||
@ -414,7 +469,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<div class="sticky-header allday-header text-sm content-dark-color">
|
<div class="sticky-header allday-header text-sm content-dark-color">
|
||||||
All day
|
<Label label={calendar.string.AllDay} />
|
||||||
{#if (!minimizedAD && adMaxRow > maxAD) || (minimizedAD && adMaxRow > minAD)}
|
{#if (!minimizedAD && adMaxRow > maxAD) || (minimizedAD && adMaxRow > minAD)}
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
icon={shownAD ? IconUpOutline : IconDownOutline}
|
icon={shownAD ? IconUpOutline : IconDownOutline}
|
||||||
@ -432,19 +487,26 @@
|
|||||||
<div style:min-height={`${shownHeightAD - cellBorder * 2}px`} />
|
<div style:min-height={`${shownHeightAD - cellBorder * 2}px`} />
|
||||||
{#each alldays as event, i}
|
{#each alldays as event, i}
|
||||||
{@const rect = getADRect(event._id)}
|
{@const rect = getADRect(event._id)}
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
{@const ev = events.find((p) => p._id === event._id)}
|
||||||
<div
|
{#if ev}
|
||||||
class="calendar-element"
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
style:top={`${rect.top}px`}
|
<div
|
||||||
style:height={`${rect.height}px`}
|
class="calendar-element"
|
||||||
style:left={`${rect.left}px`}
|
style:top={`${rect.top}px`}
|
||||||
style:width={`${rect.width}px`}
|
style:height={`${rect.height}px`}
|
||||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
style:left={`${rect.left}px`}
|
||||||
style:--mask-image={getMask(rect.visibility)}
|
style:width={`${rect.width}px`}
|
||||||
tabindex={500 + i}
|
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||||
>
|
style:--mask-image={getMask(rect.visibility)}
|
||||||
<slot name="event" id={event._id} size={{ width: rect.width, height: rect.height }} />
|
tabindex={500 + i}
|
||||||
</div>
|
>
|
||||||
|
<EventElement
|
||||||
|
hourHeight={cellHeight}
|
||||||
|
event={ev}
|
||||||
|
size={{ width: rect.width, height: rect.height }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{/key}{/key}{/key}
|
{/key}{/key}{/key}
|
||||||
</Scroller>
|
</Scroller>
|
||||||
@ -452,38 +514,44 @@
|
|||||||
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
||||||
{#each alldays as event, i}
|
{#each alldays as event, i}
|
||||||
{@const rect = getADRect(event._id)}
|
{@const rect = getADRect(event._id)}
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
{@const ev = events.find((p) => p._id === event._id)}
|
||||||
<div
|
{#if ev}
|
||||||
class="calendar-element"
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
style:top={`${rect.top}px`}
|
<div
|
||||||
style:height={`${rect.height}px`}
|
class="calendar-element"
|
||||||
style:left={`${rect.left}px`}
|
style:top={`${rect.top}px`}
|
||||||
style:width={`${rect.width}px`}
|
style:height={`${rect.height}px`}
|
||||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
style:left={`${rect.left}px`}
|
||||||
style:--mask-image={getMask(rect.visibility)}
|
style:width={`${rect.width}px`}
|
||||||
tabindex={500 + i}
|
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||||
>
|
style:--mask-image={getMask(rect.visibility)}
|
||||||
<slot name="event" id={event._id} size={{ width: rect.width, height: rect.height }} />
|
tabindex={500 + i}
|
||||||
</div>
|
>
|
||||||
|
<EventElement hourHeight={cellHeight} event={ev} size={{ width: rect.width, height: rect.height }} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{/key}
|
{/key}
|
||||||
{:else}
|
{:else}
|
||||||
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
||||||
{#each shortAlldays as event, i}
|
{#each shortAlldays as event, i}
|
||||||
{@const rect = getADRect(event.id, event.day, event.fixRow)}
|
{@const rect = getADRect(event.id, event.day, event.fixRow)}
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
{@const ev = events.find((p) => p._id === event.id)}
|
||||||
<div
|
{#if ev}
|
||||||
class="calendar-element"
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
style:top={`${rect.top}px`}
|
<div
|
||||||
style:height={`${rect.height}px`}
|
class="calendar-element"
|
||||||
style:left={`${rect.left}px`}
|
style:top={`${rect.top}px`}
|
||||||
style:width={`${rect.width}px`}
|
style:height={`${rect.height}px`}
|
||||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
style:left={`${rect.left}px`}
|
||||||
style:--mask-image={getMask(rect.visibility)}
|
style:width={`${rect.width}px`}
|
||||||
tabindex={500 + i}
|
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||||
>
|
style:--mask-image={getMask(rect.visibility)}
|
||||||
<slot name="event" id={event.id} size={{ width: rect.width, height: rect.height }} />
|
tabindex={500 + i}
|
||||||
</div>
|
>
|
||||||
|
<EventElement hourHeight={cellHeight} event={ev} size={{ width: rect.width, height: rect.height }} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{#each moreCounts as more, day}
|
{#each moreCounts as more, day}
|
||||||
{@const addon = shortAlldays.length}
|
{@const addon = shortAlldays.length}
|
||||||
@ -530,7 +598,11 @@
|
|||||||
style:width={`${colWidth}px`}
|
style:width={`${colWidth}px`}
|
||||||
style:grid-column={`col-start ${dayOfWeek + 1} / ${dayOfWeek + 2}`}
|
style:grid-column={`col-start ${dayOfWeek + 1} / ${dayOfWeek + 2}`}
|
||||||
style:grid-row={`row-start ${hourOfDay * 2 + 1} / row-start ${hourOfDay * 2 + 3}`}
|
style:grid-row={`row-start ${hourOfDay * 2 + 1} / row-start ${hourOfDay * 2 + 3}`}
|
||||||
on:dragover|preventDefault
|
on:dragenter={(e) => {
|
||||||
|
dispatch('dragenter', {
|
||||||
|
date: new Date(day.setHours(hourOfDay + startHour, 0, 0, 0))
|
||||||
|
})
|
||||||
|
}}
|
||||||
on:drop|preventDefault={(e) => {
|
on:drop|preventDefault={(e) => {
|
||||||
dispatch('drop', {
|
dispatch('drop', {
|
||||||
day,
|
day,
|
||||||
@ -552,26 +624,35 @@
|
|||||||
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
||||||
{#each newEvents.filter((ev) => !ev.allDay) as event, i}
|
{#each newEvents.filter((ev) => !ev.allDay) as event, i}
|
||||||
{@const rect = getRect(event)}
|
{@const rect = getRect(event)}
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
{@const ev = events.find((p) => p._id === event._id)}
|
||||||
<div
|
{#if ev}
|
||||||
class="calendar-element"
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
style:top={`${rect.top}px`}
|
<div
|
||||||
style:bottom={`${rect.bottom}px`}
|
class="calendar-element"
|
||||||
style:left={`${rect.left}px`}
|
style:top={`${rect.top}px`}
|
||||||
style:right={`${rect.right}px`}
|
style:bottom={`${rect.bottom}px`}
|
||||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
style:left={`${rect.left}px`}
|
||||||
style:--mask-image={'none'}
|
style:right={`${rect.right}px`}
|
||||||
tabindex={1000 + i}
|
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||||
>
|
style:--mask-image={'none'}
|
||||||
<slot
|
tabindex={1000 + i}
|
||||||
name="event"
|
>
|
||||||
id={event._id}
|
<EventElement
|
||||||
size={{
|
event={ev}
|
||||||
width: rect.width,
|
hourHeight={cellHeight}
|
||||||
height: (calendarRect?.height ?? rect.top + rect.bottom) - rect.top - rect.bottom
|
size={{
|
||||||
}}
|
width: rect.width,
|
||||||
/>
|
height: (calendarRect?.height ?? rect.top + rect.bottom) - rect.top - rect.bottom
|
||||||
</div>
|
}}
|
||||||
|
on:drop={(e) => {
|
||||||
|
dispatch('drop', {
|
||||||
|
date: new Date(event.date)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
on:resize={() => (events = events)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
@ -596,6 +677,7 @@
|
|||||||
mask-image: var(--mask-image, none);
|
mask-image: var(--mask-image, none);
|
||||||
--webkit-mask-image: var(--mask-image, none);
|
--webkit-mask-image: var(--mask-image, none);
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.sticky-header {
|
.sticky-header {
|
||||||
position: sticky;
|
position: sticky;
|
@ -13,47 +13,141 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Event } from '@hcengineering/calendar'
|
import calendar, { CalendarEventPresenter, Event } from '@hcengineering/calendar'
|
||||||
import { MILLISECONDS_IN_MINUTE, addZero, showPanel, tooltip } from '@hcengineering/ui'
|
import { Doc, DocumentUpdate } from '@hcengineering/core'
|
||||||
import view from '@hcengineering/view'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
|
import { Component, MILLISECONDS_IN_MINUTE, deviceOptionsStore, showPopup, tooltip } from '@hcengineering/ui'
|
||||||
|
import view, { ObjectEditor } from '@hcengineering/view'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import EventPresenter from './EventPresenter.svelte'
|
import EventPresenter from './EventPresenter.svelte'
|
||||||
|
|
||||||
export let event: Event
|
export let event: Event
|
||||||
|
export let hourHeight: number
|
||||||
export let size: { width: number; height: number }
|
export let size: { width: number; height: number }
|
||||||
|
|
||||||
$: startDate = new Date(event.date)
|
|
||||||
$: endDate = new Date(event.dueDate)
|
|
||||||
$: oneRow = size.height < 42 || event.allDay
|
$: oneRow = size.height < 42 || event.allDay
|
||||||
$: narrow = event.dueDate - event.date < MILLISECONDS_IN_MINUTE * 25
|
$: narrow = event.dueDate - event.date < MILLISECONDS_IN_MINUTE * 25
|
||||||
$: empty = size.width < 44
|
$: empty = size.width < 44
|
||||||
|
|
||||||
const getTime = (date: Date): string => {
|
function click () {
|
||||||
return `${addZero(date.getHours())}:${addZero(date.getMinutes())}`
|
const editor = hierarchy.classHierarchyMixin<Doc, ObjectEditor>(event._class, view.mixin.ObjectEditor)
|
||||||
|
if (editor?.editor !== undefined) {
|
||||||
|
showPopup(editor.editor, { object: event })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = getClient()
|
||||||
|
const hierarchy = client.getHierarchy()
|
||||||
|
$: presenter = hierarchy.classHierarchyMixin<Doc, CalendarEventPresenter>(
|
||||||
|
event._class,
|
||||||
|
calendar.mixin.CalendarEventPresenter
|
||||||
|
)
|
||||||
|
|
||||||
|
let div: HTMLDivElement
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
$: fontSize = $deviceOptionsStore.fontSize
|
||||||
|
|
||||||
|
function dragStart (e: DragEvent) {
|
||||||
|
if (event.allDay) return
|
||||||
|
originDate = event.date
|
||||||
|
originDueDate = event.dueDate
|
||||||
|
const rect = div.getBoundingClientRect()
|
||||||
|
const topThreshold = rect.y + fontSize / 2
|
||||||
|
if (e.dataTransfer) {
|
||||||
|
e.dataTransfer.effectAllowed = 'move'
|
||||||
|
e.dataTransfer.dropEffect = 'move'
|
||||||
|
}
|
||||||
|
dragInitY = e.y
|
||||||
|
if (e.y < topThreshold) {
|
||||||
|
dragDirection = 'top'
|
||||||
|
} else {
|
||||||
|
const bottomThreshold = rect.y + rect.height - fontSize / 2
|
||||||
|
if (e.y > bottomThreshold) {
|
||||||
|
dragDirection = 'bottom'
|
||||||
|
} else {
|
||||||
|
dragDirection = 'mid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let originDate = event.date
|
||||||
|
let originDueDate = event.dueDate
|
||||||
|
$: pixelPer15Min = hourHeight / 4
|
||||||
|
let dragInitY: number | undefined
|
||||||
|
let dragDirection: 'bottom' | 'mid' | 'top' | undefined
|
||||||
|
|
||||||
|
function drag (e: DragEvent) {
|
||||||
|
if (event.allDay) return
|
||||||
|
if (dragInitY !== undefined) {
|
||||||
|
const diff = Math.floor((e.y - dragInitY) / pixelPer15Min)
|
||||||
|
if (diff) {
|
||||||
|
if (dragDirection !== 'bottom') {
|
||||||
|
const newValue = new Date(originDate).setMinutes(new Date(originDate).getMinutes() + 15 * diff)
|
||||||
|
if (dragDirection === 'top') {
|
||||||
|
if (newValue < event.dueDate) {
|
||||||
|
event.date = newValue
|
||||||
|
dispatch('resize')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const newDue = new Date(originDueDate).setMinutes(new Date(originDueDate).getMinutes() + 15 * diff)
|
||||||
|
event.date = newValue
|
||||||
|
event.dueDate = newDue
|
||||||
|
dispatch('resize')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const newDue = new Date(originDueDate).setMinutes(new Date(originDueDate).getMinutes() + 15 * diff)
|
||||||
|
if (newDue > event.date) {
|
||||||
|
event.dueDate = newDue
|
||||||
|
dispatch('resize')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function drop () {
|
||||||
|
const update: DocumentUpdate<Event> = {}
|
||||||
|
if (originDate !== event.date) {
|
||||||
|
update.date = event.date
|
||||||
|
}
|
||||||
|
if (originDueDate !== event.dueDate) {
|
||||||
|
update.dueDate = event.dueDate
|
||||||
|
}
|
||||||
|
if (Object.keys(update).length > 0) {
|
||||||
|
await client.update(event, {
|
||||||
|
dueDate: event.dueDate,
|
||||||
|
date: event.date
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if event}
|
{#if event}
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div
|
<div
|
||||||
|
bind:this={div}
|
||||||
class="event-container"
|
class="event-container"
|
||||||
class:oneRow
|
class:oneRow
|
||||||
class:empty
|
class:empty
|
||||||
|
draggable={!event.allDay}
|
||||||
use:tooltip={{ component: EventPresenter, props: { value: event } }}
|
use:tooltip={{ component: EventPresenter, props: { value: event } }}
|
||||||
on:click|stopPropagation={() => {
|
on:click|stopPropagation={click}
|
||||||
if (event) showPanel(view.component.EditDoc, event._id, event._class, 'content')
|
on:dragstart={dragStart}
|
||||||
}}
|
on:drag={drag}
|
||||||
|
on:dragend={drop}
|
||||||
|
on:drop
|
||||||
>
|
>
|
||||||
{#if !narrow && !empty}
|
{#if !empty && presenter?.presenter}
|
||||||
<b class="overflow-label">{event.title}</b>
|
<Component is={presenter.presenter} props={{ event, narrow, oneRow }} />
|
||||||
{/if}
|
|
||||||
{#if !oneRow && !empty}
|
|
||||||
<span class="overflow-label text-sm">{getTime(startDate)}-{getTime(endDate)}</span>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.event-container {
|
.event-container {
|
||||||
|
pointer-events: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -33,11 +33,13 @@ import UpdateRecInstancePopup from './components/UpdateRecInstancePopup.svelte'
|
|||||||
import ReminderViewlet from './components/activity/ReminderViewlet.svelte'
|
import ReminderViewlet from './components/activity/ReminderViewlet.svelte'
|
||||||
import CalendarIntegrationIcon from './components/icons/Calendar.svelte'
|
import CalendarIntegrationIcon from './components/icons/Calendar.svelte'
|
||||||
import EventElement from './components/EventElement.svelte'
|
import EventElement from './components/EventElement.svelte'
|
||||||
|
import CalendarEventPresenter from './components/CalendarEventPresenter.svelte'
|
||||||
|
import DayCalendar from './components/DayCalendar.svelte'
|
||||||
import calendar from './plugin'
|
import calendar from './plugin'
|
||||||
import contact from '@hcengineering/contact'
|
import contact from '@hcengineering/contact'
|
||||||
import { deleteObjects } from '@hcengineering/view-resources'
|
import { deleteObjects } from '@hcengineering/view-resources'
|
||||||
|
|
||||||
export { EventElement, CalendarView }
|
export { EventElement, CalendarView, DayCalendar }
|
||||||
|
|
||||||
async function saveEventReminder (object: Doc): Promise<void> {
|
async function saveEventReminder (object: Doc): Promise<void> {
|
||||||
showPopup(SaveEventReminder, { objectId: object._id, objectClass: object._class })
|
showPopup(SaveEventReminder, { objectId: object._id, objectClass: object._class })
|
||||||
@ -148,7 +150,8 @@ export default async (): Promise<Resources> => ({
|
|||||||
EventPresenter,
|
EventPresenter,
|
||||||
CreateEvent,
|
CreateEvent,
|
||||||
IntegrationConnect,
|
IntegrationConnect,
|
||||||
CalendarIntegrationIcon
|
CalendarIntegrationIcon,
|
||||||
|
CalendarEventPresenter
|
||||||
},
|
},
|
||||||
activity: {
|
activity: {
|
||||||
ReminderViewlet
|
ReminderViewlet
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Contact } from '@hcengineering/contact'
|
import { Contact } from '@hcengineering/contact'
|
||||||
import type { AttachedDoc, Class, Doc, Markup, Ref, Space, Timestamp } from '@hcengineering/core'
|
import type { AttachedDoc, Class, Doc, Markup, Mixin, Ref, Space, Timestamp } from '@hcengineering/core'
|
||||||
import { NotificationType } from '@hcengineering/notification'
|
import { NotificationType } from '@hcengineering/notification'
|
||||||
import type { Asset, IntlString, Metadata, Plugin } from '@hcengineering/platform'
|
import type { Asset, IntlString, Metadata, Plugin } from '@hcengineering/platform'
|
||||||
import { plugin } from '@hcengineering/platform'
|
import { plugin } from '@hcengineering/platform'
|
||||||
@ -94,6 +94,13 @@ export interface ReccuringInstance extends Event {
|
|||||||
virtual?: boolean
|
virtual?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface CalendarEventPresenter extends Class<Event> {
|
||||||
|
presenter: AnyComponent
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -109,6 +116,9 @@ const calendarPlugin = plugin(calendarId, {
|
|||||||
ReccuringEvent: '' as Ref<Class<ReccuringEvent>>,
|
ReccuringEvent: '' as Ref<Class<ReccuringEvent>>,
|
||||||
ReccuringInstance: '' as Ref<Class<ReccuringInstance>>
|
ReccuringInstance: '' as Ref<Class<ReccuringInstance>>
|
||||||
},
|
},
|
||||||
|
mixin: {
|
||||||
|
CalendarEventPresenter: '' as Ref<Mixin<CalendarEventPresenter>>
|
||||||
|
},
|
||||||
icon: {
|
icon: {
|
||||||
Calendar: '' as Asset,
|
Calendar: '' as Asset,
|
||||||
Location: '' as Asset,
|
Location: '' as Asset,
|
||||||
|
@ -261,11 +261,7 @@ export function getAllEvents (events: Event[], from: Timestamp, to: Timestamp):
|
|||||||
const recurData: ReccuringInstance[] = []
|
const recurData: ReccuringInstance[] = []
|
||||||
const instancesMap: Map<string, ReccuringInstance[]> = new Map()
|
const instancesMap: Map<string, ReccuringInstance[]> = new Map()
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
if (event._class === calendar.class.Event) {
|
if (event._class === calendar.class.ReccuringEvent) {
|
||||||
if (from > event.dueDate) continue
|
|
||||||
if (event.date > to) continue
|
|
||||||
base.push(event)
|
|
||||||
} else if (event._class === calendar.class.ReccuringEvent) {
|
|
||||||
recur.push(event as ReccuringEvent)
|
recur.push(event as ReccuringEvent)
|
||||||
} else if (event._class === calendar.class.ReccuringInstance) {
|
} else if (event._class === calendar.class.ReccuringInstance) {
|
||||||
const instance = event as ReccuringInstance
|
const instance = event as ReccuringInstance
|
||||||
@ -273,6 +269,10 @@ export function getAllEvents (events: Event[], from: Timestamp, to: Timestamp):
|
|||||||
const arr = instancesMap.get(instance.recurringEventId) ?? []
|
const arr = instancesMap.get(instance.recurringEventId) ?? []
|
||||||
arr.push(instance)
|
arr.push(instance)
|
||||||
instancesMap.set(instance.recurringEventId, arr)
|
instancesMap.set(instance.recurringEventId, arr)
|
||||||
|
} else {
|
||||||
|
if (from > event.dueDate) continue
|
||||||
|
if (event.date > to) continue
|
||||||
|
base.push(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const rec of recur) {
|
for (const rec of recur) {
|
||||||
|
Loading…
Reference in New Issue
Block a user