From e001c6ae9205e3b1c6424482726ce1a003e2d7e7 Mon Sep 17 00:00:00 2001 From: Alexander Platov Date: Wed, 27 Sep 2023 22:27:05 +0300 Subject: [PATCH] Calendar: resize and move event Signed-off-by: Alexander Platov --- packages/theme/styles/_layouts.scss | 1 + .../src/components/DayCalendar.svelte | 277 +++++++++++++++--- .../src/components/EditEvent.svelte | 97 +----- .../src/components/EventElement.svelte | 94 +----- plugins/calendar-resources/src/utils.ts | 97 +++++- 5 files changed, 342 insertions(+), 224 deletions(-) diff --git a/packages/theme/styles/_layouts.scss b/packages/theme/styles/_layouts.scss index 9f706f97aac..3053a9106c9 100644 --- a/packages/theme/styles/_layouts.scss +++ b/packages/theme/styles/_layouts.scss @@ -793,6 +793,7 @@ a.no-line { .cursor-pointer { cursor: pointer; } .cursor-default { cursor: default; } .cursor-inherit { cursor: inherit; } +.cursor-row-resize { cursor: row-resize; } .pointer-events-none { pointer-events: none; } .content-pointer-events-none > * { pointer-events: none; } diff --git a/plugins/calendar-resources/src/components/DayCalendar.svelte b/plugins/calendar-resources/src/components/DayCalendar.svelte index 16fe395d025..9808609708e 100644 --- a/plugins/calendar-resources/src/components/DayCalendar.svelte +++ b/plugins/calendar-resources/src/components/DayCalendar.svelte @@ -13,8 +13,9 @@ // limitations under the License. --> mouseMoveElement(e, day, hourOfDay)} on:dragover={(e) => dragOver(e, day, hourOfDay)} - on:drop|preventDefault={(e) => { - dispatch('drop', { - day, - hour: hourOfDay + startHour, - date: new Date(day.setHours(hourOfDay + startHour, getMinutes(e), 0, 0)) - }) - }} + on:drop|preventDefault={(e) => dragDrop(e, day, hourOfDay)} on:click|stopPropagation={() => { dispatch('create', { date: new Date(day.setHours(hourOfDay + startHour, 0, 0, 0)), @@ -733,14 +867,31 @@
dragStartElement(e, ev)} + on:dragend={dragEndElement} > +
mouseDownElement(e, ev, 'top')} + on:contextmenu={(e) => showMenu(e, ev)} + /> +
mouseDownElement(e, ev, 'bottom')} + on:contextmenu={(e) => showMenu(e, ev)} + /> { - dispatch('drop', { - date: new Date(event.date) - }) - }} - on:resize={() => (events = events)} />
{/if} @@ -778,7 +923,7 @@ &::after { position: absolute; content: ''; - inset: 0; + inset: -1px; z-index: 5; } } @@ -847,7 +992,61 @@ &:not(.withPointer) { pointer-events: none; } + &-start, + &-end { + position: absolute; + left: 0; + right: 0; + height: 0.5rem; + border-radius: 0.5rem; + + &::after { + position: absolute; + content: ''; + left: -0.25rem; + right: -0.25rem; + height: 1rem; + border: 1px solid transparent; + border-radius: 0.5rem; + transition-property: opacity, border-width, transform; + transition-duration: 0.15s; + transition-timing-function: var(--timing-main); + transform: scale(0.9); + opacity: 0; + cursor: row-resize; + filter: drop-shadow(0 0 2px var(--primary-edit-border-color)); + pointer-events: none; + } + &.allowed::after { + pointer-events: all; + z-index: 10; + } + &.allowed:hover::after, + &.hovered::after { + border-width: 1px; + transform: scale(1); + opacity: 1; + } + } + &-start { + top: 0; + &::after { + top: -0.25rem; + border-top-color: var(--primary-edit-border-color); + } + } + &-end { + bottom: 0; + &::after { + bottom: -0.25rem; + border-bottom-color: var(--primary-edit-border-color); + } + } + } + :global(.calendar-element.past .event-container) { + opacity: 0.4; } + .sticky-header { position: sticky; background-color: var(--theme-comp-header-color); diff --git a/plugins/calendar-resources/src/components/EditEvent.svelte b/plugins/calendar-resources/src/components/EditEvent.svelte index 93ac4a20874..300c4cedd73 100644 --- a/plugins/calendar-resources/src/components/EditEvent.svelte +++ b/plugins/calendar-resources/src/components/EditEvent.svelte @@ -13,22 +13,21 @@ // limitations under the License. -->
diff --git a/plugins/calendar-resources/src/components/EventElement.svelte b/plugins/calendar-resources/src/components/EventElement.svelte index d5cc7c4973b..6dfd9f4e4d0 100644 --- a/plugins/calendar-resources/src/components/EventElement.svelte +++ b/plugins/calendar-resources/src/components/EventElement.svelte @@ -14,20 +14,19 @@ --> {#if event} @@ -152,14 +71,9 @@ class="event-container" class:oneRow class:empty - draggable={!event.allDay} use:tooltip={{ component: EventPresenter, props: { value: event, hideDetails: !visible } }} on:click|stopPropagation={click} on:contextmenu={showMenu} - on:dragstart={dragStart} - on:drag={drag} - on:dragend={drop} - on:drop > {#if !empty && presenter?.presenter} diff --git a/plugins/calendar-resources/src/utils.ts b/plugins/calendar-resources/src/utils.ts index 41f3d37241c..6e49a427843 100644 --- a/plugins/calendar-resources/src/utils.ts +++ b/plugins/calendar-resources/src/utils.ts @@ -1,8 +1,10 @@ -import { Calendar, Event } from '@hcengineering/calendar' -import { IdMap, Timestamp, getCurrentAccount, toIdMap } from '@hcengineering/core' +import { Calendar, Event, ReccuringEvent, ReccuringInstance, generateEventId } from '@hcengineering/calendar' +import { IdMap, Timestamp, getCurrentAccount, toIdMap, DocumentUpdate } from '@hcengineering/core' import { createQuery, getClient } from '@hcengineering/presentation' +import { showPopup, closePopup, DAY } from '@hcengineering/ui' import { writable } from 'svelte/store' import calendar from './plugin' +import UpdateRecInstancePopup from './components/UpdateRecInstancePopup.svelte' export function saveUTC (date: Timestamp): Timestamp { const utcdate = new Date(date) @@ -76,3 +78,94 @@ function fillStores (): void { } fillStores() + +export async function updatePast (ops: DocumentUpdate, object: ReccuringInstance): Promise { + const client = getClient() + const origin = await client.findOne(calendar.class.ReccuringEvent, { + eventId: object.recurringEventId, + space: object.space + }) + if (origin !== undefined) { + await client.addCollection( + calendar.class.ReccuringEvent, + origin.space, + origin.attachedTo, + origin.attachedToClass, + origin.collection, + { + ...origin, + date: object.date, + dueDate: object.dueDate, + ...ops, + eventId: generateEventId() + } + ) + const targetDate = ops.date ?? object.date + await client.update(origin, { + rules: [{ ...origin.rules[0], endDate: targetDate - DAY }], + rdate: origin.rdate.filter((p) => p < targetDate) + }) + const instances = await client.findAll(calendar.class.ReccuringInstance, { + recurringEventId: origin.eventId, + date: { $gte: targetDate } + }) + for (const instance of instances) { + await client.remove(instance) + } + } +} + +export async function updateReccuringInstance ( + ops: DocumentUpdate, + object: ReccuringInstance +): Promise { + const client = getClient() + if (object.virtual !== true) { + await client.update(object, ops) + } else { + showPopup(UpdateRecInstancePopup, { currentAvailable: ops.rules === undefined }, undefined, async (res) => { + if (res !== null) { + if (res.mode === 'current') { + await client.addCollection( + object._class, + object.space, + object.attachedTo, + object.attachedToClass, + object.collection, + { + title: object.title, + description: object.description, + date: object.date, + dueDate: object.dueDate, + allDay: object.allDay, + participants: object.participants, + externalParticipants: object.externalParticipants, + originalStartTime: object.originalStartTime, + recurringEventId: object.recurringEventId, + reminders: object.reminders, + location: object.location, + eventId: object.eventId, + access: 'owner', + rules: object.rules, + exdate: object.exdate, + rdate: object.rdate, + ...ops + }, + object._id + ) + } else if (res.mode === 'all') { + const base = await client.findOne(calendar.class.ReccuringEvent, { + space: object.space, + eventId: object.recurringEventId + }) + if (base !== undefined) { + await client.update(base, ops) + } + } else if (res.mode === 'next') { + await updatePast(ops, object) + } + } + closePopup() + }) + } +}