UBERF-6676: Chat local state (#5461)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2024-04-25 07:56:18 +04:00 committed by GitHub
parent 608ea96cc8
commit b282edfc65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 112 additions and 14 deletions

View File

@ -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<Doc>, _class?: Ref<Class<Doc>>): Promise<void> {
@ -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<ActivityMessage>)
}
}

View File

@ -188,6 +188,7 @@
{#each sections as section (section.id)}
<ChatNavSection
id={section.id}
objects={section.objects}
{contexts}
{objectId}

View File

@ -27,7 +27,9 @@
import { ChatNavItemModel } from '../types'
import { getObjectIcon, getChannelName } from '../../../utils'
import ChatSectionHeader from './ChatSectionHeader.svelte'
import { navigatorStateStore, toggleSections } from '../utils'
export let id: string
export let header: string
export let objects: Doc[]
export let contexts: DocNotifyContext[]
@ -46,6 +48,8 @@
let canShowMore = false
let isShownMore = false
$: isCollapsed = $navigatorStateStore.collapsedSections.includes(id)
$: void getChatNavItems(objects).then((res) => {
items = sortFn(res, contexts)
})
@ -136,7 +140,7 @@
{actions}
{isCollapsed}
on:collapse={() => {
isCollapsed = !isCollapsed
toggleSections(id)
}}
/>
{#if !isCollapsed}
@ -155,6 +159,12 @@
/>
</div>
{/if}
{:else if objectId}
{@const item = items.find(({ id }) => id === objectId)}
{#if item}
{@const context = contexts.find(({ attachedTo }) => attachedTo === item.id)}
<ChatNavItem {context} isSelected {item} on:select />
{/if}
{/if}
</div>
{/if}

View File

@ -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<Doc>
_class: Ref<Class<Doc>>
thread?: Ref<ActivityMessage>
}
interface NavigatorState {
collapsedSections: string[]
}
export const savedAttachmentsStore = writable<Array<WithLookup<SavedAttachments>>>([])
export const openedChannelStore = writable<ChannelMetadata | undefined>(restoreChannel())
export const navigatorStateStore = writable<NavigatorState>(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<Doc>, _class: Ref<Class<Doc>>, thread?: Ref<ActivityMessage>): void {
const data: ChannelMetadata = { _id, _class, thread }
localStorage.setItem(channelStorageKey, JSON.stringify(data))
openedChannelStore.set(data)
}
export const chatSpecials: SpecialNavModel[] = [
{

View File

@ -16,7 +16,7 @@ function encodeChannelURI (_id: Ref<Doc>, _class: Ref<Class<Doc>>): string {
return [_id, _class].join('|')
}
export function openChannel (_id: Ref<Doc>, _class: Ref<Class<Doc>>): void {
export function openChannel (_id: Ref<Doc>, _class: Ref<Class<Doc>>, thread?: Ref<ActivityMessage>): void {
const loc = getCurrentLocation()
const id = encodeChannelURI(_id, _class)
@ -26,9 +26,15 @@ export function openChannel (_id: Ref<Doc>, _class: Ref<Class<Doc>>): void {
}
loc.path[3] = id
loc.path[4] = ''
loc.query = { ...loc.query, message: null }
if (thread !== undefined) {
loc.path[4] = thread
loc.path.length = 5
} else {
loc.path[4] = ''
loc.path.length = 4
}
navigate(loc)
}

View File

@ -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<Employee>)
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<PersonAcco
export async function getDmPersons (client: Client, space: Space): Promise<Person[]> {
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)
}
}