From cbddcf9a3e12cb47606e55c4603681fb168e6d2a Mon Sep 17 00:00:00 2001
From: Denis Bykhov <bykhov.denis@gmail.com>
Date: Wed, 15 May 2024 23:13:42 +0500
Subject: [PATCH] Fix team planning event duplicates (#5605)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
---
 .../src/components/CalendarView.svelte           |  6 +++---
 .../src/components/EventElement.svelte           |  4 ++--
 plugins/calendar-resources/src/utils.ts          |  8 ++++++--
 .../src/components/PlanningCalendar.svelte       |  8 ++++----
 .../src/components/team/WithTeamData.svelte      | 13 ++++---------
 .../src/components/team/agenda/Agenda.svelte     | 16 ++++++----------
 .../src/components/team/agenda/DayPlan.svelte    |  7 +++----
 .../src/components/team/agenda/PlanGroup.svelte  |  7 +++----
 .../components/team/calendar/EventElement.svelte |  4 ++--
 .../components/team/calendar/TeamCalendar.svelte | 11 ++++-------
 .../team/calendar/TeamCalendarDay.svelte         |  6 ++----
 .../time-resources/src/components/team/utils.ts  | 11 ++---------
 12 files changed, 41 insertions(+), 60 deletions(-)

diff --git a/plugins/calendar-resources/src/components/CalendarView.svelte b/plugins/calendar-resources/src/components/CalendarView.svelte
index fa3e52cdb7..29e78bbb3f 100644
--- a/plugins/calendar-resources/src/components/CalendarView.svelte
+++ b/plugins/calendar-resources/src/components/CalendarView.svelte
@@ -39,7 +39,7 @@
     getMonday,
     showPopup
   } from '@hcengineering/ui'
-  import { CalendarMode, DayCalendar, calendarStore, hidePrivateEvents } from '../index'
+  import { CalendarMode, DayCalendar, calendarByIdStore, hidePrivateEvents } from '../index'
   import calendar from '../plugin'
   import Day from './Day.svelte'
 
@@ -140,7 +140,7 @@
     )
   }
   $: update(_class, query, calendars, options)
