mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
Add keyboard support for inbox and simplify code (#4380)
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
parent
cf8ff1be31
commit
ed634ccabf
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { ActionIcon, CheckBox, Component, IconMoreH, Label, showPopup } from '@hcengineering/ui'
|
||||
import { ActionIcon, Component, IconMoreH, Label, showPopup } from '@hcengineering/ui'
|
||||
import notification, {
|
||||
ActivityNotificationViewlet,
|
||||
DisplayInboxNotification,
|
||||
@ -71,13 +71,13 @@
|
||||
}}
|
||||
>
|
||||
<div class="header">
|
||||
<CheckBox
|
||||
circle
|
||||
kind="primary"
|
||||
on:value={(event) => {
|
||||
dispatch('check', event.detail)
|
||||
}}
|
||||
/>
|
||||
<!-- <CheckBox-->
|
||||
<!-- circle-->
|
||||
<!-- kind="primary"-->
|
||||
<!-- on:value={(event) => {-->
|
||||
<!-- dispatch('check', event.detail)-->
|
||||
<!-- }}-->
|
||||
<!-- />-->
|
||||
<NotifyContextIcon {value} />
|
||||
|
||||
{#if presenterMixin?.labelPresenter}
|
||||
@ -135,10 +135,6 @@
|
||||
font-weight: 500;
|
||||
max-width: 20.5rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--highlight-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.labels {
|
||||
|
@ -32,7 +32,8 @@
|
||||
Scroller,
|
||||
Separator,
|
||||
TabItem,
|
||||
TabList
|
||||
TabList,
|
||||
Location
|
||||
} from '@hcengineering/ui'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import { Ref, WithLookup } from '@hcengineering/core'
|
||||
@ -41,7 +42,7 @@
|
||||
|
||||
import { InboxNotificationsClientImpl } from '../../inboxNotificationsClient'
|
||||
import Filter from '../Filter.svelte'
|
||||
import { getDisplayInboxNotifications } from '../../utils'
|
||||
import { getDisplayInboxNotifications, resolveLocation } from '../../utils'
|
||||
import { InboxNotificationsFilter } from '../../types'
|
||||
|
||||
export let visibleNav: boolean = true
|
||||
@ -89,17 +90,21 @@
|
||||
viewlets = res
|
||||
})
|
||||
|
||||
$: getDisplayInboxNotifications($notificationsByContextStore, filter).then((res) => {
|
||||
displayNotifications = res
|
||||
})
|
||||
$: displayNotifications = getDisplayInboxNotifications($notificationsByContextStore, filter)
|
||||
|
||||
locationStore.subscribe((newLocation) => {
|
||||
selectedContextId = newLocation.fragment as Ref<DocNotifyContext> | undefined
|
||||
syncLocation(newLocation)
|
||||
})
|
||||
|
||||
async function syncLocation (newLocation: Location) {
|
||||
const loc = await resolveLocation(newLocation)
|
||||
|
||||
selectedContextId = loc?.loc.fragment as Ref<DocNotifyContext> | undefined
|
||||
|
||||
if (selectedContextId !== selectedContext?._id) {
|
||||
selectedContext = undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$: selectedContext = selectedContextId
|
||||
? selectedContext ?? $notifyContextsStore.find(({ _id }) => _id === selectedContextId)
|
||||
@ -242,7 +247,8 @@
|
||||
props={{
|
||||
notifications: filteredNotifications,
|
||||
checkedContexts,
|
||||
viewlets
|
||||
viewlets,
|
||||
selectedContext
|
||||
}}
|
||||
on:click={selectContext}
|
||||
/>
|
||||
|
@ -13,10 +13,9 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Scroller } from '@hcengineering/ui'
|
||||
import { ActivityNotificationViewlet, DisplayInboxNotification } from '@hcengineering/notification'
|
||||
import { ListView } from '@hcengineering/ui'
|
||||
import { ActivityNotificationViewlet, DisplayInboxNotification, DocNotifyContext } from '@hcengineering/notification'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { flip } from 'svelte/animate'
|
||||
|
||||
import InboxNotificationPresenter from './InboxNotificationPresenter.svelte'
|
||||
import { InboxNotificationsClientImpl } from '../../inboxNotificationsClient'
|
||||
@ -29,44 +28,94 @@
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const notifyContextsStore = inboxClient.docNotifyContexts
|
||||
|
||||
async function handleCheck (notification: DisplayInboxNotification, isChecked: boolean) {
|
||||
if (!isChecked) {
|
||||
return
|
||||
}
|
||||
let list: ListView
|
||||
let listSelection = 0
|
||||
let element: HTMLDivElement | undefined
|
||||
|
||||
await deleteInboxNotification(notification)
|
||||
function onKeydown (key: KeyboardEvent): void {
|
||||
if (key.code === 'ArrowUp') {
|
||||
key.stopPropagation()
|
||||
key.preventDefault()
|
||||
list.select(listSelection - 1)
|
||||
}
|
||||
if (key.code === 'ArrowDown') {
|
||||
key.stopPropagation()
|
||||
key.preventDefault()
|
||||
list.select(listSelection + 1)
|
||||
}
|
||||
if (key.code === 'Backspace') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
|
||||
const notification = notifications[listSelection]
|
||||
|
||||
deleteInboxNotification(notification)
|
||||
}
|
||||
if (key.code === 'Enter') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
const notification = notifications[listSelection]
|
||||
const context = $notifyContextsStore.find(({ _id }) => _id === notification.docNotifyContext)
|
||||
dispatch('click', {
|
||||
context,
|
||||
notification
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
$: if (element) {
|
||||
element.focus()
|
||||
}
|
||||
|
||||
// async function handleCheck(notification: DisplayInboxNotification, isChecked: boolean) {
|
||||
// if (!isChecked) {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// await deleteInboxNotification(notification)
|
||||
// }
|
||||
</script>
|
||||
|
||||
<Scroller>
|
||||
{#each notifications as notification (notification._id)}
|
||||
<div animate:flip={{ duration: 500 }}>
|
||||
<div class="notification gap-2 ml-2">
|
||||
<!-- <div class="mt-6">-->
|
||||
<!-- <CheckBox-->
|
||||
<!-- circle-->
|
||||
<!-- kind="primary"-->
|
||||
<!-- on:value={(event) => {-->
|
||||
<!-- handleCheck(notification, event.detail)-->
|
||||
<!-- }}-->
|
||||
<!-- />-->
|
||||
<!-- </div>-->
|
||||
<InboxNotificationPresenter
|
||||
value={notification}
|
||||
{viewlets}
|
||||
onClick={() => {
|
||||
dispatch('click', {
|
||||
context: $notifyContextsStore.find(({ _id }) => _id === notification.docNotifyContext),
|
||||
notification
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</Scroller>
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="root" bind:this={element} tabindex="0" on:keydown={onKeydown}>
|
||||
<ListView bind:this={list} bind:selection={listSelection} count={notifications.length}>
|
||||
<svelte:fragment slot="item" let:item={itemIndex}>
|
||||
{@const notification = notifications[itemIndex]}
|
||||
{#key notification._id}
|
||||
<div class="notification gap-2 ml-2">
|
||||
<!-- <div class="mt-6">-->
|
||||
<!-- <CheckBox-->
|
||||
<!-- circle-->
|
||||
<!-- kind="primary"-->
|
||||
<!-- on:value={(event) => {-->
|
||||
<!-- handleCheck(notification, event.detail)-->
|
||||
<!-- }}-->
|
||||
<!-- />-->
|
||||
<!-- </div>-->
|
||||
<InboxNotificationPresenter
|
||||
value={notification}
|
||||
{viewlets}
|
||||
onClick={() => {
|
||||
dispatch('click', {
|
||||
context: $notifyContextsStore.find(({ _id }) => _id === notification.docNotifyContext),
|
||||
notification
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/key}
|
||||
</svelte:fragment>
|
||||
</ListView>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
display: flex;
|
||||
}
|
||||
|
@ -14,8 +14,9 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { ActivityNotificationViewlet, DisplayInboxNotification, DocNotifyContext } from '@hcengineering/notification'
|
||||
import { groupByArray, Ref } from '@hcengineering/core'
|
||||
import { flip } from 'svelte/animate'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { ListView } from '@hcengineering/ui'
|
||||
|
||||
import { InboxNotificationsClientImpl } from '../../inboxNotificationsClient'
|
||||
import DocNotifyContextCard from '../DocNotifyContextCard.svelte'
|
||||
@ -24,12 +25,33 @@
|
||||
export let notifications: DisplayInboxNotification[] = []
|
||||
export let viewlets: ActivityNotificationViewlet[] = []
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const notifyContextsStore = inboxClient.docNotifyContexts
|
||||
|
||||
let displayNotificationsByContext = new Map<Ref<DocNotifyContext>, DisplayInboxNotification[]>()
|
||||
let list: ListView
|
||||
let listSelection = 0
|
||||
let element: HTMLDivElement | undefined
|
||||
|
||||
$: displayNotificationsByContext = groupByArray(notifications, ({ docNotifyContext }) => docNotifyContext)
|
||||
let displayData: [Ref<DocNotifyContext>, DisplayInboxNotification[]][] = []
|
||||
|
||||
$: updateDisplayData(notifications)
|
||||
|
||||
function updateDisplayData (notifications: DisplayInboxNotification[]) {
|
||||
const result: [Ref<DocNotifyContext>, DisplayInboxNotification[]][] = []
|
||||
|
||||
notifications.forEach((item) => {
|
||||
const data = result.find(([_id]) => _id === item.docNotifyContext)
|
||||
|
||||
if (!data) {
|
||||
result.push([item.docNotifyContext, [item]])
|
||||
} else {
|
||||
data[1].push(item)
|
||||
}
|
||||
})
|
||||
|
||||
displayData = result
|
||||
}
|
||||
|
||||
async function handleCheck (context: DocNotifyContext, isChecked: boolean) {
|
||||
if (!isChecked) {
|
||||
@ -38,28 +60,73 @@
|
||||
|
||||
await deleteContextNotifications(context)
|
||||
}
|
||||
|
||||
function onKeydown (key: KeyboardEvent): void {
|
||||
if (key.code === 'ArrowUp') {
|
||||
key.stopPropagation()
|
||||
key.preventDefault()
|
||||
list.select(listSelection - 1)
|
||||
}
|
||||
if (key.code === 'ArrowDown') {
|
||||
key.stopPropagation()
|
||||
key.preventDefault()
|
||||
list.select(listSelection + 1)
|
||||
}
|
||||
if (key.code === 'Backspace') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
|
||||
const context = $notifyContextsStore.find(({ _id }) => _id === displayData[listSelection][0])
|
||||
|
||||
deleteContextNotifications(context)
|
||||
}
|
||||
if (key.code === 'Enter') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
const context = $notifyContextsStore.find(({ _id }) => _id === displayData[listSelection][0])
|
||||
dispatch('click', { context })
|
||||
}
|
||||
}
|
||||
|
||||
$: if (element) {
|
||||
element.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
{#each displayNotificationsByContext as [contextId, contextNotifications] (contextId)}
|
||||
<div animate:flip={{ duration: 500 }}>
|
||||
{#if contextNotifications.length}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="root" bind:this={element} tabindex="0" on:keydown={onKeydown}>
|
||||
<ListView bind:this={list} bind:selection={listSelection} count={displayData.length}>
|
||||
<svelte:fragment slot="item" let:item={itemIndex}>
|
||||
{@const contextId = displayData[itemIndex][0]}
|
||||
{@const contextNotifications = displayData[itemIndex][1]}
|
||||
{@const context = $notifyContextsStore.find(({ _id }) => _id === contextId)}
|
||||
|
||||
{#if context}
|
||||
<DocNotifyContextCard
|
||||
value={context}
|
||||
notifications={contextNotifications}
|
||||
{viewlets}
|
||||
on:click
|
||||
on:check={(event) => handleCheck(context, event.detail)}
|
||||
/>
|
||||
<div class="separator" />
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{#key contextId}
|
||||
{#if context}
|
||||
<DocNotifyContextCard
|
||||
value={context}
|
||||
notifications={contextNotifications}
|
||||
{viewlets}
|
||||
on:click={(event) => {
|
||||
dispatch('click', event.detail)
|
||||
listSelection = itemIndex
|
||||
}}
|
||||
on:check={(event) => handleCheck(context, event.detail)}
|
||||
/>
|
||||
<div class="separator" />
|
||||
{/if}
|
||||
{/key}
|
||||
</svelte:fragment>
|
||||
</ListView>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
import { type ActivityMessage } from '@hcengineering/activity'
|
||||
import activity, { type ActivityMessage } from '@hcengineering/activity'
|
||||
import { SortingOrder, getCurrentAccount, type Class, type Doc, type Ref, type WithLookup } from '@hcengineering/core'
|
||||
import notification, {
|
||||
type ActivityInboxNotification,
|
||||
@ -22,7 +22,7 @@ import notification, {
|
||||
type InboxNotificationsClient
|
||||
} from '@hcengineering/notification'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { derived, writable } from 'svelte/store'
|
||||
import { derived, get, writable } from 'svelte/store'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -33,7 +33,19 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
readonly docNotifyContexts = writable<DocNotifyContext[]>([])
|
||||
readonly docNotifyContextByDoc = writable<Map<Ref<Doc>, DocNotifyContext>>(new Map())
|
||||
|
||||
readonly inboxNotifications = writable<InboxNotification[]>([])
|
||||
readonly activityInboxNotifications = writable<Array<WithLookup<ActivityInboxNotification>>>([])
|
||||
readonly otherInboxNotifications = writable<InboxNotification[]>([])
|
||||
|
||||
readonly inboxNotifications = derived(
|
||||
[this.activityInboxNotifications, this.otherInboxNotifications],
|
||||
([activityNotifications, otherNotifications]) => {
|
||||
return otherNotifications
|
||||
.concat(activityNotifications)
|
||||
.sort((n1, n2) => (n2.createdOn ?? n2.modifiedOn) - (n1.createdOn ?? n1.modifiedOn))
|
||||
},
|
||||
[] as InboxNotification[]
|
||||
)
|
||||
|
||||
readonly inboxNotificationsByContext = derived(
|
||||
[this.docNotifyContexts, this.inboxNotifications],
|
||||
([notifyContexts, inboxNotifications]) => {
|
||||
@ -53,20 +65,11 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
}
|
||||
)
|
||||
|
||||
readonly activityInboxNotifications = derived(
|
||||
[this.inboxNotifications],
|
||||
([notifications]) =>
|
||||
notifications.filter(
|
||||
(n): n is ActivityInboxNotification => n._class === notification.class.ActivityInboxNotification
|
||||
),
|
||||
[] as ActivityInboxNotification[]
|
||||
)
|
||||
|
||||
private readonly docNotifyContextsQuery = createQuery(true)
|
||||
private readonly inboxNotificationsQuery = createQuery(true)
|
||||
private readonly otherInboxNotificationsQuery = createQuery(true)
|
||||
private readonly activityInboxNotificationsQuery = createQuery(true)
|
||||
|
||||
private _docNotifyContextByDoc = new Map<Ref<Doc>, DocNotifyContext>()
|
||||
private _inboxNotifications: Array<WithLookup<InboxNotification>> = []
|
||||
|
||||
private constructor () {
|
||||
this.docNotifyContextsQuery.query(
|
||||
@ -80,14 +83,14 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
this.docNotifyContextByDoc.set(this._docNotifyContextByDoc)
|
||||
}
|
||||
)
|
||||
this.inboxNotificationsQuery.query(
|
||||
this.otherInboxNotificationsQuery.query(
|
||||
notification.class.InboxNotification,
|
||||
{
|
||||
_class: { $nin: [notification.class.ActivityInboxNotification] },
|
||||
user: getCurrentAccount()._id
|
||||
},
|
||||
(result: InboxNotification[]) => {
|
||||
this.inboxNotifications.set(result)
|
||||
this._inboxNotifications = result
|
||||
this.otherInboxNotifications.set(result)
|
||||
},
|
||||
{
|
||||
sort: {
|
||||
@ -95,6 +98,24 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
this.activityInboxNotificationsQuery.query(
|
||||
notification.class.ActivityInboxNotification,
|
||||
{
|
||||
user: getCurrentAccount()._id
|
||||
},
|
||||
(result: ActivityInboxNotification[]) => {
|
||||
this.activityInboxNotifications.set(result)
|
||||
},
|
||||
{
|
||||
sort: {
|
||||
createdOn: SortingOrder.Descending
|
||||
},
|
||||
lookup: {
|
||||
attachedTo: activity.class.ActivityMessage
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
static createClient (): InboxNotificationsClientImpl {
|
||||
@ -117,7 +138,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
return
|
||||
}
|
||||
|
||||
const inboxNotifications = this._inboxNotifications.filter(
|
||||
const inboxNotifications = get(this.inboxNotifications).filter(
|
||||
(notification) => notification.docNotifyContext === docNotifyContext._id && !notification.isViewed
|
||||
)
|
||||
|
||||
@ -180,7 +201,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
async readMessages (ids: Array<Ref<ActivityMessage>>): Promise<void> {
|
||||
const client = getClient()
|
||||
|
||||
const notificationsToRead = this._inboxNotifications
|
||||
const notificationsToRead = get(this.inboxNotifications)
|
||||
.filter((n): n is ActivityInboxNotification => n._class === notification.class.ActivityInboxNotification)
|
||||
.filter(({ attachedTo, isViewed }) => ids.includes(attachedTo) && !isViewed)
|
||||
|
||||
@ -191,7 +212,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
|
||||
async readNotifications (ids: Array<Ref<InboxNotification>>): Promise<void> {
|
||||
const client = getClient()
|
||||
const notificationsToRead = this._inboxNotifications.filter(({ _id }) => ids.includes(_id))
|
||||
const notificationsToRead = get(this.inboxNotifications).filter(({ _id }) => ids.includes(_id))
|
||||
|
||||
await Promise.all(
|
||||
notificationsToRead.map(async (notification) => await client.update(notification, { isViewed: true }))
|
||||
@ -200,7 +221,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
|
||||
async unreadNotifications (ids: Array<Ref<InboxNotification>>): Promise<void> {
|
||||
const client = getClient()
|
||||
const notificationsToUnread = this._inboxNotifications.filter(({ _id }) => ids.includes(_id))
|
||||
const notificationsToUnread = get(this.inboxNotifications).filter(({ _id }) => ids.includes(_id))
|
||||
|
||||
await Promise.all(
|
||||
notificationsToUnread.map(async (notification) => await client.update(notification, { isViewed: false }))
|
||||
@ -209,7 +230,7 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
|
||||
|
||||
async deleteNotifications (ids: Array<Ref<InboxNotification>>): Promise<void> {
|
||||
const client = getClient()
|
||||
const inboxNotifications = this._inboxNotifications.filter(({ _id }) => ids.includes(_id))
|
||||
const inboxNotifications = get(this.inboxNotifications).filter(({ _id }) => ids.includes(_id))
|
||||
await Promise.all(inboxNotifications.map(async (notification) => await client.remove(notification)))
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ import {
|
||||
canUnReadNotifyContext,
|
||||
readNotifyContext,
|
||||
unReadNotifyContext,
|
||||
deleteContextNotifications
|
||||
deleteContextNotifications,
|
||||
hasInboxNotifications
|
||||
} from './utils'
|
||||
|
||||
import { InboxNotificationsClientImpl } from './inboxNotificationsClient'
|
||||
@ -85,7 +86,8 @@ export default async (): Promise<Resources> => ({
|
||||
IsDocNotifyContextTracked: isDocNotifyContextVisible,
|
||||
HasHiddenDocNotifyContext: hasHiddenDocNotifyContext,
|
||||
CanReadNotifyContext: canReadNotifyContext,
|
||||
CanUnReadNotifyContext: canUnReadNotifyContext
|
||||
CanUnReadNotifyContext: canUnReadNotifyContext,
|
||||
HasInboxNotifications: hasInboxNotifications
|
||||
},
|
||||
actionImpl: {
|
||||
Unsubscribe: unsubscribe,
|
||||
|
@ -21,7 +21,8 @@ import {
|
||||
getCurrentAccount,
|
||||
type Ref,
|
||||
SortingOrder,
|
||||
type TxOperations
|
||||
type TxOperations,
|
||||
type WithLookup
|
||||
} from '@hcengineering/core'
|
||||
import notification, {
|
||||
type ActivityInboxNotification,
|
||||
@ -203,7 +204,11 @@ export async function unReadNotifyContext (doc: DocNotifyContext): Promise<void>
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function deleteContextNotifications (doc: DocNotifyContext): Promise<void> {
|
||||
export async function deleteContextNotifications (doc?: DocNotifyContext): Promise<void> {
|
||||
if (doc === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const client = getClient()
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const inboxNotifications = get(inboxClient.inboxNotificationsByContext).get(doc._id) ?? []
|
||||
@ -324,9 +329,11 @@ async function generateLocation (
|
||||
const workspace = loc.path[1] ?? ''
|
||||
const messageId = loc.query?.message as Ref<ActivityMessage> | undefined
|
||||
|
||||
const context = await client.findOne(notification.class.DocNotifyContext, { _id: contextId })
|
||||
const contextNotification = await client.findOne(notification.class.InboxNotification, {
|
||||
docNotifyContext: contextId
|
||||
})
|
||||
|
||||
if (context === undefined) {
|
||||
if (contextNotification === undefined) {
|
||||
return {
|
||||
loc: {
|
||||
path: [loc.path[0], loc.path[1], inboxId],
|
||||
@ -355,12 +362,11 @@ async function generateLocation (
|
||||
}
|
||||
}
|
||||
|
||||
export async function getDisplayInboxNotifications (
|
||||
export function getDisplayInboxNotifications (
|
||||
notificationsByContext: Map<Ref<DocNotifyContext>, InboxNotification[]>,
|
||||
filter: InboxNotificationsFilter,
|
||||
filter: InboxNotificationsFilter = 'all',
|
||||
objectClass?: Ref<Class<Doc>>
|
||||
): Promise<DisplayInboxNotification[]> {
|
||||
const client = getClient()
|
||||
): DisplayInboxNotification[] {
|
||||
const filteredNotifications = Array.from(notificationsByContext.values())
|
||||
.flat()
|
||||
.filter(({ isViewed }) => {
|
||||
@ -377,20 +383,14 @@ export async function getDisplayInboxNotifications (
|
||||
})
|
||||
|
||||
const activityNotifications = filteredNotifications.filter(
|
||||
(n): n is ActivityInboxNotification => n._class === notification.class.ActivityInboxNotification
|
||||
(n): n is WithLookup<ActivityInboxNotification> => n._class === notification.class.ActivityInboxNotification
|
||||
)
|
||||
const displayNotifications: DisplayInboxNotification[] = filteredNotifications.filter(
|
||||
({ _class }) => _class !== notification.class.ActivityInboxNotification
|
||||
)
|
||||
|
||||
const messages: Array<ActivityMessage | undefined> = await Promise.all(
|
||||
activityNotifications.map(
|
||||
async (activityNotification) =>
|
||||
await client.findOne(activity.class.ActivityMessage, { _id: activityNotification.attachedTo })
|
||||
)
|
||||
)
|
||||
|
||||
const filteredMessages = messages
|
||||
const messages: ActivityMessage[] = activityNotifications
|
||||
.map((activityNotification) => activityNotification.$lookup?.attachedTo)
|
||||
.filter((message): message is ActivityMessage => {
|
||||
if (message === undefined) {
|
||||
return false
|
||||
@ -406,7 +406,7 @@ export async function getDisplayInboxNotifications (
|
||||
})
|
||||
.sort(activityMessagesComparator)
|
||||
|
||||
const combinedMessages = combineActivityMessages(filteredMessages, SortingOrder.Descending)
|
||||
const combinedMessages = combineActivityMessages(messages, SortingOrder.Descending)
|
||||
|
||||
for (const message of combinedMessages) {
|
||||
if (message._class === activity.class.DocUpdateMessage) {
|
||||
@ -442,3 +442,11 @@ export async function getDisplayInboxNotifications (
|
||||
|
||||
return displayNotifications
|
||||
}
|
||||
|
||||
export async function hasInboxNotifications (
|
||||
notificationsByContext: Map<Ref<DocNotifyContext>, InboxNotification[]>
|
||||
): Promise<boolean> {
|
||||
const displayNotifications = getDisplayInboxNotifications(notificationsByContext)
|
||||
|
||||
return displayNotifications.some(({ isViewed }) => !isViewed)
|
||||
}
|
||||
|
@ -272,8 +272,8 @@ export interface DocNotifyContext extends Doc {
|
||||
export interface InboxNotificationsClient {
|
||||
docNotifyContextByDoc: Writable<Map<Ref<Doc>, DocNotifyContext>>
|
||||
docNotifyContexts: Writable<DocNotifyContext[]>
|
||||
inboxNotifications: Writable<InboxNotification[]>
|
||||
activityInboxNotifications: Readable<ActivityInboxNotification[]>
|
||||
inboxNotifications: Readable<InboxNotification[]>
|
||||
activityInboxNotifications: Writable<ActivityInboxNotification[]>
|
||||
inboxNotificationsByContext: Readable<Map<Ref<DocNotifyContext>, InboxNotification[]>>
|
||||
readDoc: (_id: Ref<Doc>) => Promise<void>
|
||||
forceReadDoc: (_id: Ref<Doc>, _class: Ref<Class<Doc>>) => Promise<void>
|
||||
@ -393,7 +393,10 @@ const notification = plugin(notificationId, {
|
||||
GetInboxNotificationsClient: '' as Resource<InboxNotificationsClientFactory>,
|
||||
HasHiddenDocNotifyContext: '' as Resource<(doc: Doc[]) => Promise<boolean>>,
|
||||
IsDocNotifyContextHidden: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
|
||||
IsDocNotifyContextTracked: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>
|
||||
IsDocNotifyContextTracked: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
|
||||
HasInboxNotifications: '' as Resource<
|
||||
(notificationsByContext: Map<Ref<DocNotifyContext>, InboxNotification[]>) => Promise<boolean>
|
||||
>
|
||||
},
|
||||
resolver: {
|
||||
Location: '' as Resource<(loc: Location) => Promise<ResolvedLocation | undefined>>
|
||||
|
@ -16,7 +16,7 @@
|
||||
import contact, { Employee, PersonAccount } from '@hcengineering/contact'
|
||||
import core, { Class, Doc, getCurrentAccount, Ref, setCurrentAccount, Space } from '@hcengineering/core'
|
||||
import login from '@hcengineering/login'
|
||||
import notification, { inboxId } from '@hcengineering/notification'
|
||||
import notification, { DocNotifyContext, inboxId, InboxNotification } from '@hcengineering/notification'
|
||||
import { BrowserNotificatator, InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
import { broadcastEvent, getMetadata, getResource, IntlString } from '@hcengineering/platform'
|
||||
import { ActionContext, createQuery, getClient } from '@hcengineering/presentation'
|
||||
@ -162,17 +162,21 @@
|
||||
)
|
||||
|
||||
const workspaceId = $location.path[1]
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const inboxNotificationsByContextStore = inboxClient.inboxNotificationsByContext
|
||||
|
||||
let hasNotificationsFn: ((data: Map<Ref<DocNotifyContext>, InboxNotification[]>) => Promise<boolean>) | undefined =
|
||||
undefined
|
||||
let hasInboxNotifications = false
|
||||
let syncPromise: Promise<void> | undefined = undefined
|
||||
let locUpdate = 0
|
||||
|
||||
const notificationClient = InboxNotificationsClientImpl.getClient()
|
||||
getResource(notification.function.HasInboxNotifications).then((f) => {
|
||||
hasNotificationsFn = f
|
||||
})
|
||||
|
||||
notificationClient.inboxNotificationsByContext.subscribe((inboxNotificationsByContext) => {
|
||||
hasInboxNotifications = Array.from(inboxNotificationsByContext.entries()).some(([_, notifications]) =>
|
||||
notifications.some(({ isViewed }) => !isViewed)
|
||||
)
|
||||
$: hasNotificationsFn?.($inboxNotificationsByContextStore).then((res) => {
|
||||
hasInboxNotifications = res
|
||||
})
|
||||
|
||||
const doSyncLoc = async (loc: Location, iteration: number): Promise<void> => {
|
||||
|
Loading…
Reference in New Issue
Block a user