From b282edfc65533a2e160087fdfe0273347efdd583 Mon Sep 17 00:00:00 2001 From: Kristina Date: Thu, 25 Apr 2024 07:56:18 +0400 Subject: [PATCH] UBERF-6676: Chat local state (#5461) Signed-off-by: Kristina Fefelova --- .../src/components/chat/Chat.svelte | 29 ++++++-- .../chat/navigator/ChatNavGroup.svelte | 1 + .../chat/navigator/ChatNavSection.svelte | 12 +++- .../src/components/chat/utils.ts | 66 ++++++++++++++++++- plugins/chunter-resources/src/navigation.ts | 12 +++- plugins/chunter-resources/src/utils.ts | 6 +- 6 files changed, 112 insertions(+), 14 deletions(-) diff --git a/plugins/chunter-resources/src/components/chat/Chat.svelte b/plugins/chunter-resources/src/components/chat/Chat.svelte index 7cfc41af1e..51adcdb179 100644 --- a/plugins/chunter-resources/src/components/chat/Chat.svelte +++ b/plugins/chunter-resources/src/components/chat/Chat.svelte @@ -28,10 +28,12 @@ import { NavigatorModel, SpecialNavModel } from '@hcengineering/workbench' import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources' import { onMount } from 'svelte' + import { chunterId } from '@hcengineering/chunter' + import { ActivityMessage } from '@hcengineering/activity' import ChatNavigator from './navigator/ChatNavigator.svelte' import ChannelView from '../ChannelView.svelte' - import { chatSpecials, loadSavedAttachments } from './utils' + import { chatSpecials, loadSavedAttachments, storeChannel, openedChannelStore, clearChannel } from './utils' import { SelectChannelEvent } from './types' import { decodeChannelURI, openChannel } from '../../navigation' @@ -58,6 +60,13 @@ syncLocation(loc) }) + openedChannelStore.subscribe((data) => { + if (data && selectedData?._id !== data._id) { + selectedData = data + openChannel(data._id, data._class, data.thread) + } + }) + $: void loadObject(selectedData?._id, selectedData?._class) async function loadObject (_id?: Ref, _class?: Ref>): Promise { @@ -77,17 +86,25 @@ ) } - function syncLocation (loc: Location) { - const specialId = loc.path[3] + function syncLocation (loc: Location): void { + if (loc.path[2] !== chunterId) { + return + } - currentSpecial = navigatorModel?.specials?.find((special) => special.id === specialId) + const id = loc.path[3] + + if (!id) { + return + } + + currentSpecial = navigatorModel?.specials?.find((special) => special.id === id) if (currentSpecial !== undefined) { - selectedData = undefined + clearChannel() } else { const [_id, _class] = decodeChannelURI(loc.path[3]) - selectedData = { _id, _class } + storeChannel(_id, _class, loc.path[4] as Ref) } } diff --git a/plugins/chunter-resources/src/components/chat/navigator/ChatNavGroup.svelte b/plugins/chunter-resources/src/components/chat/navigator/ChatNavGroup.svelte index 6a4bbe1141..98226f4f06 100644 --- a/plugins/chunter-resources/src/components/chat/navigator/ChatNavGroup.svelte +++ b/plugins/chunter-resources/src/components/chat/navigator/ChatNavGroup.svelte @@ -188,6 +188,7 @@ {#each sections as section (section.id)} { items = sortFn(res, contexts) }) @@ -136,7 +140,7 @@ {actions} {isCollapsed} on:collapse={() => { - isCollapsed = !isCollapsed + toggleSections(id) }} /> {#if !isCollapsed} @@ -155,6 +159,12 @@ /> {/if} + {:else if objectId} + {@const item = items.find(({ id }) => id === objectId)} + {#if item} + {@const context = contexts.find(({ attachedTo }) => attachedTo === item.id)} + + {/if} {/if} {/if} diff --git a/plugins/chunter-resources/src/components/chat/utils.ts b/plugins/chunter-resources/src/components/chat/utils.ts index 5377c53ad1..4cb3b62791 100644 --- a/plugins/chunter-resources/src/components/chat/utils.ts +++ b/plugins/chunter-resources/src/components/chat/utils.ts @@ -13,13 +13,13 @@ // limitations under the License. // import notification, { type DocNotifyContext } from '@hcengineering/notification' -import { generateId, SortingOrder, type WithLookup } from '@hcengineering/core' +import { type Class, type Doc, generateId, type Ref, SortingOrder, type WithLookup } from '@hcengineering/core' import { createQuery, getClient, MessageBox } from '@hcengineering/presentation' import { get, writable } from 'svelte/store' import view from '@hcengineering/view' import { type SpecialNavModel } from '@hcengineering/workbench' import attachment, { type SavedAttachments } from '@hcengineering/attachment' -import activity from '@hcengineering/activity' +import activity, { type ActivityMessage } from '@hcengineering/activity' import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources' import { type Action, showPopup } from '@hcengineering/ui' import contact from '@hcengineering/contact' @@ -27,7 +27,69 @@ import contact from '@hcengineering/contact' import { type ChatNavGroupModel, type ChatNavItemModel } from './types' import chunter from '../../plugin' +const channelStorageKey = 'chunter.openedChannel' +const navigatorStateStorageKey = 'chunter.navigatorState' + +interface ChannelMetadata { + _id: Ref + _class: Ref> + thread?: Ref +} +interface NavigatorState { + collapsedSections: string[] +} + export const savedAttachmentsStore = writable>>([]) +export const openedChannelStore = writable(restoreChannel()) +export const navigatorStateStore = writable(restoreNavigatorState()) + +function restoreChannel (): ChannelMetadata | undefined { + const raw = localStorage.getItem(channelStorageKey) + + if (raw == null) return undefined + + try { + return JSON.parse(raw) as ChannelMetadata + } catch (e) { + return undefined + } +} + +function restoreNavigatorState (): NavigatorState { + const raw = localStorage.getItem(navigatorStateStorageKey) + + if (raw == null) return { collapsedSections: [] } + + try { + return JSON.parse(raw) as NavigatorState + } catch (e) { + return { collapsedSections: [] } + } +} + +export function toggleSections (_id: string): void { + const navState = get(navigatorStateStore) + const result: NavigatorState = navState.collapsedSections.includes(_id) + ? { + collapsedSections: navState.collapsedSections.filter((id) => id !== _id) + } + : { collapsedSections: [...navState.collapsedSections, _id] } + + localStorage.setItem(navigatorStateStorageKey, JSON.stringify(result)) + navigatorStateStore.set(result) +} + +export function clearChannel (): void { + localStorage.removeItem(channelStorageKey) + openedChannelStore.set(undefined) +} + +export function storeChannel (_id: Ref, _class: Ref>, thread?: Ref): void { + const data: ChannelMetadata = { _id, _class, thread } + + localStorage.setItem(channelStorageKey, JSON.stringify(data)) + openedChannelStore.set(data) +} export const chatSpecials: SpecialNavModel[] = [ { diff --git a/plugins/chunter-resources/src/navigation.ts b/plugins/chunter-resources/src/navigation.ts index 1fcc8fcfe3..8017b70aea 100644 --- a/plugins/chunter-resources/src/navigation.ts +++ b/plugins/chunter-resources/src/navigation.ts @@ -16,7 +16,7 @@ function encodeChannelURI (_id: Ref, _class: Ref>): string { return [_id, _class].join('|') } -export function openChannel (_id: Ref, _class: Ref>): void { +export function openChannel (_id: Ref, _class: Ref>, thread?: Ref): void { const loc = getCurrentLocation() const id = encodeChannelURI(_id, _class) @@ -26,9 +26,15 @@ export function openChannel (_id: Ref, _class: Ref>): void { } loc.path[3] = id - loc.path[4] = '' loc.query = { ...loc.query, message: null } - loc.path.length = 4 + + if (thread !== undefined) { + loc.path[4] = thread + loc.path.length = 5 + } else { + loc.path[4] = '' + loc.path.length = 4 + } navigate(loc) } diff --git a/plugins/chunter-resources/src/utils.ts b/plugins/chunter-resources/src/utils.ts index cbfbe34346..96f267b4e0 100644 --- a/plugins/chunter-resources/src/utils.ts +++ b/plugins/chunter-resources/src/utils.ts @@ -74,6 +74,7 @@ export async function buildDmName (client: Client, employeeAccounts: PersonAccou }) }) + const me = getCurrentAccount() as PersonAccount const map = await promise unsub?.() @@ -88,7 +89,7 @@ export async function buildDmName (client: Client, employeeAccounts: PersonAccou const employee = map.get(acc.person as unknown as Ref) - if (employee !== undefined) { + if (employee !== undefined && me.person !== employee._id) { names.push(getName(client.getHierarchy(), employee)) processedPersons.push(acc.person) } @@ -156,13 +157,14 @@ async function getDmAccounts (client: Client, space?: Space): Promise { const personAccounts: PersonAccount[] = await getDmAccounts(client, space) + const me = getCurrentAccount() as PersonAccount const persons: Person[] = [] const personRefs = new Set(personAccounts.map(({ person }) => person)) for (const personRef of personRefs) { const person = await client.findOne(contact.class.Person, { _id: personRef }) - if (person !== undefined) { + if (person !== undefined && me.person !== person._id) { persons.push(person) } }