-  $: visible = hidePrivateEvents(raw, $calendarStore)
+  $: visible = hidePrivateEvents(raw, $calendarByIdStore)
   $: objects = getAllEvents(visible, from, to)
 
   function inRange (start: Date, end: Date, startPeriod: Date, period: 'day' | 'hour'): boolean {
@@ -276,7 +276,7 @@
   function clear (dragItem: Doc | undefined) {
     if (dragItem === undefined) {
       raw = raw.filter((p) => p._id !== dragItemId)
-      visible = hidePrivateEvents(raw, $calendarStore)
+      visible = hidePrivateEvents(raw, $calendarByIdStore)
       objects = getAllEvents(visible, from, to)
     }
   }
diff --git a/plugins/calendar-resources/src/components/EventElement.svelte b/plugins/calendar-resources/src/components/EventElement.svelte
index 7519af2fa1..a1b9ee54ca 100644
--- a/plugins/calendar-resources/src/components/EventElement.svelte
+++ b/plugins/calendar-resources/src/components/EventElement.svelte
@@ -19,7 +19,7 @@
   import { Component, MILLISECONDS_IN_MINUTE, showPopup, tooltip } from '@hcengineering/ui'
   import view, { ObjectEditor } from '@hcengineering/view'
   import { showMenu } from '@hcengineering/view-resources'
-  import { calendarStore, isVisible } from '../utils'
+  import { calendarByIdStore, isVisible } from '../utils'
   import EventPresenter from './EventPresenter.svelte'
 
   export let event: Event
@@ -48,7 +48,7 @@
 
   let div: HTMLDivElement
 
-  $: visible = isVisible(event, $calendarStore)
+  $: visible = isVisible(event, $calendarByIdStore)
 
   function contextMenu (e: MouseEvent): void {
     showMenu(e, { object: event })
diff --git a/plugins/calendar-resources/src/utils.ts b/plugins/calendar-resources/src/utils.ts
index eb61914f80..a4dfa48fe4 100644
--- a/plugins/calendar-resources/src/utils.ts
+++ b/plugins/calendar-resources/src/utils.ts
@@ -70,7 +70,9 @@ export function isVisible (value: Event, calendars: IdMap<Calendar>): boolean {
   }
 }
 
-export const calendarStore = writable<IdMap<Calendar>>(new Map())
+export const calendarByIdStore = writable<IdMap<Calendar>>(new Map())
+export const calendarStore = writable<Calendar[]>([])
+export const visibleCalendarStore = writable<Calendar[]>([])
 
 function fillStores (): void {
   const client = getClient()
@@ -78,7 +80,9 @@ function fillStores (): void {
   if (client !== undefined) {
     const query = createQuery(true)
     query.query(calendar.class.Calendar, {}, (res) => {
-      calendarStore.set(toIdMap(res))
+      calendarStore.set(res)
+      visibleCalendarStore.set(res.filter((p) => !p.hidden))
+      calendarByIdStore.set(toIdMap(res))
     })
   } else {
     setTimeout(() => {
diff --git a/plugins/time-resources/src/components/PlanningCalendar.svelte b/plugins/time-resources/src/components/PlanningCalendar.svelte
index 9a337dcad3..a4d5218bcc 100644
--- a/plugins/time-resources/src/components/PlanningCalendar.svelte
+++ b/plugins/time-resources/src/components/PlanningCalendar.svelte
@@ -1,7 +1,7 @@
 <script lang="ts">
   import { createEventDispatcher } from 'svelte'
   import calendar, { Calendar, Event, generateEventId, getAllEvents } from '@hcengineering/calendar'
-  import { DayCalendar, calendarStore, hidePrivateEvents } from '@hcengineering/calendar-resources'
+  import { DayCalendar, calendarByIdStore, hidePrivateEvents } from '@hcengineering/calendar-resources'
   import { PersonAccount } from '@hcengineering/contact'
   import { Ref, SortingOrder, Timestamp, getCurrentAccount } from '@hcengineering/core'
   import { IntlString, getEmbeddedLabel } from '@hcengineering/platform'
@@ -75,7 +75,7 @@
 
   $: update(calendars)
   $: all = getAllEvents(raw, from, to)
-  $: objects = hidePrivateEvents(all, $calendarStore)
+  $: objects = hidePrivateEvents(all, $calendarByIdStore)
 
   function inc (val: number): void {
     if (val === 0) {
@@ -140,7 +140,7 @@
       }
       raw = raw
       all = getAllEvents(raw, from, to)
-      objects = hidePrivateEvents(all, $calendarStore)
+      objects = hidePrivateEvents(all, $calendarByIdStore)
     }
   }
   function dragLeave (event: DragEvent) {
@@ -155,7 +155,7 @@
     if (dragItem === null) {
       raw = raw.filter((p) => p._id !== dragItemId)
       all = getAllEvents(raw, from, to)
-      objects = hidePrivateEvents(all, $calendarStore)
+      objects = hidePrivateEvents(all, $calendarByIdStore)
     }
   }
   $: clear(dragItem)
diff --git a/plugins/time-resources/src/components/team/WithTeamData.svelte b/plugins/time-resources/src/components/team/WithTeamData.svelte
index 1acaa0a65b..c9f453c372 100644
--- a/plugins/time-resources/src/components/team/WithTeamData.svelte
+++ b/plugins/time-resources/src/components/team/WithTeamData.svelte
@@ -14,7 +14,7 @@
 -->
 <script lang="ts">
   import calendar, { Calendar, Event } from '@hcengineering/calendar'
-  import { calendarStore, hidePrivateEvents } from '@hcengineering/calendar-resources'
+  import { visibleCalendarStore, hidePrivateEvents, calendarByIdStore } from '@hcengineering/calendar-resources'
   import contact, { Person, PersonAccount } from '@hcengineering/contact'
   import { IdMap, Ref, toIdMap } from '@hcengineering/core'
   import { createQuery, getClient } from '@hcengineering/presentation'
@@ -25,7 +25,6 @@
   export let fromDate: number
   export let toDate: number
   export let project: Project | undefined
-  export let calendars: IdMap<Calendar> = new Map()
   export let personAccounts: PersonAccount[] = []
   export let slots: WorkSlot[] = []
   export let events: Event[] = []
@@ -78,9 +77,9 @@
     }
   )
 
-  $: raw = rawEvent.concat(rawReq)
+  $: raw = rawEvent.concat(rawReq).filter((it, idx, arr) => arr.findIndex((e) => e.eventId === it.eventId) === idx)
 
-  $: visible = hidePrivateEvents(raw, $calendarStore, false)
+  $: visible = hidePrivateEvents(raw, $calendarByIdStore, false)
 
   const todoQuery = createQuery()
 
@@ -97,11 +96,7 @@
     }
   )
 
-  const calendarQuery = createQuery()
-  $: calendarQuery.query(calendar.class.Calendar, { hidden: false }, (res) => {
-    calendarIds = res.map((p) => p._id)
-    calendars = toIdMap(res)
-  })
+  $: calendarIds = $visibleCalendarStore.map((p) => p._id)
 
   const personMapQuery = createQuery()
   $: personMapQuery.query(contact.class.PersonAccount, { person: { $in: persons } }, (res) => {
diff --git a/plugins/time-resources/src/components/team/agenda/Agenda.svelte b/plugins/time-resources/src/components/team/agenda/Agenda.svelte
index c2a40c02e5..d0249890f5 100644
--- a/plugins/time-resources/src/components/team/agenda/Agenda.svelte
+++ b/plugins/time-resources/src/components/team/agenda/Agenda.svelte
@@ -1,14 +1,14 @@
 <script lang="ts">
-  import { Calendar, Event, getAllEvents } from '@hcengineering/calendar'
+  import { Event, getAllEvents } from '@hcengineering/calendar'
+  import { Person, PersonAccount } from '@hcengineering/contact'
   import { IdMap, Ref } from '@hcengineering/core'
   import { Project } from '@hcengineering/task'
-  import Border from '../../Border.svelte'
-  import WithTeamData from '../WithTeamData.svelte'
-  import DayPlan from './DayPlan.svelte'
-  import { toSlots } from '../utils'
-  import { Person, PersonAccount } from '@hcengineering/contact'
   import { ToDo, WorkSlot } from '@hcengineering/time'
+  import Border from '../../Border.svelte'
   import Header from '../../Header.svelte'
+  import WithTeamData from '../WithTeamData.svelte'
+  import { toSlots } from '../utils'
+  import DayPlan from './DayPlan.svelte'
 
   export let space: Ref<Project>
   export let currentDate: Date
@@ -22,7 +22,6 @@
   $: todayTo = new Date(tomorrow).setHours(0, 0, 0, 0)
 
   let project: Project | undefined
-  let calendars: IdMap<Calendar> = new Map()
   let personAccounts: PersonAccount[] = []
   let slots: WorkSlot[] = []
   let events: Event[] = []
@@ -47,7 +46,6 @@
   fromDate={yesterdayFrom}
   toDate={todayTo}
   bind:project
-  bind:calendars
   bind:personAccounts
   bind:todos
   bind:slots
@@ -67,7 +65,6 @@
         {persons}
         {personAccounts}
         {project}
-        {calendars}
         {todos}
       />
     </div>
@@ -83,7 +80,6 @@
         {persons}
         {personAccounts}
         {project}
-        {calendars}
         {todos}
       />
     </div>
diff --git a/plugins/time-resources/src/components/team/agenda/DayPlan.svelte b/plugins/time-resources/src/components/team/agenda/DayPlan.svelte
index 5b439a1ead..552b2a00d7 100644
--- a/plugins/time-resources/src/components/team/agenda/DayPlan.svelte
+++ b/plugins/time-resources/src/components/team/agenda/DayPlan.svelte
@@ -1,11 +1,11 @@
 <script lang="ts">
-  import { Calendar, Event } from '@hcengineering/calendar'
+  import { Event } from '@hcengineering/calendar'
   import { Person, PersonAccount } from '@hcengineering/contact'
   import { IdMap, Ref, Timestamp } from '@hcengineering/core'
   import { IntlString, getEmbeddedLabel } from '@hcengineering/platform'
   import { Project } from '@hcengineering/task'
-  import { Label, Scroller, areDatesEqual, ticker } from '@hcengineering/ui'
   import { ToDo, WorkSlot } from '@hcengineering/time'
+  import { Label, Scroller, areDatesEqual, ticker } from '@hcengineering/ui'
   import time from '../../../plugin'
   import PlanGroup from './PlanGroup.svelte'
 
@@ -15,7 +15,6 @@
   export let showAssignee: boolean = false
   export let persons: Ref<Person>[]
   export let personAccounts: PersonAccount[]
-  export let calendars: IdMap<Calendar>
   export let project: Project
   export let todos: IdMap<ToDo>
 
@@ -44,6 +43,6 @@
 </div>
 
 <Scroller padding={'0 1rem'} noStretch shrink>
-  <PlanGroup {slots} {events} {showAssignee} {personAccounts} {calendars} {todos} />
+  <PlanGroup {slots} {events} {showAssignee} {personAccounts} {todos} />
 </Scroller>
 <div class="antiVSpacer x4" />
diff --git a/plugins/time-resources/src/components/team/agenda/PlanGroup.svelte b/plugins/time-resources/src/components/team/agenda/PlanGroup.svelte
index b4db5e32e5..3d4f21a321 100644
--- a/plugins/time-resources/src/components/team/agenda/PlanGroup.svelte
+++ b/plugins/time-resources/src/components/team/agenda/PlanGroup.svelte
@@ -1,6 +1,6 @@
 <script lang="ts">
-  import { Calendar, Event } from '@hcengineering/calendar'
-  import { calendarStore } from '@hcengineering/calendar-resources'
+  import { Event } from '@hcengineering/calendar'
+  import { calendarByIdStore } from '@hcengineering/calendar-resources'
   import { PersonAccount } from '@hcengineering/contact'
   import { IdMap, getCurrentAccount } from '@hcengineering/core'
   import { ToDo, WorkSlot } from '@hcengineering/time'
@@ -12,12 +12,11 @@
   export let showAssignee: boolean = false
 
   export let personAccounts: PersonAccount[]
-  export let calendars: IdMap<Calendar>
   export let todos: IdMap<ToDo>
 
   const me = (getCurrentAccount() as PersonAccount).person
 
-  $: grouped = groupTeamData(slots, todos, events, personAccounts, calendars, me, $calendarStore)
+  $: grouped = groupTeamData(slots, todos, events, personAccounts, me, $calendarByIdStore)
 </script>
 
 <div class="container flex-col background-comp-header-color">
diff --git a/plugins/time-resources/src/components/team/calendar/EventElement.svelte b/plugins/time-resources/src/components/team/calendar/EventElement.svelte
index 6ae3dc9f1c..5a16e32900 100644
--- a/plugins/time-resources/src/components/team/calendar/EventElement.svelte
+++ b/plugins/time-resources/src/components/team/calendar/EventElement.svelte
@@ -14,7 +14,7 @@
 -->
 <script lang="ts">
   import calendar, { CalendarEventPresenter, Event } from '@hcengineering/calendar'
-  import { EventPresenter, calendarStore, isVisible } from '@hcengineering/calendar-resources'
+  import { EventPresenter, calendarByIdStore, isVisible } from '@hcengineering/calendar-resources'
   import { Doc } from '@hcengineering/core'
   import { getClient } from '@hcengineering/presentation'
   import { Component, MILLISECONDS_IN_MINUTE, showPopup, tooltip } from '@hcengineering/ui'
@@ -47,7 +47,7 @@
 
   let div: HTMLDivElement
 
-  $: visible = isVisible(event, $calendarStore)
+  $: visible = isVisible(event, $calendarByIdStore)
 
   function onContext (e: MouseEvent): void {
     showMenu(e, { object: event })
diff --git a/plugins/time-resources/src/components/team/calendar/TeamCalendar.svelte b/plugins/time-resources/src/components/team/calendar/TeamCalendar.svelte
index 56ead42a4c..f69a80c0c3 100644
--- a/plugins/time-resources/src/components/team/calendar/TeamCalendar.svelte
+++ b/plugins/time-resources/src/components/team/calendar/TeamCalendar.svelte
@@ -13,8 +13,8 @@
 // limitations under the License.
 -->
 <script lang="ts">
-  import calendar, { Calendar, Event, getAllEvents } from '@hcengineering/calendar'
-  import { calendarStore } from '@hcengineering/calendar-resources'
+  import calendar, { Event, getAllEvents } from '@hcengineering/calendar'
+  import { calendarByIdStore } from '@hcengineering/calendar-resources'
   import { Person, PersonAccount } from '@hcengineering/contact'
   import core, {
     Account,
@@ -32,9 +32,9 @@
   import { Asset } from '@hcengineering/platform'
   import { createQuery, getClient } from '@hcengineering/presentation'
   import { Project } from '@hcengineering/task'
+  import { ToDo, WorkSlot } from '@hcengineering/time'
   import { Icon, tooltip } from '@hcengineering/ui'
   import view from '@hcengineering/view'
-  import { ToDo, WorkSlot } from '@hcengineering/time'
   import time from '../../../plugin'
   import TimePresenter from '../../presenters/TimePresenter.svelte'
   import WithTeamData from '../WithTeamData.svelte'
@@ -51,7 +51,6 @@
   const me = (getCurrentAccount() as PersonAccount).person
 
   let project: Project | undefined
-  let calendars: IdMap<Calendar> = new Map()
   let personAccounts: PersonAccount[] = []
   let slots: WorkSlot[] = []
   let events: Event[] = []
@@ -145,7 +144,6 @@
   {fromDate}
   {toDate}
   bind:project
-  bind:calendars
   bind:personAccounts
   bind:todos
   bind:slots
@@ -162,9 +160,8 @@
       todos,
       getAllEvents(allEvents, dayFrom, dayTo),
       personAccounts,
-      calendars,
       me,
-      $calendarStore
+      $calendarByIdStore
     )}
     {@const gitem = grouped.find((it) => it.user === person)}
     {@const planned = gitem?.mappings.reduce((it, val) => it + val.total, 0) ?? 0}
diff --git a/plugins/time-resources/src/components/team/calendar/TeamCalendarDay.svelte b/plugins/time-resources/src/components/team/calendar/TeamCalendarDay.svelte
index fa5c9b9c45..4981733440 100644
--- a/plugins/time-resources/src/components/team/calendar/TeamCalendarDay.svelte
+++ b/plugins/time-resources/src/components/team/calendar/TeamCalendarDay.svelte
@@ -14,7 +14,7 @@
 -->
 <script lang="ts">
   import { Calendar, Event, getAllEvents } from '@hcengineering/calendar'
-  import { calendarStore } from '@hcengineering/calendar-resources'
+  import { calendarByIdStore } from '@hcengineering/calendar-resources'
   import { Person, PersonAccount } from '@hcengineering/contact'
   import { IdMap, Ref, getCurrentAccount } from '@hcengineering/core'
   import { Project } from '@hcengineering/task'
@@ -34,7 +34,6 @@
   const me = (getCurrentAccount() as PersonAccount).person
 
   let project: Project | undefined
-  let calendars: IdMap<Calendar> = new Map()
   let personAccounts: PersonAccount[] = []
   let slots: WorkSlot[] = []
   let events: Event[] = []
@@ -84,7 +83,6 @@
   {fromDate}
   {toDate}
   bind:project
-  bind:calendars
   bind:personAccounts
   bind:todos
   bind:slots
@@ -136,7 +134,7 @@
     {@const dayTo = new Date(day).setHours(23, 59, 59, 999)}
     {@const totalSlots = toSlots(getAllEvents(slots, dayFrom, dayTo))}
     {@const totalEvents = getAllEvents(events, dayFrom, dayTo)}
-    {@const grouped = groupTeamData(totalSlots, todos, totalEvents, personAccounts, calendars, me, $calendarStore)}
+    {@const grouped = groupTeamData(totalSlots, todos, totalEvents, personAccounts, me, $calendarByIdStore)}
     {@const gitem = grouped.find((it) => it.user === person)}
     {@const hourWidths = calcHourWidth([...totalSlots, ...totalEvents], width)}
     {#if gitem}
diff --git a/plugins/time-resources/src/components/team/utils.ts b/plugins/time-resources/src/components/team/utils.ts
index 21cc80f703..b03d168214 100644
--- a/plugins/time-resources/src/components/team/utils.ts
+++ b/plugins/time-resources/src/components/team/utils.ts
@@ -39,7 +39,6 @@ export function groupTeamData (
   todos: IdMap<ToDo>,
   events: Event[],
   personAccounts: PersonAccount[],
-  calendars: IdMap<Calendar>,
   mePerson: Ref<Person>,
   calendarStore: IdMap<Calendar>
 ): EventPersonMapping[] {
@@ -91,8 +90,8 @@ export function groupTeamData (
   }
 
   for (const event of events) {
-    const _calendar = calendars.get(event.calendar)
-    if (_calendar === undefined) {
+    const _calendar = calendarStore.get(event.calendar)
+    if (_calendar === undefined || _calendar.hidden) {
       continue
     }
     for (const p of event.participants) {
@@ -126,12 +125,6 @@ export function groupTeamData (
       }
     }
   }
-  console.log(
-    Array.from(totalEventsMap.entries()).map(([k, it]) => [
-      k,
-      it.toSorted((a, b) => a.date - b.date).map((q) => [new Date(q.date), new Date(q.dueDate)])
-    ])
-  )
   return Array.from(result.values())
 }