Add confirmation modal for archive all and add read all option (#4880)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2024-03-05 17:02:52 +04:00 committed by GitHub
parent 2732756b76
commit e0fb65ab47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 99 additions and 23 deletions

View File

@ -60,7 +60,7 @@
id={mainButtonId} id={mainButtonId}
> >
<div class="flex w-full" slot="content"> <div class="flex w-full" slot="content">
<div class="flex-row-center w-full flex-between"> <div class="flex-row-center w-full flex-between relative">
{#if label} {#if label}
<Label {label} /> <Label {label} />
<slot name="content" /> <slot name="content" />
@ -81,10 +81,11 @@
<style lang="scss"> <style lang="scss">
.vertical-divider { .vertical-divider {
position: absolute;
background-color: var(--theme-content-color); background-color: var(--theme-content-color);
min-width: 1px; min-width: 1px;
opacity: 0.25; opacity: 0.25;
margin-right: -0.75rem; right: -0.75rem;
&.primary, &.primary,
&.secondary, &.secondary,

View File

@ -36,6 +36,9 @@
"Message": "Message", "Message": "Message",
"FlatList": "Flat list", "FlatList": "Flat list",
"GroupedList": "Grouped list", "GroupedList": "Grouped list",
"ArchiveAll": "Archive all" "ArchiveAll": "Archive all",
"ReadAll": "Read all",
"ArchiveAllConfirmationTitle": "Archive all notifications?",
"ArchiveAllConfirmationMessage": "Are you sure you want to archive all notifications? This operation cannot be undone."
} }
} }

View File

@ -36,6 +36,9 @@
"Message": "Сообщение", "Message": "Сообщение",
"FlatList": "Flat list", "FlatList": "Flat list",
"GroupedList": "Grouped list", "GroupedList": "Grouped list",
"ArchiveAll": "Архивировать все" "ArchiveAll": "Архивировать все",
"ReadAll": "Прочитать все",
"ArchiveAllConfirmationTitle": "Архивировать все уведомления?",
"ArchiveAllConfirmationMessage": "Вы уверены, что хотите заархивировать все уведомления? Эту операцию невозможно отменить."
} }
} }

View File

@ -18,7 +18,7 @@
DisplayInboxNotification, DisplayInboxNotification,
DocNotifyContext DocNotifyContext
} from '@hcengineering/notification' } from '@hcengineering/notification'
import { ActionContext, createQuery, getClient } from '@hcengineering/presentation' import { ActionContext, createQuery, getClient, MessageBox } from '@hcengineering/presentation'
import view, { Viewlet } from '@hcengineering/view' import view, { Viewlet } from '@hcengineering/view'
import { import {
AnyComponent, AnyComponent,
@ -32,7 +32,10 @@
TabItem, TabItem,
TabList, TabList,
Location, Location,
ModernButton IconDropdown,
ButtonWithDropdown,
IconCheckAll,
showPopup
} from '@hcengineering/ui' } from '@hcengineering/ui'
import chunter, { ThreadMessage } from '@hcengineering/chunter' import chunter, { ThreadMessage } from '@hcengineering/chunter'
import { Ref, WithLookup } from '@hcengineering/core' import { Ref, WithLookup } from '@hcengineering/core'
@ -92,11 +95,11 @@
let viewlet: WithLookup<Viewlet> | undefined let viewlet: WithLookup<Viewlet> | undefined
let loading = true let loading = true
client.findAll(notification.class.ActivityNotificationViewlet, {}).then((res) => { void client.findAll(notification.class.ActivityNotificationViewlet, {}).then((res) => {
viewlets = res viewlets = res
}) })
$: getDisplayInboxNotifications($notificationsByContextStore, filter).then((res) => { $: void getDisplayInboxNotifications($notificationsByContextStore, filter).then((res) => {
displayNotifications = res displayNotifications = res
}) })
$: displayContextsIds = new Set(displayNotifications.map(({ docNotifyContext }) => docNotifyContext)) $: displayContextsIds = new Set(displayNotifications.map(({ docNotifyContext }) => docNotifyContext))
@ -104,7 +107,7 @@
$: filteredNotifications = filterNotifications(selectedTabId, displayNotifications, $notifyContextsStore) $: filteredNotifications = filterNotifications(selectedTabId, displayNotifications, $notifyContextsStore)
locationStore.subscribe((newLocation) => { locationStore.subscribe((newLocation) => {
syncLocation(newLocation) void syncLocation(newLocation)
}) })
inboxClient.activityInboxNotifications.subscribe((notifications) => { inboxClient.activityInboxNotifications.subscribe((notifications) => {
@ -121,7 +124,7 @@
} }
) )
async function syncLocation (newLocation: Location) { async function syncLocation (newLocation: Location): Promise<void> {
const loc = await resolveLocation(newLocation) const loc = await resolveLocation(newLocation)
selectedContextId = loc?.loc.path[3] as Ref<DocNotifyContext> | undefined selectedContextId = loc?.loc.path[3] as Ref<DocNotifyContext> | undefined
@ -165,13 +168,13 @@
) )
} }
function selectTab (event: CustomEvent) { function selectTab (event: CustomEvent): void {
if (event.detail !== undefined) { if (event.detail !== undefined) {
selectedTabId = event.detail.id selectedTabId = event.detail.id
} }
} }
async function selectContext (event?: CustomEvent) { async function selectContext (event?: CustomEvent): Promise<void> {
selectedContext = event?.detail?.context selectedContext = event?.detail?.context
selectedContextId = selectedContext?._id selectedContextId = selectedContext?._id
@ -202,7 +205,7 @@
} }
} }
async function updateSelectedPanel (selectedContext?: DocNotifyContext) { async function updateSelectedPanel (selectedContext?: DocNotifyContext): Promise<void> {
if (selectedContext === undefined) { if (selectedContext === undefined) {
selectedComponent = undefined selectedComponent = undefined
return return
@ -236,7 +239,7 @@
selectedTabId: string, selectedTabId: string,
displayNotifications: DisplayInboxNotification[], displayNotifications: DisplayInboxNotification[],
notifyContexts: DocNotifyContext[] notifyContexts: DocNotifyContext[]
) { ): DisplayInboxNotification[] {
if (selectedTabId === allTab.id) { if (selectedTabId === allTab.id) {
return displayNotifications return displayNotifications
} }
@ -258,7 +261,35 @@
}) })
function archiveAll (): void { function archiveAll (): void {
void inboxClient.deleteAllNotifications() showPopup(
MessageBox,
{
label: notification.string.ArchiveAllConfirmationTitle,
message: notification.string.ArchiveAllConfirmationMessage
},
'top',
(result?: boolean) => {
if (result === true) {
void inboxClient.deleteAllNotifications()
}
}
)
}
function readAll (): void {
void inboxClient.readAllNotifications()
}
async function dropdownItemSelected (id: 'archive' | 'read'): Promise<void> {
if (id == null) return
if (id === 'archive') {
archiveAll()
}
if (id === 'read') {
readAll()
}
} }
</script> </script>
@ -288,12 +319,29 @@
/> />
</div> </div>
<div class="flex flex-gap-2"> <div class="flex flex-gap-2">
<ModernButton {#if displayNotifications.length > 0}
label={notification.string.ArchiveAll} <ButtonWithDropdown
icon={view.icon.Archive} justify="left"
size="small" kind="regular"
on:click={archiveAll} label={notification.string.ReadAll}
/> icon={IconCheckAll}
on:click={readAll}
dropdownItems={[
{
id: 'read',
icon: IconCheckAll,
label: notification.string.ReadAll
},
{
id: 'archive',
icon: view.icon.Archive,
label: notification.string.ArchiveAll
}
]}
dropdownIcon={IconDropdown}
on:dropdown-selected={(ev) => dropdownItemSelected(ev.detail)}
/>
{/if}
<Filter bind:filter /> <Filter bind:filter />
</div> </div>
</div> </div>

View File

@ -17,7 +17,7 @@
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { Component } from '@hcengineering/ui' import { Component } from '@hcengineering/ui'
import { Class, Doc, Ref } from '@hcengineering/core' import { Class, Doc, Ref } from '@hcengineering/core'
import { ActivityNotificationViewlet, DisplayInboxNotification, DocNotifyContext } from '@hcengineering/notification' import { ActivityNotificationViewlet, DisplayInboxNotification } from '@hcengineering/notification'
export let value: DisplayInboxNotification export let value: DisplayInboxNotification
export let embedded = false export let embedded = false

View File

@ -266,4 +266,21 @@ export class InboxNotificationsClientImpl implements InboxNotificationsClient {
await doneOp() await doneOp()
} }
} }
async readAllNotifications (): Promise<void> {
const doneOp = await getClient().measure('readAllNotifications')
const ops = getClient().apply(generateId())
try {
const inboxNotifications = get(this.inboxNotifications) ?? []
for (const notification of inboxNotifications) {
if (!notification.isViewed) {
await ops.update(notification, { isViewed: true })
}
}
} finally {
await ops.commit()
await doneOp()
}
}
} }

View File

@ -283,6 +283,7 @@ export interface InboxNotificationsClient {
unreadNotifications: (client: TxOperations, ids: Array<Ref<InboxNotification>>) => Promise<void> unreadNotifications: (client: TxOperations, ids: Array<Ref<InboxNotification>>) => Promise<void>
deleteNotifications: (client: TxOperations, ids: Array<Ref<InboxNotification>>) => Promise<void> deleteNotifications: (client: TxOperations, ids: Array<Ref<InboxNotification>>) => Promise<void>
deleteAllNotifications: () => Promise<void> deleteAllNotifications: () => Promise<void>
readAllNotifications: () => Promise<void>
} }
/** /**
@ -390,7 +391,10 @@ const notification = plugin(notificationId, {
FlatList: '' as IntlString, FlatList: '' as IntlString,
GroupedList: '' as IntlString, GroupedList: '' as IntlString,
All: '' as IntlString, All: '' as IntlString,
ArchiveAll: '' as IntlString ArchiveAll: '' as IntlString,
ReadAll: '' as IntlString,
ArchiveAllConfirmationTitle: '' as IntlString,
ArchiveAllConfirmationMessage: '' as IntlString
}, },
function: { function: {
GetInboxNotificationsClient: '' as Resource<InboxNotificationsClientFactory>, GetInboxNotificationsClient: '' as Resource<InboxNotificationsClientFactory>,