@acorex-platform/module-communication-management-client 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-platform-module-communication-management-client-acorex-platform-module-communication-management-client-09UhY2Rc.mjs +2375 -0
- package/fesm2022/acorex-platform-module-communication-management-client-acorex-platform-module-communication-management-client-09UhY2Rc.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-email-send.command-wuqLiY8s.mjs +69 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-email-send.command-wuqLiY8s.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-email-show-dialog.command-CP0zAEe4.mjs +285 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-email-show-dialog.command-CP0zAEe4.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-in-app-inbox-page.component-b7ZqkMTt.mjs +514 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-in-app-inbox-page.component-b7ZqkMTt.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-send.command-D7_MmGQe.mjs +85 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-send.command-D7_MmGQe.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-show-sent-message.command-D8125Jxi.mjs +111 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-show-sent-message.command-D8125Jxi.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-test-smtp.command-BySmN1Lz.mjs +155 -0
- package/fesm2022/acorex-platform-module-communication-management-client-communication-test-smtp.command-BySmN1Lz.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-communication-management-client-contracts.mjs +278 -0
- package/fesm2022/acorex-platform-module-communication-management-client-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-communication-management-client.mjs +2 -0
- package/fesm2022/acorex-platform-module-communication-management-client.mjs.map +1 -0
- package/package.json +28 -0
- package/types/acorex-platform-module-communication-management-client-contracts.d.ts +330 -0
- package/types/acorex-platform-module-communication-management-client.d.ts +360 -0
|
@@ -0,0 +1,2375 @@
|
|
|
1
|
+
import { AXPSessionService, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/auth';
|
|
2
|
+
import { AXPLocalEntityEngine, AXPLocalEntityRealtimeBridge, AXP_IN_APP_NOTIFICATION_SERVICE, AXPSearchCommandProvider, AXP_PROTECTED_ROUTE_GUARDS, AXP_MENU_PROVIDER, AXP_STATUS_PROVIDERS, AXP_SEARCH_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/common';
|
|
3
|
+
import * as i1$2 from '@acorex-platform/framework-client/core';
|
|
4
|
+
import { provideAppStartUpTask, AXP_APP_STARTUP_PRIORITY, AXPComponentSlotModule, AXP_MODULE_MANIFEST_PROVIDER } from '@acorex-platform/framework-client/core';
|
|
5
|
+
import { AXPUserAvatarComponent, AXPUserCardDirective, AXPStateMessageComponent, AXP_TASK_BADGE_PROVIDERS } from '@acorex-platform/framework-client/layout/components';
|
|
6
|
+
import { AXPRootLayoutComponent } from '@acorex-platform/framework-client/themes/default';
|
|
7
|
+
import { AXPCommandService, provideCommandSetups } from '@acorex-platform/framework-client/runtime';
|
|
8
|
+
import * as i0 from '@angular/core';
|
|
9
|
+
import { Injectable, InjectionToken, inject, DestroyRef, signal, computed, input, output, ChangeDetectionStrategy, Component, effect, viewChild, ViewEncapsulation, ChangeDetectorRef, NgModule } from '@angular/core';
|
|
10
|
+
import { Router, ROUTES } from '@angular/router';
|
|
11
|
+
import { AXP_COMMUNICATION_DELIVERY_STATUS_DEFINITION_KEY, AXP_COMMUNICATION_DELIVERY_STATUS_PENDING, AXP_COMMUNICATION_STATUS_DEFINITION_KEY, AXP_COMMUNICATION_STATUS_PENDING, RootConfig, resolveCommunicationMessage, AXPCollaborationPermissionKeys, AXMCommunicationManagementMenuKeys, AXMCommunicationManagementCommandKeys as AXMCommunicationManagementCommandKeys$1 } from '@acorex-platform/module-communication-management-client/contracts';
|
|
12
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
13
|
+
import { Subject, distinctUntilChanged, debounceTime, timer, switchMap, EMPTY } from 'rxjs';
|
|
14
|
+
import { AXP_QUERY_QUICK_SEARCH_FIELD, AXPStatusProvider, AXPWidgetsList, AXPWidgetsCatalog } from '@acorex-platform/framework-shared/core';
|
|
15
|
+
import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
|
|
16
|
+
import { AXPRealtimeDispatcherService, AXP_REALTIME_TOPIC_INBOX_REFRESH, AXPRealtimeConnectionService } from '@acorex-platform/framework-client/realtime';
|
|
17
|
+
import * as i4$1 from '@acorex/components/badge';
|
|
18
|
+
import { AXBadgeModule } from '@acorex/components/badge';
|
|
19
|
+
import * as i3 from '@acorex/components/decorators';
|
|
20
|
+
import { AXDecoratorModule } from '@acorex/components/decorators';
|
|
21
|
+
import * as i3$1 from '@acorex/core/format';
|
|
22
|
+
import { AXFormatModule } from '@acorex/core/format';
|
|
23
|
+
import * as i4 from '@acorex/core/translation';
|
|
24
|
+
import { AXTranslationModule } from '@acorex/core/translation';
|
|
25
|
+
import * as i1 from '@angular/common';
|
|
26
|
+
import { CommonModule, AsyncPipe } from '@angular/common';
|
|
27
|
+
import * as i1$1 from '@acorex/components/button';
|
|
28
|
+
import { AXButtonModule } from '@acorex/components/button';
|
|
29
|
+
import * as i2 from '@acorex/components/tabs';
|
|
30
|
+
import { AXTabsModule } from '@acorex/components/tabs';
|
|
31
|
+
import { AXToastService } from '@acorex/components/toast';
|
|
32
|
+
import * as i4$2 from '@acorex/components/popover';
|
|
33
|
+
import { AXPopoverComponent, AXPopoverModule } from '@acorex/components/popover';
|
|
34
|
+
import { AXP_COMMUNICATION_USER_NOTIFICATIONS_SETTINGS_GROUP, RootConfig as RootConfig$1, AXP_COMMUNICATION_DELIVERY_CHANNELS_SETTINGS_SECTION, AXP_COMMUNICATION_USER_NOTIFICATION_DEFAULTS, AXPCommunicationManagementSettingKeys, AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS, AXMCommunicationManagementCommandKeys } from '@acorex-platform/module-communication-management-contracts';
|
|
35
|
+
import { AXPCommonMenuKeys, AXPCommonPermissionGroupKeys } from '@acorex-platform/module-common-client/contracts';
|
|
36
|
+
import { AXP_PLATFORM_DEV_TOOLS_SETTINGS_GROUP, AXP_PLATFORM_DEV_TOOLS_COMMUNICATION_DEBUG_REDIRECT_SECTION } from '@acorex-platform/module-platform-dev-tools-client/contracts';
|
|
37
|
+
import { AXPValueWidgetComponent, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/layout/widget-core';
|
|
38
|
+
import { AXP_TEXT_TEMPLATE_CHANNEL_DEFINITION_PROVIDER } from '@acorex-platform/module-content-management-client';
|
|
39
|
+
import { cloneProperty, AXPWidgetGroupEnum } from '@acorex-platform/framework-shared/widget-core';
|
|
40
|
+
import { defineDashboardWidgetDimensions, AXP_WIDGETS_UTILITY_CATEGORY, layoutFromDimensions } from '@acorex-platform/module-dashboard-management-client';
|
|
41
|
+
import { AXP_STYLING_PROPERTY_GROUP, AXP_APPEARANCE_PROPERTY_GROUP, AXP_DATA_PATH_PROPERTY } from '@acorex-platform/framework-client/layout/widgets';
|
|
42
|
+
|
|
43
|
+
//#region ----- Constants -----
|
|
44
|
+
/** Local-entity engine key for the active in-app inbox hot subset. */
|
|
45
|
+
const AXP_IN_APP_INBOX_LOCAL_ENTITY_KEY = 'CommunicationManagement.InAppInbox';
|
|
46
|
+
/** Max active deliveries kept in the local hot subset. */
|
|
47
|
+
const AXP_IN_APP_INBOX_LOCAL_MAX_ITEMS = 100;
|
|
48
|
+
/** Legacy IndexedDB name from the inbox-only store (deleted on migrate). */
|
|
49
|
+
const AXP_IN_APP_INBOX_LEGACY_DB_NAME = 'ACoreXInAppInbox';
|
|
50
|
+
//#endregion
|
|
51
|
+
|
|
52
|
+
//#region ---- In-app inbox leading icon ----
|
|
53
|
+
const REPORT_GENERATION_DEFINITION_KEY = 'ReportManagement:ReportGeneration';
|
|
54
|
+
function isInAppInboxRealUserSender(sender) {
|
|
55
|
+
const senderId = sender?.id?.trim();
|
|
56
|
+
const senderName = sender?.fullName?.trim();
|
|
57
|
+
return Boolean(senderId && senderId !== 'system' && senderName && senderName !== senderId);
|
|
58
|
+
}
|
|
59
|
+
function resolveInAppInboxIconClass(item) {
|
|
60
|
+
if (item.iconClass?.trim()) {
|
|
61
|
+
return item.iconClass.trim();
|
|
62
|
+
}
|
|
63
|
+
if (isInAppInboxRealUserSender(item.sender)) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
if (item.definitionKey === REPORT_GENERATION_DEFINITION_KEY) {
|
|
67
|
+
return 'fa-light fa-file-chart-pie';
|
|
68
|
+
}
|
|
69
|
+
return resolveInAppInboxPriorityIconClass(item.priority);
|
|
70
|
+
}
|
|
71
|
+
function resolveInAppInboxPriorityIconClass(priority) {
|
|
72
|
+
switch (priority) {
|
|
73
|
+
case 'Danger':
|
|
74
|
+
return 'fa-light fa-circle-exclamation';
|
|
75
|
+
case 'Warning':
|
|
76
|
+
return 'fa-light fa-triangle-exclamation';
|
|
77
|
+
default:
|
|
78
|
+
return 'fa-light fa-bell';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
|
|
83
|
+
//#region ---- Shared in-app inbox helpers ----
|
|
84
|
+
function isInAppInboxUnread(readAt) {
|
|
85
|
+
return readAt == null;
|
|
86
|
+
}
|
|
87
|
+
function isInAppInboxUnseen(seenAt) {
|
|
88
|
+
return seenAt == null;
|
|
89
|
+
}
|
|
90
|
+
function getInAppInboxPriorityClass(priority) {
|
|
91
|
+
return priority ?? 'Notice';
|
|
92
|
+
}
|
|
93
|
+
function sortInAppInboxItems(items) {
|
|
94
|
+
return [...items].sort((left, right) => {
|
|
95
|
+
const pinDelta = Number(Boolean(right.isPinned)) - Number(Boolean(left.isPinned));
|
|
96
|
+
if (pinDelta !== 0) {
|
|
97
|
+
return pinDelta;
|
|
98
|
+
}
|
|
99
|
+
return right.createdAt.getTime() - left.createdAt.getTime();
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function normalizeInAppInboxItem(item) {
|
|
103
|
+
return {
|
|
104
|
+
id: String(item.id),
|
|
105
|
+
title: item.title ?? '',
|
|
106
|
+
body: item.body ?? '',
|
|
107
|
+
createdAt: item.createdAt ? new Date(item.createdAt) : new Date(),
|
|
108
|
+
seenAt: item.seenAt ? new Date(item.seenAt) : item.seenAt ?? null,
|
|
109
|
+
readAt: item.readAt ? new Date(item.readAt) : item.readAt ?? null,
|
|
110
|
+
sender: item.sender,
|
|
111
|
+
iconClass: item.iconClass ?? resolveInAppInboxIconClass(item),
|
|
112
|
+
showAvatar: item.showAvatar,
|
|
113
|
+
priority: item.priority ?? 'Notice',
|
|
114
|
+
isPinned: item.isPinned ?? false,
|
|
115
|
+
category: item.category,
|
|
116
|
+
definitionKey: item.definitionKey,
|
|
117
|
+
archivedAt: item.archivedAt ? new Date(item.archivedAt) : item.archivedAt ?? null,
|
|
118
|
+
actions: Array.isArray(item.actions) ? item.actions : undefined,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
|
|
123
|
+
//#region ----- Imports -----
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region ----- Local inbox filters -----
|
|
126
|
+
function isArchiveCategoryFilter(filters) {
|
|
127
|
+
return filters?.some((filter) => filter.field === 'category' && filter.value === 'Archive') ?? false;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Filters and sorts active inbox items in memory (search, unread, priority).
|
|
131
|
+
* Archive is never applied here — callers must use the API for archived rows.
|
|
132
|
+
*/
|
|
133
|
+
function filterInAppInboxItemsLocally(items, filters) {
|
|
134
|
+
const active = items.filter((item) => item.archivedAt == null);
|
|
135
|
+
if (!filters?.length) {
|
|
136
|
+
return sortInAppInboxItems(active);
|
|
137
|
+
}
|
|
138
|
+
const searchFilter = filters.find((filter) => filter.field === 'all' || filter.field === AXP_QUERY_QUICK_SEARCH_FIELD);
|
|
139
|
+
const searchText = searchFilter?.value != null ? String(searchFilter.value).trim().toLowerCase() : '';
|
|
140
|
+
const readFilter = filters.find((filter) => filter.field === 'readStatus');
|
|
141
|
+
const unreadOnly = readFilter?.value === 'unread';
|
|
142
|
+
const priorityFilter = filters.find((filter) => filter.field === 'priority');
|
|
143
|
+
const priority = priorityFilter?.value ? String(priorityFilter.value) : '';
|
|
144
|
+
const definitionFilter = filters.find((filter) => filter.field === 'type');
|
|
145
|
+
const definitionKey = definitionFilter?.value ? String(definitionFilter.value) : '';
|
|
146
|
+
const filtered = active.filter((item) => {
|
|
147
|
+
if (unreadOnly && !isInAppInboxUnread(item.readAt)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
if (priority && item.priority !== priority) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
if (definitionKey && item.definitionKey !== definitionKey) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
if (searchText) {
|
|
157
|
+
const haystack = `${item.title} ${item.body} ${item.sender?.fullName ?? ''}`.toLowerCase();
|
|
158
|
+
if (!haystack.includes(searchText)) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
});
|
|
164
|
+
return sortInAppInboxItems(filtered);
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
|
|
168
|
+
//#region ---- In-app inbox realtime events ----
|
|
169
|
+
class AXPInAppInboxRealtimeService {
|
|
170
|
+
constructor() {
|
|
171
|
+
this.changedSubject = new Subject();
|
|
172
|
+
this.changed$ = this.changedSubject.asObservable();
|
|
173
|
+
}
|
|
174
|
+
notifyChanged(event) {
|
|
175
|
+
this.changedSubject.next(event);
|
|
176
|
+
}
|
|
177
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxRealtimeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
178
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxRealtimeService, providedIn: 'root' }); }
|
|
179
|
+
}
|
|
180
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxRealtimeService, decorators: [{
|
|
181
|
+
type: Injectable,
|
|
182
|
+
args: [{
|
|
183
|
+
providedIn: 'root',
|
|
184
|
+
}]
|
|
185
|
+
}] });
|
|
186
|
+
|
|
187
|
+
//#region ---- In-app inbox data port ----
|
|
188
|
+
const AXP_IN_APP_INBOX_PORT = new InjectionToken('AXP_IN_APP_INBOX_PORT');
|
|
189
|
+
//#endregion
|
|
190
|
+
|
|
191
|
+
//#region ----- Imports -----
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region ----- Shared in-app inbox connector -----
|
|
194
|
+
/**
|
|
195
|
+
* Single source of truth for active in-app inbox UI.
|
|
196
|
+
* Active items live in the shared local-entity engine (max 100) and sync via realtime / reconnect.
|
|
197
|
+
* Archived views always load from the API.
|
|
198
|
+
*/
|
|
199
|
+
class AXPInAppInboxConnectorService {
|
|
200
|
+
constructor() {
|
|
201
|
+
this.port = inject(AXP_IN_APP_INBOX_PORT);
|
|
202
|
+
this.realtime = inject(AXPInAppInboxRealtimeService);
|
|
203
|
+
this.engine = inject(AXPLocalEntityEngine);
|
|
204
|
+
this.localBridge = inject(AXPLocalEntityRealtimeBridge);
|
|
205
|
+
this.sessionService = inject(AXPSessionService);
|
|
206
|
+
this.destroyRef = inject(DestroyRef);
|
|
207
|
+
this.entityKey = AXP_IN_APP_INBOX_LOCAL_ENTITY_KEY;
|
|
208
|
+
this.localItems = this.engine.itemsSignal(this.entityKey);
|
|
209
|
+
this.isLoading = signal(false, /* @ts-ignore */
|
|
210
|
+
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
211
|
+
this.pageLoading = signal(false, /* @ts-ignore */
|
|
212
|
+
...(ngDevMode ? [{ debugName: "pageLoading" }] : /* istanbul ignore next */ []));
|
|
213
|
+
this.error = signal(null, /* @ts-ignore */
|
|
214
|
+
...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
215
|
+
this.archivePageItems = signal([], /* @ts-ignore */
|
|
216
|
+
...(ngDevMode ? [{ debugName: "archivePageItems" }] : /* istanbul ignore next */ []));
|
|
217
|
+
this.archiveTotalCount = signal(0, /* @ts-ignore */
|
|
218
|
+
...(ngDevMode ? [{ debugName: "archiveTotalCount" }] : /* istanbul ignore next */ []));
|
|
219
|
+
this.pageQuery = signal(null, /* @ts-ignore */
|
|
220
|
+
...(ngDevMode ? [{ debugName: "pageQuery" }] : /* istanbul ignore next */ []));
|
|
221
|
+
this.pendingRealtimeRefresh = false;
|
|
222
|
+
this.bootstrapPromise = null;
|
|
223
|
+
this.syncInFlight = null;
|
|
224
|
+
this.boundUserKey = null;
|
|
225
|
+
this.legacyDbCleanupDone = false;
|
|
226
|
+
this.capabilities = this.port.capabilities;
|
|
227
|
+
this.loading = computed(() => this.isLoading(), /* @ts-ignore */
|
|
228
|
+
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
229
|
+
this.pageLoadingState = computed(() => this.pageLoading(), /* @ts-ignore */
|
|
230
|
+
...(ngDevMode ? [{ debugName: "pageLoadingState" }] : /* istanbul ignore next */ []));
|
|
231
|
+
this.errorMessage = computed(() => this.error(), /* @ts-ignore */
|
|
232
|
+
...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
|
|
233
|
+
this.inboxList = computed(() => this.readLocalItems(), /* @ts-ignore */
|
|
234
|
+
...(ngDevMode ? [{ debugName: "inboxList" }] : /* istanbul ignore next */ []));
|
|
235
|
+
this.total = computed(() => {
|
|
236
|
+
if (this.pageQuery()?.mode === 'archive') {
|
|
237
|
+
return this.archiveTotalCount();
|
|
238
|
+
}
|
|
239
|
+
return this.readLocalItems().length;
|
|
240
|
+
}, /* @ts-ignore */
|
|
241
|
+
...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
|
|
242
|
+
this.pagedInboxList = computed(() => {
|
|
243
|
+
const query = this.pageQuery();
|
|
244
|
+
if (!query) {
|
|
245
|
+
return [];
|
|
246
|
+
}
|
|
247
|
+
if (query.mode === 'archive') {
|
|
248
|
+
return this.archivePageItems();
|
|
249
|
+
}
|
|
250
|
+
const filtered = filterInAppInboxItemsLocally(this.readLocalItems(), query.filters);
|
|
251
|
+
return filtered.slice(query.skip, query.skip + query.take);
|
|
252
|
+
}, /* @ts-ignore */
|
|
253
|
+
...(ngDevMode ? [{ debugName: "pagedInboxList" }] : /* istanbul ignore next */ []));
|
|
254
|
+
this.pagedTotal = computed(() => {
|
|
255
|
+
const query = this.pageQuery();
|
|
256
|
+
if (!query) {
|
|
257
|
+
return 0;
|
|
258
|
+
}
|
|
259
|
+
if (query.mode === 'archive') {
|
|
260
|
+
return this.archiveTotalCount();
|
|
261
|
+
}
|
|
262
|
+
return filterInAppInboxItemsLocally(this.readLocalItems(), query.filters).length;
|
|
263
|
+
}, /* @ts-ignore */
|
|
264
|
+
...(ngDevMode ? [{ debugName: "pagedTotal" }] : /* istanbul ignore next */ []));
|
|
265
|
+
this.unreadCount = computed(() => this.readLocalItems().filter((item) => isInAppInboxUnread(item.readAt)).length, /* @ts-ignore */
|
|
266
|
+
...(ngDevMode ? [{ debugName: "unreadCount" }] : /* istanbul ignore next */ []));
|
|
267
|
+
this.engine.registerPolicy(this.entityKey, {
|
|
268
|
+
mode: 'local-first',
|
|
269
|
+
maxItems: AXP_IN_APP_INBOX_LOCAL_MAX_ITEMS,
|
|
270
|
+
sortField: 'createdAt',
|
|
271
|
+
role: 'entity',
|
|
272
|
+
});
|
|
273
|
+
this.localBridge.register(this.entityKey, {
|
|
274
|
+
fetchByIds: this.port.loadByIds ? (ids) => this.fetchActiveByIds(ids) : undefined,
|
|
275
|
+
fetchHot: () => this.fetchActiveHot(),
|
|
276
|
+
});
|
|
277
|
+
this.sessionService.isReadyForAppScopedApi$
|
|
278
|
+
.pipe(distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))
|
|
279
|
+
.subscribe((isReady) => {
|
|
280
|
+
if (isReady) {
|
|
281
|
+
void this.ensureReady();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
void this.clearInboxState();
|
|
285
|
+
});
|
|
286
|
+
this.realtime.changed$.pipe(debounceTime(100), takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
|
|
287
|
+
void this.handleRealtimeEvent(event);
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
/** Hydrate from IndexedDB then sync active inbox from the server (idempotent). */
|
|
291
|
+
ensureReady() {
|
|
292
|
+
if (!this.canLoadInbox()) {
|
|
293
|
+
return Promise.resolve();
|
|
294
|
+
}
|
|
295
|
+
if (!this.bootstrapPromise) {
|
|
296
|
+
this.bootstrapPromise = this.bootstrap();
|
|
297
|
+
}
|
|
298
|
+
return this.bootstrapPromise;
|
|
299
|
+
}
|
|
300
|
+
async refresh() {
|
|
301
|
+
if (!this.canLoadInbox()) {
|
|
302
|
+
return { items: [], total: 0 };
|
|
303
|
+
}
|
|
304
|
+
await this.ensureReady();
|
|
305
|
+
return this.syncActiveFromServer();
|
|
306
|
+
}
|
|
307
|
+
async loadPage(filtersOrSkip, skipOrTake, takeArg) {
|
|
308
|
+
const filters = Array.isArray(filtersOrSkip) ? filtersOrSkip : [];
|
|
309
|
+
const skip = Array.isArray(filtersOrSkip) ? (skipOrTake ?? 0) : filtersOrSkip;
|
|
310
|
+
const take = Array.isArray(filtersOrSkip) ? (takeArg ?? 10) : (skipOrTake ?? 10);
|
|
311
|
+
const mode = isArchiveCategoryFilter(filters) ? 'archive' : 'local';
|
|
312
|
+
this.pageQuery.set({ skip, take, filters, mode });
|
|
313
|
+
if (mode === 'archive') {
|
|
314
|
+
if (!this.canLoadInbox()) {
|
|
315
|
+
this.archivePageItems.set([]);
|
|
316
|
+
this.archiveTotalCount.set(0);
|
|
317
|
+
return { items: [], total: 0 };
|
|
318
|
+
}
|
|
319
|
+
return this.loadArchivePage(filters, skip, take);
|
|
320
|
+
}
|
|
321
|
+
if (this.canLoadInbox()) {
|
|
322
|
+
await this.ensureReady();
|
|
323
|
+
}
|
|
324
|
+
this.pageLoading.set(false);
|
|
325
|
+
return { items: this.pagedInboxList(), total: this.pagedTotal() };
|
|
326
|
+
}
|
|
327
|
+
async markUnseenAsSeen() {
|
|
328
|
+
if (!this.port.capabilities.seenTracking || !this.canLoadInbox()) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
await this.ensureReady();
|
|
332
|
+
const unseenIds = this.readLocalItems()
|
|
333
|
+
.filter((item) => isInAppInboxUnseen(item.seenAt))
|
|
334
|
+
.map((item) => item.id);
|
|
335
|
+
if (unseenIds.length === 0) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const now = new Date().toISOString();
|
|
339
|
+
await this.engine.patchMany(this.entityKey, unseenIds, (item) => item['seenAt'] ? item : { ...item, seenAt: now });
|
|
340
|
+
try {
|
|
341
|
+
await this.port.markSeen(unseenIds);
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to mark inbox as seen');
|
|
345
|
+
await this.syncActiveFromServer();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
async markAsRead(ids) {
|
|
349
|
+
if (ids.length === 0 || !this.port.capabilities.readTracking || !this.canLoadInbox()) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
await this.ensureReady();
|
|
353
|
+
const now = new Date().toISOString();
|
|
354
|
+
await this.engine.patchMany(this.entityKey, ids, (item) => ({
|
|
355
|
+
...item,
|
|
356
|
+
seenAt: item['seenAt'] ?? now,
|
|
357
|
+
readAt: item['readAt'] ?? now,
|
|
358
|
+
}));
|
|
359
|
+
try {
|
|
360
|
+
await this.port.markRead(ids);
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to mark inbox as read');
|
|
364
|
+
await this.localBridge.apply({ entityKey: this.entityKey, type: 'upsert', ids });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async markAllAsRead() {
|
|
368
|
+
if (!this.port.capabilities.readTracking || !this.canLoadInbox()) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
await this.ensureReady();
|
|
372
|
+
const now = new Date().toISOString();
|
|
373
|
+
await this.engine.patchAll(this.entityKey, (item) => {
|
|
374
|
+
const readAt = item['readAt'];
|
|
375
|
+
if (readAt != null) {
|
|
376
|
+
return item;
|
|
377
|
+
}
|
|
378
|
+
return { ...item, readAt: now, seenAt: item['seenAt'] ?? now };
|
|
379
|
+
});
|
|
380
|
+
try {
|
|
381
|
+
await this.port.markAllRead();
|
|
382
|
+
}
|
|
383
|
+
catch (err) {
|
|
384
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to mark all as read');
|
|
385
|
+
await this.syncActiveFromServer();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async togglePin(id) {
|
|
389
|
+
if (!this.port.capabilities.pinSupport || !this.port.togglePin || !this.canLoadInbox()) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
await this.ensureReady();
|
|
393
|
+
const current = this.readLocalItems().find((item) => item.id === id);
|
|
394
|
+
if (current) {
|
|
395
|
+
await this.engine.patchMany(this.entityKey, [id], (item) => ({
|
|
396
|
+
...item,
|
|
397
|
+
isPinned: !Boolean(item['isPinned']),
|
|
398
|
+
}));
|
|
399
|
+
}
|
|
400
|
+
try {
|
|
401
|
+
await this.port.togglePin(id);
|
|
402
|
+
await this.localBridge.apply({ entityKey: this.entityKey, type: 'upsert', ids: [id] });
|
|
403
|
+
}
|
|
404
|
+
catch (err) {
|
|
405
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to toggle pin');
|
|
406
|
+
await this.localBridge.apply({ entityKey: this.entityKey, type: 'upsert', ids: [id] });
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async archive(ids) {
|
|
410
|
+
if (!this.port.archive || ids.length === 0 || !this.canLoadInbox()) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
await this.ensureReady();
|
|
414
|
+
await this.engine.removeMany(this.entityKey, ids);
|
|
415
|
+
try {
|
|
416
|
+
await this.port.archive(ids);
|
|
417
|
+
}
|
|
418
|
+
catch (err) {
|
|
419
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to archive inbox items');
|
|
420
|
+
await this.syncActiveFromServer();
|
|
421
|
+
}
|
|
422
|
+
const query = this.pageQuery();
|
|
423
|
+
if (query?.mode === 'archive') {
|
|
424
|
+
await this.loadArchivePage(query.filters, query.skip, query.take);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async deleteOne(id) {
|
|
428
|
+
if (!this.port.deleteDeliveries || !this.canLoadInbox()) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
await this.ensureReady();
|
|
432
|
+
await this.engine.removeMany(this.entityKey, [id]);
|
|
433
|
+
try {
|
|
434
|
+
await this.port.deleteDeliveries([id]);
|
|
435
|
+
}
|
|
436
|
+
catch (err) {
|
|
437
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to delete inbox item');
|
|
438
|
+
await this.syncActiveFromServer();
|
|
439
|
+
}
|
|
440
|
+
const query = this.pageQuery();
|
|
441
|
+
if (query?.mode === 'archive') {
|
|
442
|
+
await this.loadArchivePage(query.filters, query.skip, query.take);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
//#region ----- Bootstrap & sync -----
|
|
446
|
+
async bootstrap() {
|
|
447
|
+
if (!this.canLoadInbox()) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
try {
|
|
451
|
+
this.deleteLegacyInboxDb();
|
|
452
|
+
this.boundUserKey = this.engine.resolveUserKey();
|
|
453
|
+
await this.engine.hydrate(this.entityKey);
|
|
454
|
+
if (!this.boundUserKey) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
await this.syncActiveFromServer();
|
|
458
|
+
}
|
|
459
|
+
catch (err) {
|
|
460
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to bootstrap inbox');
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
async syncActiveFromServer() {
|
|
464
|
+
if (!this.canLoadInbox()) {
|
|
465
|
+
return { items: [], total: 0 };
|
|
466
|
+
}
|
|
467
|
+
if (this.syncInFlight) {
|
|
468
|
+
return this.syncInFlight;
|
|
469
|
+
}
|
|
470
|
+
this.syncInFlight = this.syncActiveFromServerInternal();
|
|
471
|
+
try {
|
|
472
|
+
return await this.syncInFlight;
|
|
473
|
+
}
|
|
474
|
+
finally {
|
|
475
|
+
this.syncInFlight = null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
async syncActiveFromServerInternal() {
|
|
479
|
+
if (!this.canLoadInbox()) {
|
|
480
|
+
return { items: [], total: 0 };
|
|
481
|
+
}
|
|
482
|
+
try {
|
|
483
|
+
this.isLoading.set(true);
|
|
484
|
+
this.error.set(null);
|
|
485
|
+
const response = await this.fetchActiveHot();
|
|
486
|
+
const items = sortInAppInboxItems(response.items.map((item) => normalizeInAppInboxItem(item)));
|
|
487
|
+
await this.engine.replaceAll(this.entityKey, items.map((item) => this.toPayload(item)));
|
|
488
|
+
const local = this.readLocalItems();
|
|
489
|
+
return { items: local, total: local.length };
|
|
490
|
+
}
|
|
491
|
+
catch (err) {
|
|
492
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to load inbox');
|
|
493
|
+
const local = this.readLocalItems();
|
|
494
|
+
return { items: local, total: local.length };
|
|
495
|
+
}
|
|
496
|
+
finally {
|
|
497
|
+
this.isLoading.set(false);
|
|
498
|
+
if (this.pendingRealtimeRefresh) {
|
|
499
|
+
this.pendingRealtimeRefresh = false;
|
|
500
|
+
void this.syncActiveFromServer();
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
async fetchActiveHot() {
|
|
505
|
+
if (!this.canLoadInbox()) {
|
|
506
|
+
return { items: [], total: 0 };
|
|
507
|
+
}
|
|
508
|
+
const response = await this.port.loadInbox({
|
|
509
|
+
skip: 0,
|
|
510
|
+
take: AXP_IN_APP_INBOX_LOCAL_MAX_ITEMS,
|
|
511
|
+
excludeArchived: true,
|
|
512
|
+
});
|
|
513
|
+
return {
|
|
514
|
+
items: response.items.map((item) => this.toPayload(normalizeInAppInboxItem(item))),
|
|
515
|
+
total: response.total,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
async fetchActiveByIds(ids) {
|
|
519
|
+
if (!this.canLoadInbox() || !this.port.loadByIds) {
|
|
520
|
+
return [];
|
|
521
|
+
}
|
|
522
|
+
const result = await this.port.loadByIds(ids);
|
|
523
|
+
return result.items
|
|
524
|
+
.filter((item) => item.archivedAt == null)
|
|
525
|
+
.map((item) => this.toPayload(normalizeInAppInboxItem(item)));
|
|
526
|
+
}
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region ----- Page views -----
|
|
529
|
+
async loadArchivePage(filters, skip, take) {
|
|
530
|
+
if (!this.canLoadInbox()) {
|
|
531
|
+
this.archivePageItems.set([]);
|
|
532
|
+
this.archiveTotalCount.set(0);
|
|
533
|
+
return { items: [], total: 0 };
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
this.pageLoading.set(true);
|
|
537
|
+
this.error.set(null);
|
|
538
|
+
const result = await this.port.loadInbox({
|
|
539
|
+
skip,
|
|
540
|
+
take,
|
|
541
|
+
filters,
|
|
542
|
+
excludeArchived: false,
|
|
543
|
+
});
|
|
544
|
+
const items = sortInAppInboxItems(result.items.map((item) => normalizeInAppInboxItem(item)));
|
|
545
|
+
this.archivePageItems.set(items);
|
|
546
|
+
this.archiveTotalCount.set(result.total);
|
|
547
|
+
return { items, total: result.total };
|
|
548
|
+
}
|
|
549
|
+
catch (err) {
|
|
550
|
+
this.error.set(err instanceof Error ? err.message : 'Failed to load archived inbox');
|
|
551
|
+
this.archivePageItems.set([]);
|
|
552
|
+
this.archiveTotalCount.set(0);
|
|
553
|
+
return { items: [], total: 0 };
|
|
554
|
+
}
|
|
555
|
+
finally {
|
|
556
|
+
this.pageLoading.set(false);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
//#endregion
|
|
560
|
+
//#region ----- Realtime -----
|
|
561
|
+
async handleRealtimeEvent(event) {
|
|
562
|
+
if (!this.canLoadInbox()) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
await this.ensureReady();
|
|
566
|
+
if (event.type === 'seen' || event.type === 'read') {
|
|
567
|
+
// Local optimistic path already patched; ignore echo noise.
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
if ((event.type === 'deleted' || event.type === 'archived') && event.ids?.length) {
|
|
571
|
+
await this.localBridge.apply({
|
|
572
|
+
entityKey: this.entityKey,
|
|
573
|
+
type: 'remove',
|
|
574
|
+
ids: event.ids,
|
|
575
|
+
});
|
|
576
|
+
const query = this.pageQuery();
|
|
577
|
+
if (query?.mode === 'archive') {
|
|
578
|
+
await this.loadArchivePage(query.filters, query.skip, query.take);
|
|
579
|
+
}
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (this.isLoading()) {
|
|
583
|
+
this.pendingRealtimeRefresh = true;
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (event.ids?.length) {
|
|
587
|
+
await this.localBridge.apply({
|
|
588
|
+
entityKey: this.entityKey,
|
|
589
|
+
type: 'upsert',
|
|
590
|
+
ids: event.ids,
|
|
591
|
+
});
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
await this.localBridge.apply({ entityKey: this.entityKey, type: 'invalidate' });
|
|
595
|
+
}
|
|
596
|
+
//#endregion
|
|
597
|
+
//#region ----- Local helpers -----
|
|
598
|
+
canLoadInbox() {
|
|
599
|
+
return this.sessionService.isReadyForAppScopedApi;
|
|
600
|
+
}
|
|
601
|
+
async clearInboxState() {
|
|
602
|
+
this.bootstrapPromise = null;
|
|
603
|
+
this.syncInFlight = null;
|
|
604
|
+
this.boundUserKey = null;
|
|
605
|
+
this.pendingRealtimeRefresh = false;
|
|
606
|
+
this.pageQuery.set(null);
|
|
607
|
+
this.archivePageItems.set([]);
|
|
608
|
+
this.archiveTotalCount.set(0);
|
|
609
|
+
this.error.set(null);
|
|
610
|
+
this.isLoading.set(false);
|
|
611
|
+
this.pageLoading.set(false);
|
|
612
|
+
await this.engine.clear(this.entityKey);
|
|
613
|
+
}
|
|
614
|
+
readLocalItems() {
|
|
615
|
+
return sortInAppInboxItems(this.localItems().map((row) => normalizeInAppInboxItem(row)));
|
|
616
|
+
}
|
|
617
|
+
toPayload(item) {
|
|
618
|
+
return {
|
|
619
|
+
id: item.id,
|
|
620
|
+
title: item.title,
|
|
621
|
+
body: item.body,
|
|
622
|
+
createdAt: item.createdAt.toISOString(),
|
|
623
|
+
seenAt: item.seenAt ? item.seenAt.toISOString() : null,
|
|
624
|
+
readAt: item.readAt ? item.readAt.toISOString() : null,
|
|
625
|
+
sender: item.sender,
|
|
626
|
+
iconClass: item.iconClass,
|
|
627
|
+
showAvatar: item.showAvatar,
|
|
628
|
+
priority: item.priority ?? 'Notice',
|
|
629
|
+
isPinned: Boolean(item.isPinned),
|
|
630
|
+
category: item.category,
|
|
631
|
+
definitionKey: item.definitionKey,
|
|
632
|
+
archivedAt: item.archivedAt ? item.archivedAt.toISOString() : null,
|
|
633
|
+
actions: item.actions,
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
deleteLegacyInboxDb() {
|
|
637
|
+
if (this.legacyDbCleanupDone || typeof indexedDB === 'undefined') {
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
this.legacyDbCleanupDone = true;
|
|
641
|
+
try {
|
|
642
|
+
indexedDB.deleteDatabase(AXP_IN_APP_INBOX_LEGACY_DB_NAME);
|
|
643
|
+
}
|
|
644
|
+
catch {
|
|
645
|
+
// Best-effort cleanup of the pre-engine inbox DB.
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxConnectorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
649
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxConnectorService, providedIn: 'root' }); }
|
|
650
|
+
}
|
|
651
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxConnectorService, decorators: [{
|
|
652
|
+
type: Injectable,
|
|
653
|
+
args: [{
|
|
654
|
+
providedIn: 'root',
|
|
655
|
+
}]
|
|
656
|
+
}], ctorParameters: () => [] });
|
|
657
|
+
|
|
658
|
+
//#region ---- Communication in-app inbox badge ----
|
|
659
|
+
class AXMCommunicationInboxBadgeProvider {
|
|
660
|
+
constructor() {
|
|
661
|
+
this.inbox = inject(AXPInAppInboxConnectorService);
|
|
662
|
+
this.key = 'badge-communication-inbox';
|
|
663
|
+
this.count = computed(() => this.inbox.unreadCount(), /* @ts-ignore */
|
|
664
|
+
...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
|
|
665
|
+
}
|
|
666
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInboxBadgeProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
667
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInboxBadgeProvider }); }
|
|
668
|
+
}
|
|
669
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInboxBadgeProvider, decorators: [{
|
|
670
|
+
type: Injectable
|
|
671
|
+
}] });
|
|
672
|
+
|
|
673
|
+
const I18N$4 = '@communication-management:entities.communication-delivery.states';
|
|
674
|
+
//#region ---- Communication delivery status provider ----
|
|
675
|
+
/** Engine-managed delivery lifecycle — read-only in the UI. */
|
|
676
|
+
class AXMCommunicationDeliveryStatusProvider extends AXPStatusProvider {
|
|
677
|
+
constructor() {
|
|
678
|
+
super(...arguments);
|
|
679
|
+
this.key = AXP_COMMUNICATION_DELIVERY_STATUS_DEFINITION_KEY;
|
|
680
|
+
this.defaultStatus = AXP_COMMUNICATION_DELIVERY_STATUS_PENDING;
|
|
681
|
+
this.statuses = [
|
|
682
|
+
{ name: 'Pending', title: `${I18N$4}.pending`, color: 'secondary', generateView: true, isInitial: true },
|
|
683
|
+
{ name: 'Queued', title: `${I18N$4}.queued`, color: 'info', generateView: true },
|
|
684
|
+
{ name: 'Processing', title: `${I18N$4}.processing`, color: 'primary', generateView: true },
|
|
685
|
+
{ name: 'Accepted', title: `${I18N$4}.accepted`, color: 'info', generateView: true },
|
|
686
|
+
{ name: 'Sent', title: `${I18N$4}.sent`, color: 'warning', generateView: true },
|
|
687
|
+
{ name: 'Delivered', title: `${I18N$4}.delivered`, color: 'success', generateView: true, isFinal: true },
|
|
688
|
+
{ name: 'Failed', title: `${I18N$4}.failed`, color: 'danger', generateView: true, isFinal: true },
|
|
689
|
+
{ name: 'RetryScheduled', title: `${I18N$4}.retry-scheduled`, color: 'warning', generateView: true },
|
|
690
|
+
{ name: 'Cancelled', title: `${I18N$4}.cancelled`, color: 'secondary', generateView: true, isFinal: true },
|
|
691
|
+
{ name: 'DeadLettered', title: `${I18N$4}.dead-lettered`, color: 'danger', generateView: true, isFinal: true },
|
|
692
|
+
];
|
|
693
|
+
this.transitions = [];
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
//#endregion
|
|
697
|
+
|
|
698
|
+
const I18N$3 = '@communication-management:entities.communication.states';
|
|
699
|
+
//#region ---- Communication status provider ----
|
|
700
|
+
/** Engine-managed aggregate communication status — read-only in the UI. */
|
|
701
|
+
class AXMCommunicationStatusProvider extends AXPStatusProvider {
|
|
702
|
+
constructor() {
|
|
703
|
+
super(...arguments);
|
|
704
|
+
this.key = AXP_COMMUNICATION_STATUS_DEFINITION_KEY;
|
|
705
|
+
this.defaultStatus = AXP_COMMUNICATION_STATUS_PENDING;
|
|
706
|
+
this.statuses = [
|
|
707
|
+
{ name: 'Pending', title: `${I18N$3}.pending`, color: 'secondary', generateView: true, isInitial: true },
|
|
708
|
+
{ name: 'Processing', title: `${I18N$3}.processing`, color: 'primary', generateView: true },
|
|
709
|
+
{ name: 'Completed', title: `${I18N$3}.completed`, color: 'success', generateView: true, isFinal: true },
|
|
710
|
+
{ name: 'Failed', title: `${I18N$3}.failed`, color: 'danger', generateView: true, isFinal: true },
|
|
711
|
+
{ name: 'Cancelled', title: `${I18N$3}.cancelled`, color: 'secondary', generateView: true, isFinal: true },
|
|
712
|
+
];
|
|
713
|
+
this.transitions = [];
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
//#endregion
|
|
717
|
+
|
|
718
|
+
//#region ---- Communication in-app inbox registration values ----
|
|
719
|
+
const communicationInAppInboxConfig = {
|
|
720
|
+
headerIconClass: 'fa-regular fa-bell',
|
|
721
|
+
viewAllRoute: (appName) => [`/${appName}/my/notification`],
|
|
722
|
+
settingsRoute: (appName) => [`/${appName}/settings/user/communication-notifications`],
|
|
723
|
+
};
|
|
724
|
+
const communicationInAppInboxI18n = {
|
|
725
|
+
panelTitle: '@communication-management:in-app.panel.title',
|
|
726
|
+
unread: '@communication-management:in-app.tabs.unread',
|
|
727
|
+
all: '@communication-management:in-app.tabs.all',
|
|
728
|
+
markAllAsRead: '@communication-management:in-app.actions.mark-all-read',
|
|
729
|
+
viewAll: '@communication-management:in-app.actions.view-all',
|
|
730
|
+
emptyTitle: '@communication-management:in-app.state.empty.title',
|
|
731
|
+
emptyDescription: '@communication-management:in-app.state.empty.description',
|
|
732
|
+
pageTitle: '@communication-management:in-app.page.title',
|
|
733
|
+
pageDescriptionNone: '@communication-management:in-app.page.description.none',
|
|
734
|
+
pageDescriptionUnread: '@communication-management:in-app.page.description.unread',
|
|
735
|
+
pageDescriptionAllRead: '@communication-management:in-app.page.description.all-read',
|
|
736
|
+
refresh: '@communication-management:in-app.actions.refresh',
|
|
737
|
+
pin: '@general:actions.pin.title',
|
|
738
|
+
unpin: '@general:actions.unpin.title',
|
|
739
|
+
delete: '@communication-management:in-app.actions.delete',
|
|
740
|
+
archive: '@communication-management:in-app.actions.archive',
|
|
741
|
+
markAsRead: '@communication-management:in-app.actions.mark-as-read',
|
|
742
|
+
selectItems: '@communication-management:in-app.actions.select-items',
|
|
743
|
+
clearFilters: '@communication-management:in-app.actions.clear-filters',
|
|
744
|
+
liveUpdatesOffline: '@communication-management:in-app.live-updates-offline',
|
|
745
|
+
};
|
|
746
|
+
//#endregion
|
|
747
|
+
|
|
748
|
+
class AXPCommunicationManagementClient {
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const UNREAD_DELIVERY_FILTER = {
|
|
752
|
+
logic: 'or',
|
|
753
|
+
filters: [
|
|
754
|
+
{ field: 'readAt', operator: { type: 'isNull' }, value: null },
|
|
755
|
+
{ field: 'readAt', operator: { type: 'equal' }, value: false },
|
|
756
|
+
],
|
|
757
|
+
};
|
|
758
|
+
const INBOX_CATEGORY_FILTER = {
|
|
759
|
+
field: 'archivedAt',
|
|
760
|
+
operator: { type: 'isNull' },
|
|
761
|
+
value: null,
|
|
762
|
+
};
|
|
763
|
+
const ARCHIVE_CATEGORY_FILTER = {
|
|
764
|
+
field: 'archivedAt',
|
|
765
|
+
operator: { type: 'isNotEmpty' },
|
|
766
|
+
};
|
|
767
|
+
function buildCommunicationInAppInboxPageQuery(filters, skip, take, communicationIds) {
|
|
768
|
+
const conditions = [
|
|
769
|
+
{ field: 'channel', operator: { type: 'equal' }, value: 'in-app' },
|
|
770
|
+
];
|
|
771
|
+
const readFilter = filters.find((f) => f.field === 'readStatus');
|
|
772
|
+
if (readFilter?.value === 'unread') {
|
|
773
|
+
conditions.push(UNREAD_DELIVERY_FILTER);
|
|
774
|
+
}
|
|
775
|
+
const categoryFilter = filters.find((f) => f.field === 'category');
|
|
776
|
+
if (categoryFilter?.value === 'Archive') {
|
|
777
|
+
conditions.push(ARCHIVE_CATEGORY_FILTER);
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
conditions.push(INBOX_CATEGORY_FILTER);
|
|
781
|
+
}
|
|
782
|
+
if (communicationIds?.length) {
|
|
783
|
+
conditions.push({
|
|
784
|
+
logic: 'or',
|
|
785
|
+
filters: communicationIds.map((id) => ({
|
|
786
|
+
field: 'communicationId',
|
|
787
|
+
operator: { type: 'equal' },
|
|
788
|
+
value: id,
|
|
789
|
+
})),
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
else if (communicationIds?.length === 0) {
|
|
793
|
+
conditions.push({
|
|
794
|
+
field: 'id',
|
|
795
|
+
operator: { type: 'equal' },
|
|
796
|
+
value: '__no_results__',
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
return {
|
|
800
|
+
skip,
|
|
801
|
+
take,
|
|
802
|
+
sort: [
|
|
803
|
+
{ field: 'isPinned', dir: 'desc' },
|
|
804
|
+
{ field: 'deliveredAt', dir: 'desc' },
|
|
805
|
+
],
|
|
806
|
+
filter: { logic: 'and', filters: conditions },
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
function resolveCommunicationInboxCommunicationFilters(filters) {
|
|
810
|
+
const searchFilter = filters.find((f) => f.field === 'all' || f.field === AXP_QUERY_QUICK_SEARCH_FIELD);
|
|
811
|
+
const searchText = searchFilter?.value != null ? String(searchFilter.value).trim() : '';
|
|
812
|
+
const typeFilter = filters.find((f) => f.field === 'type');
|
|
813
|
+
const definitionKey = typeFilter?.value ? String(typeFilter.value) : undefined;
|
|
814
|
+
const priorityFilter = filters.find((f) => f.field === 'priority');
|
|
815
|
+
const priority = priorityFilter?.value ? String(priorityFilter.value) : undefined;
|
|
816
|
+
return {
|
|
817
|
+
searchText: searchText || undefined,
|
|
818
|
+
definitionKey,
|
|
819
|
+
priority,
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
//#region ---- Conversation in-app inbox mapping ----
|
|
824
|
+
const IN_APP_CONVERSATION_CHAT_DEFINITION_KEY = 'conversation-chat-message';
|
|
825
|
+
const IN_APP_CONVERSATION_OPEN_CHAT_COMMAND = 'Conversation:OpenChat';
|
|
826
|
+
function parseConversationInAppCorrelationId(correlationId) {
|
|
827
|
+
const scoped = correlationId?.trim();
|
|
828
|
+
if (!scoped?.startsWith('conversation:')) {
|
|
829
|
+
return undefined;
|
|
830
|
+
}
|
|
831
|
+
const segments = scoped.split(':');
|
|
832
|
+
if (segments.length < 3) {
|
|
833
|
+
return undefined;
|
|
834
|
+
}
|
|
835
|
+
const conversationId = segments[1]?.trim();
|
|
836
|
+
const messageId = segments[2]?.trim();
|
|
837
|
+
if (!conversationId || !messageId) {
|
|
838
|
+
return undefined;
|
|
839
|
+
}
|
|
840
|
+
const senderUserId = segments[3]?.trim() || undefined;
|
|
841
|
+
return { conversationId, messageId, senderUserId };
|
|
842
|
+
}
|
|
843
|
+
function readSenderUserIdFromActions(actions) {
|
|
844
|
+
const options = actions?.[0]?.command?.options;
|
|
845
|
+
if (!options || typeof options !== 'object') {
|
|
846
|
+
return undefined;
|
|
847
|
+
}
|
|
848
|
+
const senderUserId = options['senderUserId'];
|
|
849
|
+
return typeof senderUserId === 'string' && senderUserId.trim() ? senderUserId.trim() : undefined;
|
|
850
|
+
}
|
|
851
|
+
function resolveConversationSenderName(title, body) {
|
|
852
|
+
const bodyText = body?.trim();
|
|
853
|
+
if (bodyText?.includes(':')) {
|
|
854
|
+
const prefix = bodyText.slice(0, bodyText.indexOf(':')).trim();
|
|
855
|
+
if (prefix) {
|
|
856
|
+
return prefix;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
const titleText = title?.trim();
|
|
860
|
+
return titleText || undefined;
|
|
861
|
+
}
|
|
862
|
+
function resolveConversationInAppInboxSender(input) {
|
|
863
|
+
if (input.definitionKey !== IN_APP_CONVERSATION_CHAT_DEFINITION_KEY) {
|
|
864
|
+
return undefined;
|
|
865
|
+
}
|
|
866
|
+
const parsed = parseConversationInAppCorrelationId(input.correlationId);
|
|
867
|
+
const senderUserId = parsed?.senderUserId ?? readSenderUserIdFromActions(input.actions);
|
|
868
|
+
const senderName = resolveConversationSenderName(input.title, input.body);
|
|
869
|
+
if (!senderUserId || !senderName || senderUserId === 'system') {
|
|
870
|
+
return undefined;
|
|
871
|
+
}
|
|
872
|
+
return { id: senderUserId, fullName: senderName };
|
|
873
|
+
}
|
|
874
|
+
function resolveConversationInAppInboxActions(input) {
|
|
875
|
+
if (input.definitionKey !== IN_APP_CONVERSATION_CHAT_DEFINITION_KEY) {
|
|
876
|
+
return input.actions;
|
|
877
|
+
}
|
|
878
|
+
if (input.actions?.some((action) => action.command?.name?.trim())) {
|
|
879
|
+
return input.actions;
|
|
880
|
+
}
|
|
881
|
+
const parsed = parseConversationInAppCorrelationId(input.correlationId);
|
|
882
|
+
if (!parsed?.conversationId) {
|
|
883
|
+
return input.actions;
|
|
884
|
+
}
|
|
885
|
+
return [
|
|
886
|
+
{
|
|
887
|
+
title: '@conversation:in-app.actions.open-chat',
|
|
888
|
+
command: {
|
|
889
|
+
name: IN_APP_CONVERSATION_OPEN_CHAT_COMMAND,
|
|
890
|
+
options: {
|
|
891
|
+
conversationId: parsed.conversationId,
|
|
892
|
+
...(parsed.senderUserId ? { senderUserId: parsed.senderUserId } : {}),
|
|
893
|
+
},
|
|
894
|
+
},
|
|
895
|
+
},
|
|
896
|
+
];
|
|
897
|
+
}
|
|
898
|
+
//#endregion
|
|
899
|
+
|
|
900
|
+
const IN_APP_CHANNEL = 'in-app';
|
|
901
|
+
//#region ---- Communication delivery inbox port ----
|
|
902
|
+
class AXMCommunicationInAppInboxPort {
|
|
903
|
+
constructor() {
|
|
904
|
+
this.capabilities = {
|
|
905
|
+
seenTracking: true,
|
|
906
|
+
readTracking: true,
|
|
907
|
+
pinSupport: true,
|
|
908
|
+
categoryTabs: false,
|
|
909
|
+
};
|
|
910
|
+
this.entityService = inject(AXPEntityService);
|
|
911
|
+
this.sessionService = inject(AXPSessionService);
|
|
912
|
+
this.client = inject(AXPCommunicationManagementClient);
|
|
913
|
+
this.deliveryData = this.entityService
|
|
914
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.communicationDelivery.name)
|
|
915
|
+
.data();
|
|
916
|
+
this.communicationData = this.entityService
|
|
917
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.communication.name)
|
|
918
|
+
.data();
|
|
919
|
+
}
|
|
920
|
+
async loadInbox(query = {}) {
|
|
921
|
+
if (!this.sessionService.isReadyForAppScopedApi) {
|
|
922
|
+
return { items: [], total: 0 };
|
|
923
|
+
}
|
|
924
|
+
const userId = this.sessionService.user?.id;
|
|
925
|
+
if (!userId) {
|
|
926
|
+
return { items: [], total: 0 };
|
|
927
|
+
}
|
|
928
|
+
const skip = query.skip ?? 0;
|
|
929
|
+
const take = query.take ?? 1000;
|
|
930
|
+
const filters = query.filters ?? [];
|
|
931
|
+
const excludeArchived = query.excludeArchived ?? filters.length === 0;
|
|
932
|
+
const communicationIds = await this.resolveCommunicationIds(filters);
|
|
933
|
+
const request = buildCommunicationInAppInboxPageQuery(filters, skip, take, communicationIds);
|
|
934
|
+
const baseFilters = [...(request.filter?.filters ?? [])];
|
|
935
|
+
if (userId) {
|
|
936
|
+
baseFilters.push({
|
|
937
|
+
field: 'recipientUserId',
|
|
938
|
+
operator: { type: 'equal' },
|
|
939
|
+
value: userId,
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
if (excludeArchived && !filters.some((filter) => filter.field === 'category' && filter.value === 'Archive')) {
|
|
943
|
+
baseFilters.push({
|
|
944
|
+
field: 'archivedAt',
|
|
945
|
+
operator: { type: 'isNull' },
|
|
946
|
+
value: null,
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
const result = await this.deliveryData.query({
|
|
950
|
+
...request,
|
|
951
|
+
filter: { logic: 'and', filters: baseFilters },
|
|
952
|
+
});
|
|
953
|
+
const deliveries = result.items;
|
|
954
|
+
const items = await this.mapDeliveriesToInboxItems(deliveries);
|
|
955
|
+
return { total: result.total, items };
|
|
956
|
+
}
|
|
957
|
+
async loadByIds(ids) {
|
|
958
|
+
if (!this.sessionService.isReadyForAppScopedApi) {
|
|
959
|
+
return { items: [], total: 0 };
|
|
960
|
+
}
|
|
961
|
+
const deliveryIds = [...new Set(ids.map((id) => id?.trim()).filter(Boolean))];
|
|
962
|
+
if (deliveryIds.length === 0) {
|
|
963
|
+
return { total: 0, items: [] };
|
|
964
|
+
}
|
|
965
|
+
const userId = this.sessionService.user?.id;
|
|
966
|
+
const filters = [
|
|
967
|
+
{ field: 'channel', operator: { type: 'equal' }, value: IN_APP_CHANNEL },
|
|
968
|
+
{
|
|
969
|
+
logic: 'or',
|
|
970
|
+
filters: deliveryIds.map((id) => ({
|
|
971
|
+
field: 'id',
|
|
972
|
+
operator: { type: 'equal' },
|
|
973
|
+
value: id,
|
|
974
|
+
})),
|
|
975
|
+
},
|
|
976
|
+
];
|
|
977
|
+
if (userId) {
|
|
978
|
+
filters.push({
|
|
979
|
+
field: 'recipientUserId',
|
|
980
|
+
operator: { type: 'equal' },
|
|
981
|
+
value: userId,
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
const result = await this.deliveryData.query({
|
|
985
|
+
skip: 0,
|
|
986
|
+
take: deliveryIds.length,
|
|
987
|
+
filter: { logic: 'and', filters: filters },
|
|
988
|
+
});
|
|
989
|
+
const deliveries = result.items;
|
|
990
|
+
const items = await this.mapDeliveriesToInboxItems(deliveries);
|
|
991
|
+
return { total: items.length, items };
|
|
992
|
+
}
|
|
993
|
+
async markSeen(ids) {
|
|
994
|
+
const deliveryIds = ids.filter(Boolean);
|
|
995
|
+
if (deliveryIds.length === 0) {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
await this.client.markInAppSeen({ deliveryIds });
|
|
999
|
+
}
|
|
1000
|
+
async markRead(ids) {
|
|
1001
|
+
const deliveryIds = ids.filter(Boolean);
|
|
1002
|
+
if (deliveryIds.length === 0) {
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
await this.client.markInAppRead({ deliveryIds });
|
|
1006
|
+
}
|
|
1007
|
+
async markAllRead() {
|
|
1008
|
+
await this.client.markAllInAppRead();
|
|
1009
|
+
}
|
|
1010
|
+
async togglePin(id) {
|
|
1011
|
+
if (!id.trim()) {
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
await this.client.toggleInAppPin({ deliveryIds: [id] });
|
|
1015
|
+
}
|
|
1016
|
+
async archive(ids) {
|
|
1017
|
+
const deliveryIds = ids.filter(Boolean);
|
|
1018
|
+
if (deliveryIds.length === 0) {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
await this.client.archiveInApp({ deliveryIds });
|
|
1022
|
+
}
|
|
1023
|
+
async deleteDeliveries(ids) {
|
|
1024
|
+
const deliveryIds = ids.filter(Boolean);
|
|
1025
|
+
if (deliveryIds.length === 0) {
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
await this.client.deleteInApp({ deliveryIds });
|
|
1029
|
+
}
|
|
1030
|
+
async mapDeliveriesToInboxItems(deliveries) {
|
|
1031
|
+
const communicationMap = await this.loadCommunicationsById([...new Set(deliveries.map((delivery) => delivery.communicationId).filter(Boolean))]);
|
|
1032
|
+
return sortInAppInboxItems(deliveries.map((item) => this.toInboxItem(item, communicationMap.get(item.communicationId))));
|
|
1033
|
+
}
|
|
1034
|
+
async resolveCommunicationIds(filters) {
|
|
1035
|
+
const { searchText, definitionKey, priority } = resolveCommunicationInboxCommunicationFilters(filters);
|
|
1036
|
+
if (!searchText && !definitionKey && !priority) {
|
|
1037
|
+
return undefined;
|
|
1038
|
+
}
|
|
1039
|
+
const conditions = [];
|
|
1040
|
+
if (definitionKey) {
|
|
1041
|
+
conditions.push({
|
|
1042
|
+
field: 'definitionKey',
|
|
1043
|
+
operator: { type: 'equal' },
|
|
1044
|
+
value: definitionKey,
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
if (priority) {
|
|
1048
|
+
conditions.push({
|
|
1049
|
+
field: 'priority',
|
|
1050
|
+
operator: { type: 'equal' },
|
|
1051
|
+
value: priority,
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
if (searchText) {
|
|
1055
|
+
conditions.push({
|
|
1056
|
+
logic: 'or',
|
|
1057
|
+
filters: [
|
|
1058
|
+
{ field: 'title', operator: { type: 'contains' }, value: searchText },
|
|
1059
|
+
{ field: 'message.subject', operator: { type: 'contains' }, value: searchText },
|
|
1060
|
+
{ field: 'message.body', operator: { type: 'contains' }, value: searchText },
|
|
1061
|
+
],
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
const result = await this.communicationData.query({
|
|
1065
|
+
take: 1000,
|
|
1066
|
+
skip: 0,
|
|
1067
|
+
filter: conditions.length > 0 ? { logic: 'and', filters: conditions } : undefined,
|
|
1068
|
+
});
|
|
1069
|
+
return result.items.map((item) => item.id);
|
|
1070
|
+
}
|
|
1071
|
+
async loadCommunicationsById(ids) {
|
|
1072
|
+
const map = new Map();
|
|
1073
|
+
if (ids.length === 0) {
|
|
1074
|
+
return map;
|
|
1075
|
+
}
|
|
1076
|
+
const result = await this.communicationData.query({
|
|
1077
|
+
take: ids.length,
|
|
1078
|
+
skip: 0,
|
|
1079
|
+
filter: {
|
|
1080
|
+
logic: 'or',
|
|
1081
|
+
filters: ids.map((id) => ({
|
|
1082
|
+
field: 'id',
|
|
1083
|
+
operator: { type: 'equal' },
|
|
1084
|
+
value: id,
|
|
1085
|
+
})),
|
|
1086
|
+
},
|
|
1087
|
+
});
|
|
1088
|
+
for (const communication of result.items) {
|
|
1089
|
+
map.set(communication.id, communication);
|
|
1090
|
+
}
|
|
1091
|
+
return map;
|
|
1092
|
+
}
|
|
1093
|
+
toInboxItem(delivery, communication) {
|
|
1094
|
+
const message = communication
|
|
1095
|
+
? resolveCommunicationMessage(communication)
|
|
1096
|
+
: { subject: '', body: '' };
|
|
1097
|
+
const definitionKey = communication?.definitionKey;
|
|
1098
|
+
const priority = communication?.priority ?? 'Notice';
|
|
1099
|
+
const title = message.subject || communication?.title || '';
|
|
1100
|
+
const body = message.body;
|
|
1101
|
+
const actions = resolveConversationInAppInboxActions({
|
|
1102
|
+
definitionKey,
|
|
1103
|
+
correlationId: communication?.correlationId,
|
|
1104
|
+
actions: communication?.actions,
|
|
1105
|
+
});
|
|
1106
|
+
const sender = resolveConversationInAppInboxSender({
|
|
1107
|
+
definitionKey,
|
|
1108
|
+
title,
|
|
1109
|
+
body,
|
|
1110
|
+
correlationId: communication?.correlationId,
|
|
1111
|
+
actions,
|
|
1112
|
+
});
|
|
1113
|
+
const iconClass = resolveInAppInboxIconClass({ definitionKey, priority, sender });
|
|
1114
|
+
return {
|
|
1115
|
+
id: delivery.id,
|
|
1116
|
+
title,
|
|
1117
|
+
body,
|
|
1118
|
+
createdAt: delivery.deliveredAt ? new Date(delivery.deliveredAt) : new Date(),
|
|
1119
|
+
seenAt: delivery.seenAt ? new Date(delivery.seenAt) : delivery.seenAt ?? null,
|
|
1120
|
+
readAt: delivery.readAt ? new Date(delivery.readAt) : delivery.readAt ?? null,
|
|
1121
|
+
sender,
|
|
1122
|
+
iconClass,
|
|
1123
|
+
priority,
|
|
1124
|
+
isPinned: Boolean(delivery.isPinned),
|
|
1125
|
+
definitionKey,
|
|
1126
|
+
archivedAt: delivery.archivedAt ? new Date(delivery.archivedAt) : delivery.archivedAt ?? null,
|
|
1127
|
+
actions,
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppInboxPort, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1131
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppInboxPort }); }
|
|
1132
|
+
}
|
|
1133
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppInboxPort, decorators: [{
|
|
1134
|
+
type: Injectable
|
|
1135
|
+
}] });
|
|
1136
|
+
|
|
1137
|
+
//#region ---- Inbox realtime topic handler ----
|
|
1138
|
+
function provideCommunicationInAppRealtimeHandlers() {
|
|
1139
|
+
return [
|
|
1140
|
+
provideAppStartUpTask(() => {
|
|
1141
|
+
const dispatcher = inject(AXPRealtimeDispatcherService, { optional: true });
|
|
1142
|
+
const inboxRealtime = inject(AXPInAppInboxRealtimeService);
|
|
1143
|
+
return {
|
|
1144
|
+
name: 'communication-in-app-realtime-handlers',
|
|
1145
|
+
priority: AXP_APP_STARTUP_PRIORITY.realtimeHandlers,
|
|
1146
|
+
run: async () => {
|
|
1147
|
+
dispatcher?.register({
|
|
1148
|
+
topic: AXP_REALTIME_TOPIC_INBOX_REFRESH,
|
|
1149
|
+
handle: (envelope) => {
|
|
1150
|
+
const payload = (envelope.payload ?? {});
|
|
1151
|
+
const ids = [
|
|
1152
|
+
...(payload.deliveryIds ?? []),
|
|
1153
|
+
...(payload.deliveryId ? [payload.deliveryId] : []),
|
|
1154
|
+
].filter(Boolean);
|
|
1155
|
+
const event = {
|
|
1156
|
+
type: resolveInboxChangeType(payload.op),
|
|
1157
|
+
ids: ids.length > 0 ? [...new Set(ids)] : undefined,
|
|
1158
|
+
};
|
|
1159
|
+
inboxRealtime.notifyChanged(event);
|
|
1160
|
+
},
|
|
1161
|
+
});
|
|
1162
|
+
},
|
|
1163
|
+
};
|
|
1164
|
+
}),
|
|
1165
|
+
];
|
|
1166
|
+
}
|
|
1167
|
+
function resolveInboxChangeType(op) {
|
|
1168
|
+
if (op === 'deleted') {
|
|
1169
|
+
return 'deleted';
|
|
1170
|
+
}
|
|
1171
|
+
if (op === 'archived') {
|
|
1172
|
+
return 'archived';
|
|
1173
|
+
}
|
|
1174
|
+
if (op === 'created') {
|
|
1175
|
+
return 'created';
|
|
1176
|
+
}
|
|
1177
|
+
return 'refresh';
|
|
1178
|
+
}
|
|
1179
|
+
//#endregion
|
|
1180
|
+
|
|
1181
|
+
//#region ---- In-app inbox sync status ----
|
|
1182
|
+
class AXMCommunicationInAppInboxSyncStatusService {
|
|
1183
|
+
constructor() {
|
|
1184
|
+
this.liveUpdatesConnected = signal(true, /* @ts-ignore */
|
|
1185
|
+
...(ngDevMode ? [{ debugName: "liveUpdatesConnected" }] : /* istanbul ignore next */ []));
|
|
1186
|
+
}
|
|
1187
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppInboxSyncStatusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1188
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppInboxSyncStatusService, providedIn: 'root' }); }
|
|
1189
|
+
}
|
|
1190
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppInboxSyncStatusService, decorators: [{
|
|
1191
|
+
type: Injectable,
|
|
1192
|
+
args: [{ providedIn: 'root' }]
|
|
1193
|
+
}] });
|
|
1194
|
+
|
|
1195
|
+
//#region ---- Constants ----
|
|
1196
|
+
const POLL_INTERVAL_MS = 60_000;
|
|
1197
|
+
const RECONNECT_REFRESH_DELAY_MS = 250;
|
|
1198
|
+
//#endregion
|
|
1199
|
+
//#region ---- In-app inbox fallback sync ----
|
|
1200
|
+
/**
|
|
1201
|
+
* Keeps the inbox fresh when Socket.IO is down: poll while disconnected,
|
|
1202
|
+
* refresh on reconnect and when the tab becomes visible again.
|
|
1203
|
+
*/
|
|
1204
|
+
function provideCommunicationInAppInboxFallbackSync() {
|
|
1205
|
+
return [
|
|
1206
|
+
provideAppStartUpTask(() => {
|
|
1207
|
+
const connector = inject(AXPInAppInboxConnectorService);
|
|
1208
|
+
const sessionService = inject(AXPSessionService);
|
|
1209
|
+
const syncStatus = inject(AXMCommunicationInAppInboxSyncStatusService);
|
|
1210
|
+
const connection = inject(AXPRealtimeConnectionService, { optional: true });
|
|
1211
|
+
const destroyRef = inject(DestroyRef);
|
|
1212
|
+
const refreshIfAuthorized = () => {
|
|
1213
|
+
if (sessionService.isReadyForAppScopedApi) {
|
|
1214
|
+
void connector.refresh();
|
|
1215
|
+
}
|
|
1216
|
+
};
|
|
1217
|
+
return {
|
|
1218
|
+
name: 'communication-in-app-inbox-fallback',
|
|
1219
|
+
priority: AXP_APP_STARTUP_PRIORITY.realtimeSubscriptions,
|
|
1220
|
+
run: async () => {
|
|
1221
|
+
if (!connection) {
|
|
1222
|
+
syncStatus.liveUpdatesConnected.set(false);
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
let wasConnected = connection.isSocketConnected();
|
|
1226
|
+
connection.connectionStatus$
|
|
1227
|
+
.pipe(distinctUntilChanged(), takeUntilDestroyed(destroyRef))
|
|
1228
|
+
.subscribe((status) => {
|
|
1229
|
+
const connected = status === 'connected';
|
|
1230
|
+
syncStatus.liveUpdatesConnected.set(connected);
|
|
1231
|
+
if (connected && !wasConnected) {
|
|
1232
|
+
timer(RECONNECT_REFRESH_DELAY_MS)
|
|
1233
|
+
.pipe(takeUntilDestroyed(destroyRef))
|
|
1234
|
+
.subscribe(() => {
|
|
1235
|
+
refreshIfAuthorized();
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
wasConnected = connected;
|
|
1239
|
+
});
|
|
1240
|
+
connection.connectionStatus$
|
|
1241
|
+
.pipe(distinctUntilChanged(), switchMap((status) => {
|
|
1242
|
+
if (status === 'connected') {
|
|
1243
|
+
return EMPTY;
|
|
1244
|
+
}
|
|
1245
|
+
return timer(POLL_INTERVAL_MS, POLL_INTERVAL_MS);
|
|
1246
|
+
}), takeUntilDestroyed(destroyRef))
|
|
1247
|
+
.subscribe(() => {
|
|
1248
|
+
refreshIfAuthorized();
|
|
1249
|
+
});
|
|
1250
|
+
document.addEventListener('visibilitychange', () => {
|
|
1251
|
+
if (document.visibilityState === 'visible') {
|
|
1252
|
+
// Re-sync active inbox in case realtime was missed while hidden.
|
|
1253
|
+
refreshIfAuthorized();
|
|
1254
|
+
}
|
|
1255
|
+
}, { passive: true });
|
|
1256
|
+
},
|
|
1257
|
+
};
|
|
1258
|
+
}),
|
|
1259
|
+
];
|
|
1260
|
+
}
|
|
1261
|
+
//#endregion
|
|
1262
|
+
|
|
1263
|
+
//#region ---- Communication-backed in-app notification port ----
|
|
1264
|
+
class AXMCommunicationInAppNotificationService {
|
|
1265
|
+
constructor() {
|
|
1266
|
+
this.client = inject(AXPCommunicationManagementClient);
|
|
1267
|
+
this.realtime = inject(AXPInAppInboxRealtimeService);
|
|
1268
|
+
}
|
|
1269
|
+
async create(request) {
|
|
1270
|
+
const recipientUserId = request.receiver.id?.trim();
|
|
1271
|
+
if (!recipientUserId) {
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
await this.client.send({
|
|
1275
|
+
title: request.title,
|
|
1276
|
+
message: {
|
|
1277
|
+
subject: request.title,
|
|
1278
|
+
body: request.body,
|
|
1279
|
+
},
|
|
1280
|
+
channel: 'in-app',
|
|
1281
|
+
recipientUserId,
|
|
1282
|
+
recipientName: request.receiver.fullName,
|
|
1283
|
+
correlationId: request.id,
|
|
1284
|
+
idempotencyKey: request.id,
|
|
1285
|
+
});
|
|
1286
|
+
this.realtime.notifyChanged({ type: 'refresh' });
|
|
1287
|
+
}
|
|
1288
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppNotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1289
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppNotificationService }); }
|
|
1290
|
+
}
|
|
1291
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationInAppNotificationService, decorators: [{
|
|
1292
|
+
type: Injectable
|
|
1293
|
+
}] });
|
|
1294
|
+
const communicationInAppNotificationServiceProvider = {
|
|
1295
|
+
provide: AXP_IN_APP_NOTIFICATION_SERVICE,
|
|
1296
|
+
useClass: AXMCommunicationInAppNotificationService,
|
|
1297
|
+
};
|
|
1298
|
+
|
|
1299
|
+
//#region ---- Shared in-app inbox types ----
|
|
1300
|
+
//#endregion
|
|
1301
|
+
|
|
1302
|
+
//#region ---- In-app inbox configuration tokens ----
|
|
1303
|
+
const AXP_IN_APP_INBOX_CONFIG = new InjectionToken('AXP_IN_APP_INBOX_CONFIG');
|
|
1304
|
+
const AXP_IN_APP_INBOX_I18N = new InjectionToken('AXP_IN_APP_INBOX_I18N');
|
|
1305
|
+
//#endregion
|
|
1306
|
+
|
|
1307
|
+
const AXP_IN_APP_INBOX_SYNC_STATUS = new InjectionToken('AXP_IN_APP_INBOX_SYNC_STATUS');
|
|
1308
|
+
//#endregion
|
|
1309
|
+
|
|
1310
|
+
//#region ---- Shared in-app inbox row item ----
|
|
1311
|
+
class AXPInAppInboxItemComponent {
|
|
1312
|
+
constructor() {
|
|
1313
|
+
this.data = input.required(/* @ts-ignore */
|
|
1314
|
+
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
1315
|
+
this.showAvatar = input(true, /* @ts-ignore */
|
|
1316
|
+
...(ngDevMode ? [{ debugName: "showAvatar" }] : /* istanbul ignore next */ []));
|
|
1317
|
+
this.showDate = input(true, /* @ts-ignore */
|
|
1318
|
+
...(ngDevMode ? [{ debugName: "showDate" }] : /* istanbul ignore next */ []));
|
|
1319
|
+
this.showPin = input(false, /* @ts-ignore */
|
|
1320
|
+
...(ngDevMode ? [{ debugName: "showPin" }] : /* istanbul ignore next */ []));
|
|
1321
|
+
this.pinLabelKey = input('@general:actions.pin.title', /* @ts-ignore */
|
|
1322
|
+
...(ngDevMode ? [{ debugName: "pinLabelKey" }] : /* istanbul ignore next */ []));
|
|
1323
|
+
this.unpinLabelKey = input('@general:actions.unpin.title', /* @ts-ignore */
|
|
1324
|
+
...(ngDevMode ? [{ debugName: "unpinLabelKey" }] : /* istanbul ignore next */ []));
|
|
1325
|
+
/** When true, unread rows get a subtle background (use on mixed read/unread lists only). */
|
|
1326
|
+
this.highlightUnreadBackground = input(false, /* @ts-ignore */
|
|
1327
|
+
...(ngDevMode ? [{ debugName: "highlightUnreadBackground" }] : /* istanbul ignore next */ []));
|
|
1328
|
+
this.showDismissUnread = input(true, /* @ts-ignore */
|
|
1329
|
+
...(ngDevMode ? [{ debugName: "showDismissUnread" }] : /* istanbul ignore next */ []));
|
|
1330
|
+
this.markAsReadLabelKey = input('@communication-management:in-app.actions.mark-as-read', /* @ts-ignore */
|
|
1331
|
+
...(ngDevMode ? [{ debugName: "markAsReadLabelKey" }] : /* istanbul ignore next */ []));
|
|
1332
|
+
this.priorityClass = computed(() => getInAppInboxPriorityClass(this.data().priority), /* @ts-ignore */
|
|
1333
|
+
...(ngDevMode ? [{ debugName: "priorityClass" }] : /* istanbul ignore next */ []));
|
|
1334
|
+
this.isUnread = computed(() => isInAppInboxUnread(this.data().readAt), /* @ts-ignore */
|
|
1335
|
+
...(ngDevMode ? [{ debugName: "isUnread" }] : /* istanbul ignore next */ []));
|
|
1336
|
+
this.primaryAction = computed(() => this.data().actions?.[0], /* @ts-ignore */
|
|
1337
|
+
...(ngDevMode ? [{ debugName: "primaryAction" }] : /* istanbul ignore next */ []));
|
|
1338
|
+
this.hasDefaultAction = computed(() => !!this.primaryAction()?.command?.name?.trim(), /* @ts-ignore */
|
|
1339
|
+
...(ngDevMode ? [{ debugName: "hasDefaultAction" }] : /* istanbul ignore next */ []));
|
|
1340
|
+
this.headline = computed(() => {
|
|
1341
|
+
const item = this.data();
|
|
1342
|
+
if (isInAppInboxRealUserSender(item.sender)) {
|
|
1343
|
+
return item.sender.fullName.trim();
|
|
1344
|
+
}
|
|
1345
|
+
return item.title ?? '';
|
|
1346
|
+
}, /* @ts-ignore */
|
|
1347
|
+
...(ngDevMode ? [{ debugName: "headline" }] : /* istanbul ignore next */ []));
|
|
1348
|
+
this.itemIconClass = computed(() => resolveInAppInboxIconClass(this.data()), /* @ts-ignore */
|
|
1349
|
+
...(ngDevMode ? [{ debugName: "itemIconClass" }] : /* istanbul ignore next */ []));
|
|
1350
|
+
this.showItemLeading = computed(() => this.showAvatar() && this.data().showAvatar !== false, /* @ts-ignore */
|
|
1351
|
+
...(ngDevMode ? [{ debugName: "showItemLeading" }] : /* istanbul ignore next */ []));
|
|
1352
|
+
this.showItemIcon = computed(() => this.showItemLeading() && !!this.itemIconClass(), /* @ts-ignore */
|
|
1353
|
+
...(ngDevMode ? [{ debugName: "showItemIcon" }] : /* istanbul ignore next */ []));
|
|
1354
|
+
this.showItemAvatar = computed(() => {
|
|
1355
|
+
if (!this.showItemLeading() || this.itemIconClass()) {
|
|
1356
|
+
return false;
|
|
1357
|
+
}
|
|
1358
|
+
return isInAppInboxRealUserSender(this.data().sender);
|
|
1359
|
+
}, /* @ts-ignore */
|
|
1360
|
+
...(ngDevMode ? [{ debugName: "showItemAvatar" }] : /* istanbul ignore next */ []));
|
|
1361
|
+
this.itemPress = output();
|
|
1362
|
+
this.markAsRead = output();
|
|
1363
|
+
this.togglePin = output();
|
|
1364
|
+
this.closePopover = output();
|
|
1365
|
+
}
|
|
1366
|
+
isI18nKey(value) {
|
|
1367
|
+
return value.startsWith('@');
|
|
1368
|
+
}
|
|
1369
|
+
onPress(id) {
|
|
1370
|
+
if (!this.hasDefaultAction()) {
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
this.itemPress.emit(id);
|
|
1374
|
+
this.closePopover.emit();
|
|
1375
|
+
}
|
|
1376
|
+
onTogglePin(event) {
|
|
1377
|
+
event.preventDefault();
|
|
1378
|
+
event.stopPropagation();
|
|
1379
|
+
this.togglePin.emit(this.data().id);
|
|
1380
|
+
}
|
|
1381
|
+
onDismissMarkAsRead(event) {
|
|
1382
|
+
event.preventDefault();
|
|
1383
|
+
event.stopPropagation();
|
|
1384
|
+
this.markAsRead.emit(this.data().id);
|
|
1385
|
+
}
|
|
1386
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1387
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPInAppInboxItemComponent, isStandalone: true, selector: "axp-in-app-inbox-item", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, showAvatar: { classPropertyName: "showAvatar", publicName: "showAvatar", isSignal: true, isRequired: false, transformFunction: null }, showDate: { classPropertyName: "showDate", publicName: "showDate", isSignal: true, isRequired: false, transformFunction: null }, showPin: { classPropertyName: "showPin", publicName: "showPin", isSignal: true, isRequired: false, transformFunction: null }, pinLabelKey: { classPropertyName: "pinLabelKey", publicName: "pinLabelKey", isSignal: true, isRequired: false, transformFunction: null }, unpinLabelKey: { classPropertyName: "unpinLabelKey", publicName: "unpinLabelKey", isSignal: true, isRequired: false, transformFunction: null }, highlightUnreadBackground: { classPropertyName: "highlightUnreadBackground", publicName: "highlightUnreadBackground", isSignal: true, isRequired: false, transformFunction: null }, showDismissUnread: { classPropertyName: "showDismissUnread", publicName: "showDismissUnread", isSignal: true, isRequired: false, transformFunction: null }, markAsReadLabelKey: { classPropertyName: "markAsReadLabelKey", publicName: "markAsReadLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemPress: "itemPress", markAsRead: "markAsRead", togglePin: "togglePin", closePopover: "closePopover" }, ngImport: i0, template: "<div\n class=\"axp-in-app-inbox-item\"\n [id]=\"data().id\"\n (click)=\"onPress(data().id)\"\n [class]=\"[\n priorityClass(),\n isUnread() ? 'unread' : 'read',\n isUnread() && highlightUnreadBackground() ? 'unread-highlight' : '',\n ]\"\n>\n @if (showItemIcon()) {\n <div class=\"axp-in-app-inbox-item__icon\" [class]=\"priorityClass()\">\n <i [class]=\"itemIconClass()\" aria-hidden=\"true\"></i>\n </div>\n } @else if (showItemAvatar()) {\n <div class=\"axp-in-app-inbox-item__avatar\">\n <axp-user-avatar\n [size]=\"48\"\n [userId]=\"data().sender!.id\"\n [axpUserCard]=\"data().sender!.id\"\n ></axp-user-avatar>\n @if (isUnread()) {\n <div class=\"axp-in-app-inbox-item__unread-badge\"></div>\n }\n </div>\n }\n\n <div class=\"axp-in-app-inbox-item__content\">\n <div class=\"axp-in-app-inbox-item__title\" [class.--unread]=\"isUnread()\">\n @if (isI18nKey(headline())) {\n {{ headline() | translate | async }}\n } @else {\n {{ headline() }}\n }\n </div>\n\n <div class=\"axp-in-app-inbox-item__subline\">\n @if (showDate()) {\n <span class=\"axp-in-app-inbox-item__time\">{{ data().createdAt | format: 'timeleft' | async }}</span>\n }\n @if (data().category) {\n <span class=\"axp-in-app-inbox-item__subline-separator\" aria-hidden=\"true\">\u2022</span>\n <span class=\"axp-in-app-inbox-item__category\">{{ data().category }}</span>\n }\n @if (showPin()) {\n @if (data().isPinned) {\n <button\n type=\"button\"\n class=\"axp-in-app-inbox-item__pin axp-in-app-inbox-item__pin--inline\"\n [attr.aria-label]=\"unpinLabelKey() | translate | async\"\n (click)=\"onTogglePin($event)\"\n >\n <ax-icon><i class=\"fa-solid fa-thumbtack\"></i></ax-icon>\n </button>\n } @else {\n <button\n type=\"button\"\n class=\"axp-in-app-inbox-item__pin axp-in-app-inbox-item__pin--inline axp-in-app-inbox-item__pin--muted\"\n [attr.aria-label]=\"pinLabelKey() | translate | async\"\n (click)=\"onTogglePin($event)\"\n >\n <ax-icon><i class=\"fa-regular fa-thumbtack\"></i></ax-icon>\n </button>\n }\n }\n </div>\n\n <div class=\"axp-in-app-inbox-item__body\">\n @if (isI18nKey(data().body)) {\n {{ data().body | translate | async }}\n } @else {\n {{ data().body }}\n }\n </div>\n </div>\n\n @if ((isUnread() && showDismissUnread()) || hasDefaultAction()) {\n <div\n class=\"axp-in-app-inbox-item__actions\"\n [class.--dismiss-only]=\"isUnread() && showDismissUnread() && !hasDefaultAction()\"\n >\n @if (isUnread() && showDismissUnread()) {\n <button\n type=\"button\"\n class=\"axp-in-app-inbox-item__dismiss\"\n [attr.aria-label]=\"markAsReadLabelKey() | translate | async\"\n (click)=\"onDismissMarkAsRead($event)\"\n >\n <ax-icon><i class=\"fa-light fa-xmark\" aria-hidden=\"true\"></i></ax-icon>\n </button>\n }\n @if (hasDefaultAction()) {\n <div class=\"axp-in-app-inbox-item__chevron\" aria-hidden=\"true\">\n <ax-icon><i class=\"fa-light fa-chevron-right axp-in-app-inbox-item__chevron-icon\"></i></ax-icon>\n </div>\n }\n </div>\n }\n</div>\n", styles: ["@reference \"@acorex/styles/themes/default.css\";:host{@apply block text-start border-b;border-color:rgb(var(--ax-sys-color-border-lightest-surface))}:host(:last-child){@apply border-b-0;}.axp-in-app-inbox-item{@apply flex items-start gap-3 px-4 py-3 relative cursor-pointer transition-colors duration-150;}.axp-in-app-inbox-item.read,.axp-in-app-inbox-item.unread{background:transparent}.axp-in-app-inbox-item.unread-highlight{background:rgb(var(--ax-sys-color-warning-50))}@media(hover:hover){.axp-in-app-inbox-item:hover{background:rgb(var(--ax-sys-color-lightest-surface))}.axp-in-app-inbox-item:hover.unread-highlight{background:rgb(var(--ax-sys-color-warning-100))}.axp-in-app-inbox-item:hover .axp-in-app-inbox-item__pin--muted,.axp-in-app-inbox-item:hover .axp-in-app-inbox-item__dismiss{visibility:visible;pointer-events:auto}.axp-in-app-inbox-item:hover .axp-in-app-inbox-item__chevron{color:rgb(var(--ax-sys-color-on-surface))}}.axp-in-app-inbox-item__actions{@apply relative flex shrink-0 items-center self-center ps-1;}.axp-in-app-inbox-item__dismiss{@apply absolute bottom-full mb-0.5 start-1/2 inline-flex size-6 -translate-x-1/2 items-center justify-center rounded-full border-0 bg-transparent p-0;color:rgb(var(--ax-sys-color-on-surface-variant))}@media(hover:hover){.axp-in-app-inbox-item__dismiss{visibility:hidden;pointer-events:none}}.axp-in-app-inbox-item__dismiss i{@apply text-xs leading-none;}.axp-in-app-inbox-item__dismiss:focus-visible{visibility:visible;pointer-events:auto;color:rgb(var(--ax-sys-color-on-surface))}.axp-in-app-inbox-item__dismiss:hover{color:rgb(var(--ax-sys-color-on-surface))}.axp-in-app-inbox-item__actions.--dismiss-only .axp-in-app-inbox-item__dismiss{@apply static mb-0 translate-x-0;}.axp-in-app-inbox-item__avatar{@apply relative h-12 shrink-0;}.axp-in-app-inbox-item__icon{@apply flex size-12 shrink-0 items-center justify-center rounded-full border text-base leading-none;}.axp-in-app-inbox-item__icon i{@apply block text-base leading-none;}.axp-in-app-inbox-item__icon.Notice{@apply border;background-color:rgb(var(--ax-sys-color-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-light-surface))}.axp-in-app-inbox-item__icon.Notice i{color:rgb(var(--ax-sys-color-on-success-lightest-surface))}.axp-in-app-inbox-item__icon.Danger{@apply border;background-color:rgb(var(--ax-sys-color-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-light-surface))}.axp-in-app-inbox-item__icon.Danger i{color:rgb(var(--ax-sys-color-on-danger-lightest-surface))}.axp-in-app-inbox-item__icon.Warning{@apply border;background-color:rgb(var(--ax-sys-color-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-light-surface))}.axp-in-app-inbox-item__icon.Warning i{color:rgb(var(--ax-sys-color-on-warning-lightest-surface))}.axp-in-app-inbox-item__unread-badge{@apply absolute bottom-0 end-0;width:10px;height:10px;background:rgb(var(--ax-sys-color-primary-500));border:2px solid rgb(var(--ax-sys-color-surface));border-radius:50%}.axp-in-app-inbox-item__content{@apply flex min-w-0 flex-1 flex-col text-start;}.axp-in-app-inbox-item__title{@apply text-sm font-medium truncate;color:rgb(var(--ax-sys-color-on-surface))}.axp-in-app-inbox-item__title.--unread{@apply font-semibold;}.axp-in-app-inbox-item__subline{@apply mt-0.5 flex min-w-0 flex-wrap items-center gap-x-1.5 gap-y-0.5;}.axp-in-app-inbox-item__time,.axp-in-app-inbox-item__category,.axp-in-app-inbox-item__subline-separator{@apply text-xs;color:rgb(var(--ax-sys-color-on-surface-variant))}.axp-in-app-inbox-item__body{@apply mt-1 line-clamp-2 text-start text-sm;color:rgb(var(--ax-sys-color-on-surface-variant))}.axp-in-app-inbox-item__pin{@apply inline-flex items-center justify-center rounded-full border-0 bg-transparent p-0.5;color:rgb(var(--ax-sys-color-primary))}.axp-in-app-inbox-item__pin i{@apply rotate-45 text-xs;}.axp-in-app-inbox-item__pin--inline{@apply ms-auto;}.axp-in-app-inbox-item__pin--muted{color:rgb(var(--ax-sys-color-on-surface-variant))}@media(hover:hover){.axp-in-app-inbox-item__pin--muted{visibility:hidden;pointer-events:none}}.axp-in-app-inbox-item__pin--muted:focus-visible{visibility:visible;pointer-events:auto}.axp-in-app-inbox-item__pin--muted:hover{color:rgb(var(--ax-sys-color-primary))}.axp-in-app-inbox-item__chevron{@apply text-sm transition-colors;color:rgb(var(--ax-sys-color-on-surface-variant))}:host-context([dir=\"rtl\"]) .axp-in-app-inbox-item__chevron-icon{transform:scaleX(-1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: AXPUserAvatarComponent, selector: "axp-user-avatar", inputs: ["size", "userId", "showPresence", "displayName", "displayAvatar"] }, { kind: "directive", type: AXPUserCardDirective, selector: "[axpUserCard]", inputs: ["axpUserCard", "axpUserCardDisabled"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXFormatPipe, name: "format" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1388
|
+
}
|
|
1389
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxItemComponent, decorators: [{
|
|
1390
|
+
type: Component,
|
|
1391
|
+
args: [{ selector: 'axp-in-app-inbox-item', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
1392
|
+
CommonModule,
|
|
1393
|
+
AXDecoratorModule,
|
|
1394
|
+
AXPUserAvatarComponent,
|
|
1395
|
+
AXPUserCardDirective,
|
|
1396
|
+
AXBadgeModule,
|
|
1397
|
+
AXFormatModule,
|
|
1398
|
+
AXTranslationModule,
|
|
1399
|
+
], template: "<div\n class=\"axp-in-app-inbox-item\"\n [id]=\"data().id\"\n (click)=\"onPress(data().id)\"\n [class]=\"[\n priorityClass(),\n isUnread() ? 'unread' : 'read',\n isUnread() && highlightUnreadBackground() ? 'unread-highlight' : '',\n ]\"\n>\n @if (showItemIcon()) {\n <div class=\"axp-in-app-inbox-item__icon\" [class]=\"priorityClass()\">\n <i [class]=\"itemIconClass()\" aria-hidden=\"true\"></i>\n </div>\n } @else if (showItemAvatar()) {\n <div class=\"axp-in-app-inbox-item__avatar\">\n <axp-user-avatar\n [size]=\"48\"\n [userId]=\"data().sender!.id\"\n [axpUserCard]=\"data().sender!.id\"\n ></axp-user-avatar>\n @if (isUnread()) {\n <div class=\"axp-in-app-inbox-item__unread-badge\"></div>\n }\n </div>\n }\n\n <div class=\"axp-in-app-inbox-item__content\">\n <div class=\"axp-in-app-inbox-item__title\" [class.--unread]=\"isUnread()\">\n @if (isI18nKey(headline())) {\n {{ headline() | translate | async }}\n } @else {\n {{ headline() }}\n }\n </div>\n\n <div class=\"axp-in-app-inbox-item__subline\">\n @if (showDate()) {\n <span class=\"axp-in-app-inbox-item__time\">{{ data().createdAt | format: 'timeleft' | async }}</span>\n }\n @if (data().category) {\n <span class=\"axp-in-app-inbox-item__subline-separator\" aria-hidden=\"true\">\u2022</span>\n <span class=\"axp-in-app-inbox-item__category\">{{ data().category }}</span>\n }\n @if (showPin()) {\n @if (data().isPinned) {\n <button\n type=\"button\"\n class=\"axp-in-app-inbox-item__pin axp-in-app-inbox-item__pin--inline\"\n [attr.aria-label]=\"unpinLabelKey() | translate | async\"\n (click)=\"onTogglePin($event)\"\n >\n <ax-icon><i class=\"fa-solid fa-thumbtack\"></i></ax-icon>\n </button>\n } @else {\n <button\n type=\"button\"\n class=\"axp-in-app-inbox-item__pin axp-in-app-inbox-item__pin--inline axp-in-app-inbox-item__pin--muted\"\n [attr.aria-label]=\"pinLabelKey() | translate | async\"\n (click)=\"onTogglePin($event)\"\n >\n <ax-icon><i class=\"fa-regular fa-thumbtack\"></i></ax-icon>\n </button>\n }\n }\n </div>\n\n <div class=\"axp-in-app-inbox-item__body\">\n @if (isI18nKey(data().body)) {\n {{ data().body | translate | async }}\n } @else {\n {{ data().body }}\n }\n </div>\n </div>\n\n @if ((isUnread() && showDismissUnread()) || hasDefaultAction()) {\n <div\n class=\"axp-in-app-inbox-item__actions\"\n [class.--dismiss-only]=\"isUnread() && showDismissUnread() && !hasDefaultAction()\"\n >\n @if (isUnread() && showDismissUnread()) {\n <button\n type=\"button\"\n class=\"axp-in-app-inbox-item__dismiss\"\n [attr.aria-label]=\"markAsReadLabelKey() | translate | async\"\n (click)=\"onDismissMarkAsRead($event)\"\n >\n <ax-icon><i class=\"fa-light fa-xmark\" aria-hidden=\"true\"></i></ax-icon>\n </button>\n }\n @if (hasDefaultAction()) {\n <div class=\"axp-in-app-inbox-item__chevron\" aria-hidden=\"true\">\n <ax-icon><i class=\"fa-light fa-chevron-right axp-in-app-inbox-item__chevron-icon\"></i></ax-icon>\n </div>\n }\n </div>\n }\n</div>\n", styles: ["@reference \"@acorex/styles/themes/default.css\";:host{@apply block text-start border-b;border-color:rgb(var(--ax-sys-color-border-lightest-surface))}:host(:last-child){@apply border-b-0;}.axp-in-app-inbox-item{@apply flex items-start gap-3 px-4 py-3 relative cursor-pointer transition-colors duration-150;}.axp-in-app-inbox-item.read,.axp-in-app-inbox-item.unread{background:transparent}.axp-in-app-inbox-item.unread-highlight{background:rgb(var(--ax-sys-color-warning-50))}@media(hover:hover){.axp-in-app-inbox-item:hover{background:rgb(var(--ax-sys-color-lightest-surface))}.axp-in-app-inbox-item:hover.unread-highlight{background:rgb(var(--ax-sys-color-warning-100))}.axp-in-app-inbox-item:hover .axp-in-app-inbox-item__pin--muted,.axp-in-app-inbox-item:hover .axp-in-app-inbox-item__dismiss{visibility:visible;pointer-events:auto}.axp-in-app-inbox-item:hover .axp-in-app-inbox-item__chevron{color:rgb(var(--ax-sys-color-on-surface))}}.axp-in-app-inbox-item__actions{@apply relative flex shrink-0 items-center self-center ps-1;}.axp-in-app-inbox-item__dismiss{@apply absolute bottom-full mb-0.5 start-1/2 inline-flex size-6 -translate-x-1/2 items-center justify-center rounded-full border-0 bg-transparent p-0;color:rgb(var(--ax-sys-color-on-surface-variant))}@media(hover:hover){.axp-in-app-inbox-item__dismiss{visibility:hidden;pointer-events:none}}.axp-in-app-inbox-item__dismiss i{@apply text-xs leading-none;}.axp-in-app-inbox-item__dismiss:focus-visible{visibility:visible;pointer-events:auto;color:rgb(var(--ax-sys-color-on-surface))}.axp-in-app-inbox-item__dismiss:hover{color:rgb(var(--ax-sys-color-on-surface))}.axp-in-app-inbox-item__actions.--dismiss-only .axp-in-app-inbox-item__dismiss{@apply static mb-0 translate-x-0;}.axp-in-app-inbox-item__avatar{@apply relative h-12 shrink-0;}.axp-in-app-inbox-item__icon{@apply flex size-12 shrink-0 items-center justify-center rounded-full border text-base leading-none;}.axp-in-app-inbox-item__icon i{@apply block text-base leading-none;}.axp-in-app-inbox-item__icon.Notice{@apply border;background-color:rgb(var(--ax-sys-color-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-light-surface))}.axp-in-app-inbox-item__icon.Notice i{color:rgb(var(--ax-sys-color-on-success-lightest-surface))}.axp-in-app-inbox-item__icon.Danger{@apply border;background-color:rgb(var(--ax-sys-color-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-light-surface))}.axp-in-app-inbox-item__icon.Danger i{color:rgb(var(--ax-sys-color-on-danger-lightest-surface))}.axp-in-app-inbox-item__icon.Warning{@apply border;background-color:rgb(var(--ax-sys-color-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-light-surface))}.axp-in-app-inbox-item__icon.Warning i{color:rgb(var(--ax-sys-color-on-warning-lightest-surface))}.axp-in-app-inbox-item__unread-badge{@apply absolute bottom-0 end-0;width:10px;height:10px;background:rgb(var(--ax-sys-color-primary-500));border:2px solid rgb(var(--ax-sys-color-surface));border-radius:50%}.axp-in-app-inbox-item__content{@apply flex min-w-0 flex-1 flex-col text-start;}.axp-in-app-inbox-item__title{@apply text-sm font-medium truncate;color:rgb(var(--ax-sys-color-on-surface))}.axp-in-app-inbox-item__title.--unread{@apply font-semibold;}.axp-in-app-inbox-item__subline{@apply mt-0.5 flex min-w-0 flex-wrap items-center gap-x-1.5 gap-y-0.5;}.axp-in-app-inbox-item__time,.axp-in-app-inbox-item__category,.axp-in-app-inbox-item__subline-separator{@apply text-xs;color:rgb(var(--ax-sys-color-on-surface-variant))}.axp-in-app-inbox-item__body{@apply mt-1 line-clamp-2 text-start text-sm;color:rgb(var(--ax-sys-color-on-surface-variant))}.axp-in-app-inbox-item__pin{@apply inline-flex items-center justify-center rounded-full border-0 bg-transparent p-0.5;color:rgb(var(--ax-sys-color-primary))}.axp-in-app-inbox-item__pin i{@apply rotate-45 text-xs;}.axp-in-app-inbox-item__pin--inline{@apply ms-auto;}.axp-in-app-inbox-item__pin--muted{color:rgb(var(--ax-sys-color-on-surface-variant))}@media(hover:hover){.axp-in-app-inbox-item__pin--muted{visibility:hidden;pointer-events:none}}.axp-in-app-inbox-item__pin--muted:focus-visible{visibility:visible;pointer-events:auto}.axp-in-app-inbox-item__pin--muted:hover{color:rgb(var(--ax-sys-color-primary))}.axp-in-app-inbox-item__chevron{@apply text-sm transition-colors;color:rgb(var(--ax-sys-color-on-surface-variant))}:host-context([dir=\"rtl\"]) .axp-in-app-inbox-item__chevron-icon{transform:scaleX(-1)}\n"] }]
|
|
1400
|
+
}], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], showAvatar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAvatar", required: false }] }], showDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDate", required: false }] }], showPin: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPin", required: false }] }], pinLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "pinLabelKey", required: false }] }], unpinLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "unpinLabelKey", required: false }] }], highlightUnreadBackground: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightUnreadBackground", required: false }] }], showDismissUnread: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDismissUnread", required: false }] }], markAsReadLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "markAsReadLabelKey", required: false }] }], itemPress: [{ type: i0.Output, args: ["itemPress"] }], markAsRead: [{ type: i0.Output, args: ["markAsRead"] }], togglePin: [{ type: i0.Output, args: ["togglePin"] }], closePopover: [{ type: i0.Output, args: ["closePopover"] }] } });
|
|
1401
|
+
|
|
1402
|
+
//#region ----- Imports -----
|
|
1403
|
+
//#endregion
|
|
1404
|
+
//#region ----- Inbox action -----
|
|
1405
|
+
class AXPInAppInboxActionService {
|
|
1406
|
+
constructor() {
|
|
1407
|
+
this.connector = inject(AXPInAppInboxConnectorService);
|
|
1408
|
+
this.commands = inject(AXPCommandService);
|
|
1409
|
+
}
|
|
1410
|
+
async openItem(id) {
|
|
1411
|
+
const item = this.findItem(id);
|
|
1412
|
+
await this.connector.markAsRead([id]);
|
|
1413
|
+
const action = item?.actions?.[0];
|
|
1414
|
+
if (!action?.command?.name) {
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
await this.commands.execute(action.command.name, action.command.options ?? {});
|
|
1418
|
+
}
|
|
1419
|
+
findItem(id) {
|
|
1420
|
+
return (this.connector.inboxList().find((item) => item.id === id) ??
|
|
1421
|
+
this.connector.pagedInboxList().find((item) => item.id === id));
|
|
1422
|
+
}
|
|
1423
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxActionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1424
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxActionService, providedIn: 'root' }); }
|
|
1425
|
+
}
|
|
1426
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxActionService, decorators: [{
|
|
1427
|
+
type: Injectable,
|
|
1428
|
+
args: [{ providedIn: 'root' }]
|
|
1429
|
+
}] });
|
|
1430
|
+
|
|
1431
|
+
class AXPInAppInboxPanelComponent {
|
|
1432
|
+
constructor() {
|
|
1433
|
+
this.unreadCountChange = output();
|
|
1434
|
+
this.closePopover = output();
|
|
1435
|
+
this.connector = inject(AXPInAppInboxConnectorService);
|
|
1436
|
+
this.inboxActions = inject(AXPInAppInboxActionService);
|
|
1437
|
+
this.toastService = inject(AXToastService);
|
|
1438
|
+
this.router = inject(Router);
|
|
1439
|
+
this.sessionService = inject(AXPSessionService);
|
|
1440
|
+
this.i18n = inject(AXP_IN_APP_INBOX_I18N);
|
|
1441
|
+
this.config = inject(AXP_IN_APP_INBOX_CONFIG);
|
|
1442
|
+
this.items = this.connector.inboxList;
|
|
1443
|
+
this.isLoading = this.connector.loading;
|
|
1444
|
+
this.activeTab = signal('Unread', /* @ts-ignore */
|
|
1445
|
+
...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
|
|
1446
|
+
this.tabItems = computed(() => this.buildTabItems(this.items()), /* @ts-ignore */
|
|
1447
|
+
...(ngDevMode ? [{ debugName: "tabItems" }] : /* istanbul ignore next */ []));
|
|
1448
|
+
this.showPin = computed(() => this.connector.capabilities.pinSupport, /* @ts-ignore */
|
|
1449
|
+
...(ngDevMode ? [{ debugName: "showPin" }] : /* istanbul ignore next */ []));
|
|
1450
|
+
effect(() => {
|
|
1451
|
+
const unread = this.tabItems().find((tab) => tab.key === 'Unread')?.count ?? 0;
|
|
1452
|
+
this.unreadCountChange.emit(unread);
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
async ngOnInit() {
|
|
1456
|
+
try {
|
|
1457
|
+
await this.connector.ensureReady();
|
|
1458
|
+
await this.connector.markUnseenAsSeen();
|
|
1459
|
+
}
|
|
1460
|
+
catch (error) {
|
|
1461
|
+
this.toastService.show({
|
|
1462
|
+
content: typeof error === 'string' ? error : 'Failed to load inbox.',
|
|
1463
|
+
color: 'danger',
|
|
1464
|
+
location: 'bottom-center',
|
|
1465
|
+
closeButton: true,
|
|
1466
|
+
timeOut: 3000,
|
|
1467
|
+
timeOutProgress: true,
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
changeActiveTab(tab) {
|
|
1472
|
+
this.activeTab.set(tab);
|
|
1473
|
+
}
|
|
1474
|
+
getItems(tab) {
|
|
1475
|
+
const list = this.items();
|
|
1476
|
+
if (tab === 'All') {
|
|
1477
|
+
return list;
|
|
1478
|
+
}
|
|
1479
|
+
if (tab === 'Unread') {
|
|
1480
|
+
return list.filter((item) => isInAppInboxUnread(item.readAt));
|
|
1481
|
+
}
|
|
1482
|
+
return list.filter((item) => item.category === tab);
|
|
1483
|
+
}
|
|
1484
|
+
async openInboxItem(id) {
|
|
1485
|
+
await this.inboxActions.openItem(id);
|
|
1486
|
+
}
|
|
1487
|
+
async dismissUnread(id) {
|
|
1488
|
+
await this.connector.markAsRead([id]);
|
|
1489
|
+
}
|
|
1490
|
+
async togglePin(id) {
|
|
1491
|
+
await this.connector.togglePin(id);
|
|
1492
|
+
}
|
|
1493
|
+
async markAllAsRead() {
|
|
1494
|
+
await this.connector.markAllAsRead();
|
|
1495
|
+
}
|
|
1496
|
+
viewAll() {
|
|
1497
|
+
this.closePopover.emit();
|
|
1498
|
+
const app = this.sessionService.application?.name ?? 'demo';
|
|
1499
|
+
void this.router.navigate(this.config.viewAllRoute(app));
|
|
1500
|
+
}
|
|
1501
|
+
openSettings() {
|
|
1502
|
+
if (!this.config.settingsRoute) {
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
this.closePopover.emit();
|
|
1506
|
+
const app = this.sessionService.application?.name ?? 'demo';
|
|
1507
|
+
void this.router.navigate(this.config.settingsRoute(app));
|
|
1508
|
+
}
|
|
1509
|
+
buildTabItems(items) {
|
|
1510
|
+
const unreadTotal = items.filter((item) => isInAppInboxUnread(item.readAt)).length;
|
|
1511
|
+
return [
|
|
1512
|
+
{ key: 'Unread', labelKey: this.i18n.unread, count: unreadTotal },
|
|
1513
|
+
{ key: 'All', labelKey: this.i18n.all, count: unreadTotal },
|
|
1514
|
+
];
|
|
1515
|
+
}
|
|
1516
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1517
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPInAppInboxPanelComponent, isStandalone: true, selector: "axp-in-app-inbox-panel", outputs: { unreadCountChange: "unreadCountChange", closePopover: "closePopover" }, ngImport: i0, template: "<div class=\"axp-in-app-inbox-panel__header\">\n <span class=\"axp-in-app-inbox-panel__title\">\n {{ i18n.panelTitle | translate | async }}\n </span>\n @if (config.settingsRoute) {\n <ax-button color=\"default\" look=\"blank\" (onClick)=\"openSettings()\">\n <ax-icon><i class=\"fa-regular fa-gear fa-lg\"></i></ax-icon>\n </ax-button>\n }\n</div>\n<ax-tabs [content]=\"tabContent\" look=\"with-line\" location=\"bottom\">\n @for (tab of tabItems(); track tab.key) {\n <ax-tab-item\n [text]=\"(tab.labelKey | translate | async) ?? ''\"\n [active]=\"activeTab() === tab.key\"\n (activeChange)=\"changeActiveTab(tab.key)\"\n >\n <ax-suffix>\n @if (tab.count && tab.key === 'Unread') {\n <ax-badge [color]=\"activeTab() === tab.key ? 'primary' : 'ghost'\" [text]=\"tab.count.toString()\"></ax-badge>\n }\n </ax-suffix>\n <ax-content>\n <div class=\"axp-in-app-inbox-panel__list\">\n @if (isLoading()) {\n <div class=\"axp-in-app-inbox-panel__loading\">\n @for (_ of [1, 2, 3]; track $index) {\n <div class=\"axp-in-app-inbox-panel__skeleton\">\n <div class=\"axp-in-app-inbox-panel__skeleton-avatar\"></div>\n <div class=\"axp-in-app-inbox-panel__skeleton-lines\">\n <div class=\"axp-in-app-inbox-panel__skeleton-line --wide\"></div>\n <div class=\"axp-in-app-inbox-panel__skeleton-line\"></div>\n </div>\n </div>\n }\n </div>\n } @else if (getItems(tab.key).length === 0) {\n <axp-state-message\n icon=\"fa-regular fa-bell-slash\"\n [title]=\"i18n.emptyTitle\"\n [description]=\"i18n.emptyDescription\"\n />\n } @else {\n @for (item of getItems(tab.key); track item.id) {\n <axp-in-app-inbox-item\n [data]=\"item\"\n [highlightUnreadBackground]=\"tab.key === 'All'\"\n [showPin]=\"showPin()\"\n [pinLabelKey]=\"i18n.pin\"\n [unpinLabelKey]=\"i18n.unpin\"\n [markAsReadLabelKey]=\"i18n.markAsRead\"\n (itemPress)=\"openInboxItem($event)\"\n (markAsRead)=\"dismissUnread($event)\"\n (togglePin)=\"togglePin($event)\"\n (closePopover)=\"closePopover.emit()\"\n />\n }\n }\n </div>\n <div class=\"axp-in-app-inbox-panel__footer\">\n <ax-button\n class=\"ax-sm\"\n [disabled]=\"(tabItems()[0]?.count ?? 0) === 0\"\n look=\"outline\"\n color=\"default\"\n [text]=\"(i18n.markAllAsRead | translate | async) ?? ''\"\n (onClick)=\"markAllAsRead()\"\n />\n <ax-button\n class=\"ax-sm\"\n look=\"outline\"\n color=\"primary\"\n [text]=\"(i18n.viewAll | translate | async) ?? ''\"\n (onClick)=\"viewAll()\"\n />\n </div>\n </ax-content>\n </ax-tab-item>\n }\n</ax-tabs>\n\n<ng-template [axTabContent] #tabContent=\"axTabContent\"></ng-template>\n", styles: ["@reference \"@acorex/styles/themes/default.css\";.axp-in-app-inbox-panel__header{@apply p-4 flex justify-between items-center;}.axp-in-app-inbox-panel__title{@apply text-xl font-semibold;color:rgb(var(--ax-sys-color-on-surface))}.axp-in-app-inbox-panel__list{@apply max-h-[50vh] md:w-[32rem] overflow-y-auto flex flex-col;}.axp-in-app-inbox-panel__footer{@apply flex gap-4 justify-between p-4 border-t;border-color:rgb(var(--ax-sys-color-border-surface))}.axp-in-app-inbox-panel__loading{@apply p-2 space-y-2;}.axp-in-app-inbox-panel__skeleton{@apply flex gap-4 p-4 animate-pulse;}.axp-in-app-inbox-panel__skeleton-avatar{@apply w-12 h-12 rounded-full shrink-0;background:rgb(var(--ax-sys-color-lighter-surface))}.axp-in-app-inbox-panel__skeleton-lines{@apply flex-1 space-y-2 py-1;}.axp-in-app-inbox-panel__skeleton-line{@apply h-3 rounded-md;background:rgb(var(--ax-sys-color-lighter-surface))}.axp-in-app-inbox-panel__skeleton-line.--wide{@apply w-3/4;}.axp-in-app-inbox-panel__skeleton-line:not(.--wide){@apply w-1/2;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i2.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i2.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "directive", type: i2.AXTabContentDirective, selector: "[axTabContent]", inputs: ["axTabContent"], exportAs: ["axTabContent"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i4$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "component", type: AXPInAppInboxItemComponent, selector: "axp-in-app-inbox-item", inputs: ["data", "showAvatar", "showDate", "showPin", "pinLabelKey", "unpinLabelKey", "highlightUnreadBackground", "showDismissUnread", "markAsReadLabelKey"], outputs: ["itemPress", "markAsRead", "togglePin", "closePopover"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1518
|
+
}
|
|
1519
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxPanelComponent, decorators: [{
|
|
1520
|
+
type: Component,
|
|
1521
|
+
args: [{ selector: 'axp-in-app-inbox-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
1522
|
+
CommonModule,
|
|
1523
|
+
AXButtonModule,
|
|
1524
|
+
AXTabsModule,
|
|
1525
|
+
AXDecoratorModule,
|
|
1526
|
+
AXBadgeModule,
|
|
1527
|
+
AXTranslationModule,
|
|
1528
|
+
AXPStateMessageComponent,
|
|
1529
|
+
AXPInAppInboxItemComponent,
|
|
1530
|
+
], template: "<div class=\"axp-in-app-inbox-panel__header\">\n <span class=\"axp-in-app-inbox-panel__title\">\n {{ i18n.panelTitle | translate | async }}\n </span>\n @if (config.settingsRoute) {\n <ax-button color=\"default\" look=\"blank\" (onClick)=\"openSettings()\">\n <ax-icon><i class=\"fa-regular fa-gear fa-lg\"></i></ax-icon>\n </ax-button>\n }\n</div>\n<ax-tabs [content]=\"tabContent\" look=\"with-line\" location=\"bottom\">\n @for (tab of tabItems(); track tab.key) {\n <ax-tab-item\n [text]=\"(tab.labelKey | translate | async) ?? ''\"\n [active]=\"activeTab() === tab.key\"\n (activeChange)=\"changeActiveTab(tab.key)\"\n >\n <ax-suffix>\n @if (tab.count && tab.key === 'Unread') {\n <ax-badge [color]=\"activeTab() === tab.key ? 'primary' : 'ghost'\" [text]=\"tab.count.toString()\"></ax-badge>\n }\n </ax-suffix>\n <ax-content>\n <div class=\"axp-in-app-inbox-panel__list\">\n @if (isLoading()) {\n <div class=\"axp-in-app-inbox-panel__loading\">\n @for (_ of [1, 2, 3]; track $index) {\n <div class=\"axp-in-app-inbox-panel__skeleton\">\n <div class=\"axp-in-app-inbox-panel__skeleton-avatar\"></div>\n <div class=\"axp-in-app-inbox-panel__skeleton-lines\">\n <div class=\"axp-in-app-inbox-panel__skeleton-line --wide\"></div>\n <div class=\"axp-in-app-inbox-panel__skeleton-line\"></div>\n </div>\n </div>\n }\n </div>\n } @else if (getItems(tab.key).length === 0) {\n <axp-state-message\n icon=\"fa-regular fa-bell-slash\"\n [title]=\"i18n.emptyTitle\"\n [description]=\"i18n.emptyDescription\"\n />\n } @else {\n @for (item of getItems(tab.key); track item.id) {\n <axp-in-app-inbox-item\n [data]=\"item\"\n [highlightUnreadBackground]=\"tab.key === 'All'\"\n [showPin]=\"showPin()\"\n [pinLabelKey]=\"i18n.pin\"\n [unpinLabelKey]=\"i18n.unpin\"\n [markAsReadLabelKey]=\"i18n.markAsRead\"\n (itemPress)=\"openInboxItem($event)\"\n (markAsRead)=\"dismissUnread($event)\"\n (togglePin)=\"togglePin($event)\"\n (closePopover)=\"closePopover.emit()\"\n />\n }\n }\n </div>\n <div class=\"axp-in-app-inbox-panel__footer\">\n <ax-button\n class=\"ax-sm\"\n [disabled]=\"(tabItems()[0]?.count ?? 0) === 0\"\n look=\"outline\"\n color=\"default\"\n [text]=\"(i18n.markAllAsRead | translate | async) ?? ''\"\n (onClick)=\"markAllAsRead()\"\n />\n <ax-button\n class=\"ax-sm\"\n look=\"outline\"\n color=\"primary\"\n [text]=\"(i18n.viewAll | translate | async) ?? ''\"\n (onClick)=\"viewAll()\"\n />\n </div>\n </ax-content>\n </ax-tab-item>\n }\n</ax-tabs>\n\n<ng-template [axTabContent] #tabContent=\"axTabContent\"></ng-template>\n", styles: ["@reference \"@acorex/styles/themes/default.css\";.axp-in-app-inbox-panel__header{@apply p-4 flex justify-between items-center;}.axp-in-app-inbox-panel__title{@apply text-xl font-semibold;color:rgb(var(--ax-sys-color-on-surface))}.axp-in-app-inbox-panel__list{@apply max-h-[50vh] md:w-[32rem] overflow-y-auto flex flex-col;}.axp-in-app-inbox-panel__footer{@apply flex gap-4 justify-between p-4 border-t;border-color:rgb(var(--ax-sys-color-border-surface))}.axp-in-app-inbox-panel__loading{@apply p-2 space-y-2;}.axp-in-app-inbox-panel__skeleton{@apply flex gap-4 p-4 animate-pulse;}.axp-in-app-inbox-panel__skeleton-avatar{@apply w-12 h-12 rounded-full shrink-0;background:rgb(var(--ax-sys-color-lighter-surface))}.axp-in-app-inbox-panel__skeleton-lines{@apply flex-1 space-y-2 py-1;}.axp-in-app-inbox-panel__skeleton-line{@apply h-3 rounded-md;background:rgb(var(--ax-sys-color-lighter-surface))}.axp-in-app-inbox-panel__skeleton-line.--wide{@apply w-3/4;}.axp-in-app-inbox-panel__skeleton-line:not(.--wide){@apply w-1/2;}\n"] }]
|
|
1531
|
+
}], ctorParameters: () => [], propDecorators: { unreadCountChange: [{ type: i0.Output, args: ["unreadCountChange"] }], closePopover: [{ type: i0.Output, args: ["closePopover"] }] } });
|
|
1532
|
+
|
|
1533
|
+
//#region ---- Shared in-app inbox header slot ----
|
|
1534
|
+
class AXPInAppInboxSlotComponent {
|
|
1535
|
+
constructor() {
|
|
1536
|
+
this.config = inject(AXP_IN_APP_INBOX_CONFIG);
|
|
1537
|
+
this.i18n = inject(AXP_IN_APP_INBOX_I18N);
|
|
1538
|
+
this.connector = inject(AXPInAppInboxConnectorService);
|
|
1539
|
+
this.syncStatus = inject(AXP_IN_APP_INBOX_SYNC_STATUS, { optional: true });
|
|
1540
|
+
this.liveUpdatesOffline = computed(() => this.syncStatus != null && !this.syncStatus.liveUpdatesConnected(), /* @ts-ignore */
|
|
1541
|
+
...(ngDevMode ? [{ debugName: "liveUpdatesOffline" }] : /* istanbul ignore next */ []));
|
|
1542
|
+
this.badgeDisplay = computed(() => {
|
|
1543
|
+
const total = this.connector.unreadCount();
|
|
1544
|
+
if (total <= 0) {
|
|
1545
|
+
return '';
|
|
1546
|
+
}
|
|
1547
|
+
return total > 50 ? '50+' : total.toString();
|
|
1548
|
+
}, /* @ts-ignore */
|
|
1549
|
+
...(ngDevMode ? [{ debugName: "badgeDisplay" }] : /* istanbul ignore next */ []));
|
|
1550
|
+
this.popover = viewChild(AXPopoverComponent, /* @ts-ignore */
|
|
1551
|
+
...(ngDevMode ? [{ debugName: "popover" }] : /* istanbul ignore next */ []));
|
|
1552
|
+
}
|
|
1553
|
+
closePopover() {
|
|
1554
|
+
this.popover()?.close();
|
|
1555
|
+
}
|
|
1556
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxSlotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1557
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPInAppInboxSlotComponent, isStandalone: true, selector: "axp-in-app-inbox-slot", viewQueries: [{ propertyName: "popover", first: true, predicate: AXPopoverComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<ax-button\n [iconOnly]=\"true\"\n class=\"relative axp-in-app-inbox-slot__button\"\n color=\"primary\"\n #inboxTrigger\n [title]=\"liveUpdatesOffline() ? ((i18n.liveUpdatesOffline | translate | async) ?? '') : ''\"\n>\n <ax-icon>\n <i [class]=\"config.headerIconClass\"></i>\n </ax-icon>\n</ax-button>\n\n<div\n class=\"axp-in-app-inbox-slot__badge\"\n [class.--xs]=\"badgeDisplay().length > 2\"\n>\n @if (badgeDisplay()) {\n <ax-badge color=\"danger\" [text]=\"badgeDisplay()\"></ax-badge>\n }\n</div>\n<ax-popover\n [target]=\"inboxTrigger\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n [adaptivityEnabled]=\"true\"\n>\n <div class=\"bg-lightest rounded-md w-full\">\n <axp-in-app-inbox-panel (closePopover)=\"closePopover()\" />\n </div>\n</ax-popover>\n", styles: ["@reference \"@acorex/styles/themes/default.css\";axp-in-app-inbox-slot{@apply relative;}axp-in-app-inbox-slot .axp-in-app-inbox-slot__badge{@apply absolute top-[-.25rem] end-[-.25rem];pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i4$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i4$2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "visualContextScope", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPInAppInboxPanelComponent, selector: "axp-in-app-inbox-panel", outputs: ["unreadCountChange", "closePopover"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1558
|
+
}
|
|
1559
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPInAppInboxSlotComponent, decorators: [{
|
|
1560
|
+
type: Component,
|
|
1561
|
+
args: [{ selector: 'axp-in-app-inbox-slot', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
|
|
1562
|
+
AsyncPipe,
|
|
1563
|
+
AXButtonModule,
|
|
1564
|
+
AXDecoratorModule,
|
|
1565
|
+
AXBadgeModule,
|
|
1566
|
+
AXPopoverModule,
|
|
1567
|
+
AXTranslationModule,
|
|
1568
|
+
AXPInAppInboxPanelComponent,
|
|
1569
|
+
], template: "<ax-button\n [iconOnly]=\"true\"\n class=\"relative axp-in-app-inbox-slot__button\"\n color=\"primary\"\n #inboxTrigger\n [title]=\"liveUpdatesOffline() ? ((i18n.liveUpdatesOffline | translate | async) ?? '') : ''\"\n>\n <ax-icon>\n <i [class]=\"config.headerIconClass\"></i>\n </ax-icon>\n</ax-button>\n\n<div\n class=\"axp-in-app-inbox-slot__badge\"\n [class.--xs]=\"badgeDisplay().length > 2\"\n>\n @if (badgeDisplay()) {\n <ax-badge color=\"danger\" [text]=\"badgeDisplay()\"></ax-badge>\n }\n</div>\n<ax-popover\n [target]=\"inboxTrigger\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n [adaptivityEnabled]=\"true\"\n>\n <div class=\"bg-lightest rounded-md w-full\">\n <axp-in-app-inbox-panel (closePopover)=\"closePopover()\" />\n </div>\n</ax-popover>\n", styles: ["@reference \"@acorex/styles/themes/default.css\";axp-in-app-inbox-slot{@apply relative;}axp-in-app-inbox-slot .axp-in-app-inbox-slot__badge{@apply absolute top-[-.25rem] end-[-.25rem];pointer-events:none}\n"] }]
|
|
1570
|
+
}], propDecorators: { popover: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPopoverComponent), { isSignal: true }] }] } });
|
|
1571
|
+
|
|
1572
|
+
const I18N$2 = '@communication-management:settings.user-notifications';
|
|
1573
|
+
//#region ---- User notification preferences settings ----
|
|
1574
|
+
class AXMCommunicationUserNotificationsSettingProvider {
|
|
1575
|
+
async provide(context) {
|
|
1576
|
+
context
|
|
1577
|
+
.addGroup(AXP_COMMUNICATION_USER_NOTIFICATIONS_SETTINGS_GROUP, `${I18N$2}.nav-title`, `${I18N$2}.description`, RootConfig$1.module.icon, `${I18N$2}.title`, 88)
|
|
1578
|
+
.addSection(AXP_COMMUNICATION_DELIVERY_CHANNELS_SETTINGS_SECTION, `${I18N$2}.delivery-channels.title`, `${I18N$2}.delivery-channels.description`)
|
|
1579
|
+
.addSetting({
|
|
1580
|
+
key: AXPCommunicationManagementSettingKeys.UserChannelInAppEnabled,
|
|
1581
|
+
title: `${I18N$2}.delivery-channels.in-app.title`,
|
|
1582
|
+
scope: 'U',
|
|
1583
|
+
overridableAt: [],
|
|
1584
|
+
isInherited: true,
|
|
1585
|
+
defaultValue: AXP_COMMUNICATION_USER_NOTIFICATION_DEFAULTS[AXPCommunicationManagementSettingKeys.UserChannelInAppEnabled],
|
|
1586
|
+
widget: { type: AXPWidgetsList.Editors.ToggleSwitch },
|
|
1587
|
+
description: `${I18N$2}.delivery-channels.in-app.description`,
|
|
1588
|
+
})
|
|
1589
|
+
.addSetting({
|
|
1590
|
+
key: AXPCommunicationManagementSettingKeys.UserChannelEmailEnabled,
|
|
1591
|
+
title: `${I18N$2}.delivery-channels.email.title`,
|
|
1592
|
+
scope: 'U',
|
|
1593
|
+
overridableAt: [],
|
|
1594
|
+
isInherited: true,
|
|
1595
|
+
defaultValue: AXP_COMMUNICATION_USER_NOTIFICATION_DEFAULTS[AXPCommunicationManagementSettingKeys.UserChannelEmailEnabled],
|
|
1596
|
+
widget: { type: AXPWidgetsList.Editors.ToggleSwitch },
|
|
1597
|
+
description: `${I18N$2}.delivery-channels.email.description`,
|
|
1598
|
+
})
|
|
1599
|
+
.endSection()
|
|
1600
|
+
.endGroup();
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
//#endregion
|
|
1604
|
+
|
|
1605
|
+
const CommunicationManagementManifest = {
|
|
1606
|
+
name: RootConfig.module.name,
|
|
1607
|
+
version: '0.0.1',
|
|
1608
|
+
title: RootConfig.module.title,
|
|
1609
|
+
icon: RootConfig.module.icon,
|
|
1610
|
+
i18n: RootConfig.config.i18n,
|
|
1611
|
+
type: 'domain',
|
|
1612
|
+
domain: 'communication',
|
|
1613
|
+
required: false,
|
|
1614
|
+
};
|
|
1615
|
+
|
|
1616
|
+
class AXMCommunicationManagementMenuProvider {
|
|
1617
|
+
constructor() {
|
|
1618
|
+
this.entityService = inject(AXPEntityService);
|
|
1619
|
+
}
|
|
1620
|
+
async provide(context) {
|
|
1621
|
+
const module = RootConfig.module.name;
|
|
1622
|
+
const monitoringMenu = context.find(AXPCommonMenuKeys.Monitoring);
|
|
1623
|
+
if (!monitoringMenu.exists) {
|
|
1624
|
+
context.find(AXPCommonMenuKeys.Administration).addItems([
|
|
1625
|
+
{
|
|
1626
|
+
name: AXPCommonMenuKeys.Monitoring,
|
|
1627
|
+
priority: 12,
|
|
1628
|
+
text: '@general:menus.monitoring.title',
|
|
1629
|
+
icon: 'fa-light fa-chart-line',
|
|
1630
|
+
type: 'menu',
|
|
1631
|
+
children: [],
|
|
1632
|
+
},
|
|
1633
|
+
]);
|
|
1634
|
+
}
|
|
1635
|
+
context.find(AXPCommonMenuKeys.Monitoring).addItems([
|
|
1636
|
+
{
|
|
1637
|
+
name: AXMCommunicationManagementMenuKeys.Communications,
|
|
1638
|
+
text: RootConfig.entities.communication.titlePlural,
|
|
1639
|
+
path: this.entityService.createPath(module, RootConfig.entities.communication.name),
|
|
1640
|
+
icon: RootConfig.entities.communication.icon,
|
|
1641
|
+
priority: 1,
|
|
1642
|
+
policy: {
|
|
1643
|
+
features: [module],
|
|
1644
|
+
permissions: [AXPCollaborationPermissionKeys.MaintainCommunications],
|
|
1645
|
+
},
|
|
1646
|
+
},
|
|
1647
|
+
]);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
//#endregion
|
|
1652
|
+
//#region ----- Permission Definition Provider -----
|
|
1653
|
+
/**
|
|
1654
|
+
* Registers communication capabilities into the shared Collaboration group.
|
|
1655
|
+
*/
|
|
1656
|
+
class AXMCommunicationManagementPermissionDefinitionProvider {
|
|
1657
|
+
async define(context) {
|
|
1658
|
+
const keys = AXPCollaborationPermissionKeys;
|
|
1659
|
+
const groups = AXPCommonPermissionGroupKeys;
|
|
1660
|
+
const P = '@common:collaboration.permissions';
|
|
1661
|
+
const G = '@common:permission-groups';
|
|
1662
|
+
context.addGroup(groups.Collaboration.Root, `${G}.collaboration.title`, `${G}.collaboration.description`, { order: 80 });
|
|
1663
|
+
context
|
|
1664
|
+
.addGroup(groups.Collaboration.Communications, `${G}.collaboration-communications.title`, `${G}.collaboration-communications.description`, { parent: groups.Collaboration.Root, order: 30 })
|
|
1665
|
+
.addPermission(keys.MaintainCommunications, `${P}.maintain-communications.title`, `${P}.maintain-communications.description`)
|
|
1666
|
+
.endPermission()
|
|
1667
|
+
.endGroup();
|
|
1668
|
+
}
|
|
1669
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementPermissionDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1670
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementPermissionDefinitionProvider }); }
|
|
1671
|
+
}
|
|
1672
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementPermissionDefinitionProvider, decorators: [{
|
|
1673
|
+
type: Injectable
|
|
1674
|
+
}] });
|
|
1675
|
+
|
|
1676
|
+
class AXMCommunicationManagementSearchCommandProvider extends AXPSearchCommandProvider {
|
|
1677
|
+
constructor() {
|
|
1678
|
+
super(...arguments);
|
|
1679
|
+
this.commands = [];
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
const I18N$1 = '@communication-management:settings.communication';
|
|
1684
|
+
const DEV_TOOLS_I18N = '@platform-dev-tools:settings.communication-debug-redirect';
|
|
1685
|
+
/** SMTP is server-owned config — never persist to client IndexedDB. */
|
|
1686
|
+
const SMTP_CLIENT_CACHE = {
|
|
1687
|
+
cacheable: false,
|
|
1688
|
+
};
|
|
1689
|
+
class AXMCommunicationManagementSettingProvider {
|
|
1690
|
+
async provide(context) {
|
|
1691
|
+
context
|
|
1692
|
+
.addGroup('communication', `${I18N$1}.nav-title`, `${I18N$1}.description`, RootConfig$1.module.icon, `${I18N$1}.title`, 96)
|
|
1693
|
+
.addSection('smtp-settings', `${I18N$1}.smtp.title`, `${I18N$1}.smtp.description`)
|
|
1694
|
+
.addSetting({
|
|
1695
|
+
key: AXPCommunicationManagementSettingKeys.EmailServer,
|
|
1696
|
+
title: `${I18N$1}.smtp.server.title`,
|
|
1697
|
+
scope: 'P',
|
|
1698
|
+
overridableAt: ['T'],
|
|
1699
|
+
// Platform-owned SMTP baseline (same pattern as System Insight / Auth).
|
|
1700
|
+
// Tenants may still override via overridableAt; runtime inherits parent when unset.
|
|
1701
|
+
isInherited: false,
|
|
1702
|
+
...SMTP_CLIENT_CACHE,
|
|
1703
|
+
defaultValue: AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS[AXPCommunicationManagementSettingKeys.EmailServer],
|
|
1704
|
+
widget: {
|
|
1705
|
+
type: AXPWidgetsList.Editors.TextBox,
|
|
1706
|
+
},
|
|
1707
|
+
description: `${I18N$1}.smtp.server.description`,
|
|
1708
|
+
})
|
|
1709
|
+
.addSetting({
|
|
1710
|
+
key: AXPCommunicationManagementSettingKeys.EmailPort,
|
|
1711
|
+
title: `${I18N$1}.smtp.port.title`,
|
|
1712
|
+
scope: 'P',
|
|
1713
|
+
overridableAt: ['T'],
|
|
1714
|
+
isInherited: false,
|
|
1715
|
+
...SMTP_CLIENT_CACHE,
|
|
1716
|
+
defaultValue: AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS[AXPCommunicationManagementSettingKeys.EmailPort],
|
|
1717
|
+
widget: {
|
|
1718
|
+
type: AXPWidgetsList.Editors.NumberBox,
|
|
1719
|
+
options: {
|
|
1720
|
+
minValue: 1,
|
|
1721
|
+
maxValue: 65535,
|
|
1722
|
+
},
|
|
1723
|
+
},
|
|
1724
|
+
description: `${I18N$1}.smtp.port.description`,
|
|
1725
|
+
})
|
|
1726
|
+
.addSetting({
|
|
1727
|
+
key: AXPCommunicationManagementSettingKeys.EmailUsername,
|
|
1728
|
+
title: `${I18N$1}.smtp.username.title`,
|
|
1729
|
+
scope: 'P',
|
|
1730
|
+
overridableAt: ['T'],
|
|
1731
|
+
isInherited: false,
|
|
1732
|
+
...SMTP_CLIENT_CACHE,
|
|
1733
|
+
defaultValue: AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS[AXPCommunicationManagementSettingKeys.EmailUsername],
|
|
1734
|
+
widget: {
|
|
1735
|
+
type: AXPWidgetsList.Editors.TextBox,
|
|
1736
|
+
},
|
|
1737
|
+
description: `${I18N$1}.smtp.username.description`,
|
|
1738
|
+
})
|
|
1739
|
+
.addSetting({
|
|
1740
|
+
key: AXPCommunicationManagementSettingKeys.EmailPassword,
|
|
1741
|
+
title: `${I18N$1}.smtp.password.title`,
|
|
1742
|
+
scope: 'P',
|
|
1743
|
+
overridableAt: ['T'],
|
|
1744
|
+
isInherited: false,
|
|
1745
|
+
// Server DB at-rest encryption; implies cacheable: false.
|
|
1746
|
+
isEncrypted: true,
|
|
1747
|
+
defaultValue: AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS[AXPCommunicationManagementSettingKeys.EmailPassword],
|
|
1748
|
+
widget: {
|
|
1749
|
+
type: AXPWidgetsList.Editors.PasswordBox,
|
|
1750
|
+
},
|
|
1751
|
+
description: `${I18N$1}.smtp.password.description`,
|
|
1752
|
+
})
|
|
1753
|
+
.addSetting({
|
|
1754
|
+
key: AXPCommunicationManagementSettingKeys.EmailFromAddress,
|
|
1755
|
+
title: `${I18N$1}.smtp.from-address.title`,
|
|
1756
|
+
scope: 'P',
|
|
1757
|
+
overridableAt: ['T'],
|
|
1758
|
+
isInherited: false,
|
|
1759
|
+
...SMTP_CLIENT_CACHE,
|
|
1760
|
+
defaultValue: AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS[AXPCommunicationManagementSettingKeys.EmailFromAddress],
|
|
1761
|
+
widget: {
|
|
1762
|
+
type: AXPWidgetsList.Editors.TextBox,
|
|
1763
|
+
},
|
|
1764
|
+
description: `${I18N$1}.smtp.from-address.description`,
|
|
1765
|
+
})
|
|
1766
|
+
.addSetting({
|
|
1767
|
+
key: AXPCommunicationManagementSettingKeys.EmailUseSsl,
|
|
1768
|
+
title: `${I18N$1}.smtp.ssl.title`,
|
|
1769
|
+
scope: 'P',
|
|
1770
|
+
overridableAt: ['T'],
|
|
1771
|
+
isInherited: false,
|
|
1772
|
+
...SMTP_CLIENT_CACHE,
|
|
1773
|
+
defaultValue: AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS[AXPCommunicationManagementSettingKeys.EmailUseSsl],
|
|
1774
|
+
widget: {
|
|
1775
|
+
type: AXPWidgetsList.Editors.ToggleSwitch,
|
|
1776
|
+
},
|
|
1777
|
+
description: `${I18N$1}.smtp.ssl.description`,
|
|
1778
|
+
})
|
|
1779
|
+
.addSetting({
|
|
1780
|
+
key: AXPCommunicationManagementSettingKeys.EmailUseTls,
|
|
1781
|
+
title: `${I18N$1}.smtp.tls.title`,
|
|
1782
|
+
scope: 'P',
|
|
1783
|
+
overridableAt: ['T'],
|
|
1784
|
+
isInherited: false,
|
|
1785
|
+
...SMTP_CLIENT_CACHE,
|
|
1786
|
+
defaultValue: AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS[AXPCommunicationManagementSettingKeys.EmailUseTls],
|
|
1787
|
+
widget: {
|
|
1788
|
+
type: AXPWidgetsList.Editors.ToggleSwitch,
|
|
1789
|
+
},
|
|
1790
|
+
description: `${I18N$1}.smtp.tls.description`,
|
|
1791
|
+
})
|
|
1792
|
+
.addAction({
|
|
1793
|
+
title: `${I18N$1}.smtp.test.action`,
|
|
1794
|
+
icon: 'fa-light fa-paper-plane',
|
|
1795
|
+
color: 'primary',
|
|
1796
|
+
look: 'outline',
|
|
1797
|
+
disabledWhenDirty: true,
|
|
1798
|
+
requiredSettingKeys: [
|
|
1799
|
+
AXPCommunicationManagementSettingKeys.EmailServer,
|
|
1800
|
+
AXPCommunicationManagementSettingKeys.EmailPort,
|
|
1801
|
+
AXPCommunicationManagementSettingKeys.EmailFromAddress,
|
|
1802
|
+
],
|
|
1803
|
+
command: {
|
|
1804
|
+
name: AXMCommunicationManagementCommandKeys.TestSmtp,
|
|
1805
|
+
},
|
|
1806
|
+
})
|
|
1807
|
+
.endSection()
|
|
1808
|
+
.endGroup();
|
|
1809
|
+
this.registerDevToolsRedirectSettings(context);
|
|
1810
|
+
}
|
|
1811
|
+
registerDevToolsRedirectSettings(context) {
|
|
1812
|
+
const section = resolveCommunicationDebugRedirectSection(context);
|
|
1813
|
+
if (!section) {
|
|
1814
|
+
return;
|
|
1815
|
+
}
|
|
1816
|
+
section
|
|
1817
|
+
.addSetting({
|
|
1818
|
+
key: AXPCommunicationManagementSettingKeys.DebugRedirectEmailAddress,
|
|
1819
|
+
title: `${DEV_TOOLS_I18N}.email.title`,
|
|
1820
|
+
scope: 'P',
|
|
1821
|
+
overridableAt: [],
|
|
1822
|
+
isInherited: false,
|
|
1823
|
+
defaultValue: AXP_COMMUNICATION_SMTP_SETTING_DEFAULTS[AXPCommunicationManagementSettingKeys.DebugRedirectEmailAddress],
|
|
1824
|
+
widget: {
|
|
1825
|
+
type: AXPWidgetsList.Editors.TextBox,
|
|
1826
|
+
},
|
|
1827
|
+
description: `${DEV_TOOLS_I18N}.email.description`,
|
|
1828
|
+
})
|
|
1829
|
+
.endSection();
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
function resolveCommunicationDebugRedirectSection(context) {
|
|
1833
|
+
const devTools = context.group(AXP_PLATFORM_DEV_TOOLS_SETTINGS_GROUP);
|
|
1834
|
+
if (!devTools) {
|
|
1835
|
+
return null;
|
|
1836
|
+
}
|
|
1837
|
+
const hasSection = context
|
|
1838
|
+
.getGroup(AXP_PLATFORM_DEV_TOOLS_SETTINGS_GROUP)
|
|
1839
|
+
?.sections.some((section) => section.name === AXP_PLATFORM_DEV_TOOLS_COMMUNICATION_DEBUG_REDIRECT_SECTION);
|
|
1840
|
+
if (hasSection) {
|
|
1841
|
+
return devTools.section(AXP_PLATFORM_DEV_TOOLS_COMMUNICATION_DEBUG_REDIRECT_SECTION);
|
|
1842
|
+
}
|
|
1843
|
+
return devTools.addSection(AXP_PLATFORM_DEV_TOOLS_COMMUNICATION_DEBUG_REDIRECT_SECTION, `${DEV_TOOLS_I18N}.title`, `${DEV_TOOLS_I18N}.description`);
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
const I18N = `@${RootConfig$1.config.i18n}:templates.channels`;
|
|
1847
|
+
//#region ---- Built-in text template channels ----
|
|
1848
|
+
class AXMCommunicationTextTemplateChannelDefinitionProvider {
|
|
1849
|
+
getChannels() {
|
|
1850
|
+
return [
|
|
1851
|
+
{
|
|
1852
|
+
name: 'email',
|
|
1853
|
+
communicationChannelKey: 'email-smtp',
|
|
1854
|
+
title: `${I18N}.email`,
|
|
1855
|
+
type: 'rich',
|
|
1856
|
+
hasSubject: true,
|
|
1857
|
+
requiredSettingKeys: [
|
|
1858
|
+
AXPCommunicationManagementSettingKeys.EmailServer,
|
|
1859
|
+
AXPCommunicationManagementSettingKeys.EmailPort,
|
|
1860
|
+
AXPCommunicationManagementSettingKeys.EmailFromAddress,
|
|
1861
|
+
],
|
|
1862
|
+
notConfiguredMessageKey: `${I18N}.not-configured.email`,
|
|
1863
|
+
configureSettings: {
|
|
1864
|
+
group: 'communication',
|
|
1865
|
+
section: 'smtp-settings',
|
|
1866
|
+
scope: 'T',
|
|
1867
|
+
},
|
|
1868
|
+
},
|
|
1869
|
+
{
|
|
1870
|
+
name: 'in-app',
|
|
1871
|
+
communicationChannelKey: 'in-app',
|
|
1872
|
+
title: `${I18N}.in-app`,
|
|
1873
|
+
type: 'plain',
|
|
1874
|
+
hasSubject: true,
|
|
1875
|
+
},
|
|
1876
|
+
];
|
|
1877
|
+
}
|
|
1878
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationTextTemplateChannelDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1879
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationTextTemplateChannelDefinitionProvider }); }
|
|
1880
|
+
}
|
|
1881
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationTextTemplateChannelDefinitionProvider, decorators: [{
|
|
1882
|
+
type: Injectable
|
|
1883
|
+
}] });
|
|
1884
|
+
//#endregion
|
|
1885
|
+
const communicationTextTemplateChannelProvider = {
|
|
1886
|
+
provide: AXP_TEXT_TEMPLATE_CHANNEL_DEFINITION_PROVIDER,
|
|
1887
|
+
useClass: AXMCommunicationTextTemplateChannelDefinitionProvider,
|
|
1888
|
+
multi: true,
|
|
1889
|
+
};
|
|
1890
|
+
|
|
1891
|
+
//#region ---- Imports ----
|
|
1892
|
+
//#endregion
|
|
1893
|
+
//#region ---- Component ----
|
|
1894
|
+
class AXPCommunicationInAppInboxWidgetViewComponent extends AXPValueWidgetComponent {
|
|
1895
|
+
constructor() {
|
|
1896
|
+
super(...arguments);
|
|
1897
|
+
//#region ----- Services & Dependencies -----
|
|
1898
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
1899
|
+
this.connector = inject(AXPInAppInboxConnectorService);
|
|
1900
|
+
this.inboxActions = inject(AXPInAppInboxActionService);
|
|
1901
|
+
this.i18n = inject(AXP_IN_APP_INBOX_I18N);
|
|
1902
|
+
//#endregion
|
|
1903
|
+
//#region ----- Computed Properties -----
|
|
1904
|
+
this.maxItems = computed(() => this.options()?.['maxItems'] ?? 10, /* @ts-ignore */
|
|
1905
|
+
...(ngDevMode ? [{ debugName: "maxItems" }] : /* istanbul ignore next */ []));
|
|
1906
|
+
this.showAvatar = computed(() => this.options()?.['showAvatar'] ?? true, /* @ts-ignore */
|
|
1907
|
+
...(ngDevMode ? [{ debugName: "showAvatar" }] : /* istanbul ignore next */ []));
|
|
1908
|
+
this.showDate = computed(() => this.options()?.['showDate'] ?? true, /* @ts-ignore */
|
|
1909
|
+
...(ngDevMode ? [{ debugName: "showDate" }] : /* istanbul ignore next */ []));
|
|
1910
|
+
this.inboxItems = computed(() => {
|
|
1911
|
+
const items = this.connector.inboxList();
|
|
1912
|
+
if (!items?.length) {
|
|
1913
|
+
return [];
|
|
1914
|
+
}
|
|
1915
|
+
return items.filter((item) => isInAppInboxUnread(item.readAt)).slice(0, this.maxItems());
|
|
1916
|
+
}, /* @ts-ignore */
|
|
1917
|
+
...(ngDevMode ? [{ debugName: "inboxItems" }] : /* istanbul ignore next */ []));
|
|
1918
|
+
}
|
|
1919
|
+
//#endregion
|
|
1920
|
+
//#region ----- Lifecycle -----
|
|
1921
|
+
ngOnInit() {
|
|
1922
|
+
super.ngOnInit();
|
|
1923
|
+
void this.connector.ensureReady().then(() => this.cdr.detectChanges());
|
|
1924
|
+
}
|
|
1925
|
+
//#endregion
|
|
1926
|
+
//#region ----- Event Handlers -----
|
|
1927
|
+
async onItemPress(id) {
|
|
1928
|
+
await this.inboxActions.openItem(id);
|
|
1929
|
+
this.cdr.detectChanges();
|
|
1930
|
+
}
|
|
1931
|
+
async onDismissUnread(id) {
|
|
1932
|
+
await this.connector.markAsRead([id]);
|
|
1933
|
+
this.cdr.detectChanges();
|
|
1934
|
+
}
|
|
1935
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPCommunicationInAppInboxWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
1936
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPCommunicationInAppInboxWidgetViewComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: "<div class=\"size-full p-3 flex flex-col min-h-0\">\n <div class=\"overflow-auto flex-1 min-h-0 flex flex-col\">\n @for (item of inboxItems(); track item.id) {\n <axp-in-app-inbox-item\n [data]=\"item\"\n [showAvatar]=\"showAvatar()\"\n [showDate]=\"showDate()\"\n [markAsReadLabelKey]=\"i18n.markAsRead\"\n (itemPress)=\"onItemPress($event)\"\n (markAsRead)=\"onDismissUnread($event)\"\n />\n } @empty {\n <axp-state-message\n icon=\"fa-light fa-inbox\"\n [title]=\"i18n.emptyTitle\"\n [description]=\"i18n.emptyDescription\"\n />\n }\n </div>\n</div>\n", styles: ["@reference \"@acorex/styles/themes/default.css\";:host{@apply block size-full;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPInAppInboxItemComponent, selector: "axp-in-app-inbox-item", inputs: ["data", "showAvatar", "showDate", "showPin", "pinLabelKey", "unpinLabelKey", "highlightUnreadBackground", "showDismissUnread", "markAsReadLabelKey"], outputs: ["itemPress", "markAsRead", "togglePin", "closePopover"] }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1937
|
+
}
|
|
1938
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPCommunicationInAppInboxWidgetViewComponent, decorators: [{
|
|
1939
|
+
type: Component,
|
|
1940
|
+
args: [{ standalone: true, imports: [
|
|
1941
|
+
CommonModule,
|
|
1942
|
+
AXTranslationModule,
|
|
1943
|
+
AXPInAppInboxItemComponent,
|
|
1944
|
+
AXPStateMessageComponent,
|
|
1945
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"size-full p-3 flex flex-col min-h-0\">\n <div class=\"overflow-auto flex-1 min-h-0 flex flex-col\">\n @for (item of inboxItems(); track item.id) {\n <axp-in-app-inbox-item\n [data]=\"item\"\n [showAvatar]=\"showAvatar()\"\n [showDate]=\"showDate()\"\n [markAsReadLabelKey]=\"i18n.markAsRead\"\n (itemPress)=\"onItemPress($event)\"\n (markAsRead)=\"onDismissUnread($event)\"\n />\n } @empty {\n <axp-state-message\n icon=\"fa-light fa-inbox\"\n [title]=\"i18n.emptyTitle\"\n [description]=\"i18n.emptyDescription\"\n />\n }\n </div>\n</div>\n", styles: ["@reference \"@acorex/styles/themes/default.css\";:host{@apply block size-full;}\n"] }]
|
|
1946
|
+
}] });
|
|
1947
|
+
|
|
1948
|
+
var communicationInAppInboxWidget_component = /*#__PURE__*/Object.freeze({
|
|
1949
|
+
__proto__: null,
|
|
1950
|
+
AXPCommunicationInAppInboxWidgetViewComponent: AXPCommunicationInAppInboxWidgetViewComponent
|
|
1951
|
+
});
|
|
1952
|
+
|
|
1953
|
+
//#region ----- Imports -----
|
|
1954
|
+
//#endregion
|
|
1955
|
+
//#region ----- Communication dashboard presets -----
|
|
1956
|
+
/** Unread in-app inbox dashboard tile. */
|
|
1957
|
+
const AXP_MY_IN_APP_INBOX_DASHBOARD_DIMENSIONS = defineDashboardWidgetDimensions({
|
|
1958
|
+
sm: [[1, 5]],
|
|
1959
|
+
md: [
|
|
1960
|
+
[3, 4],
|
|
1961
|
+
[4, 4],
|
|
1962
|
+
],
|
|
1963
|
+
lg: [
|
|
1964
|
+
[3, 4],
|
|
1965
|
+
[4, 4],
|
|
1966
|
+
],
|
|
1967
|
+
xl: [
|
|
1968
|
+
[3, 4],
|
|
1969
|
+
[4, 4],
|
|
1970
|
+
],
|
|
1971
|
+
'2xl': [
|
|
1972
|
+
[3, 4],
|
|
1973
|
+
[4, 4],
|
|
1974
|
+
],
|
|
1975
|
+
'3xl': [
|
|
1976
|
+
[3, 4],
|
|
1977
|
+
[4, 4],
|
|
1978
|
+
],
|
|
1979
|
+
'4xl': [
|
|
1980
|
+
[3, 4],
|
|
1981
|
+
[4, 4],
|
|
1982
|
+
],
|
|
1983
|
+
});
|
|
1984
|
+
//#endregion
|
|
1985
|
+
|
|
1986
|
+
//#region ---- My in-app inbox dashboard widget config ----
|
|
1987
|
+
const AXPMyInAppInboxDashboardWidget = {
|
|
1988
|
+
name: RootConfig.widgets.myInAppInboxDashboard,
|
|
1989
|
+
title: '@communication-management:widgets.my-in-app-inbox-dashboard.widget-title',
|
|
1990
|
+
categories: [AXP_WIDGETS_UTILITY_CATEGORY],
|
|
1991
|
+
groups: [AXPWidgetGroupEnum.DashboardWidget],
|
|
1992
|
+
type: 'dashboard',
|
|
1993
|
+
description: '@communication-management:widgets.my-in-app-inbox-dashboard.widget-description',
|
|
1994
|
+
icon: 'fa-regular fa-inbox',
|
|
1995
|
+
properties: [
|
|
1996
|
+
cloneProperty(AXP_DATA_PATH_PROPERTY, { visible: false }),
|
|
1997
|
+
{
|
|
1998
|
+
name: 'maxItems',
|
|
1999
|
+
title: '@communication-management:widgets.my-in-app-inbox-dashboard.max-items',
|
|
2000
|
+
description: 'Maximum number of unread inbox items to display',
|
|
2001
|
+
group: AXP_STYLING_PROPERTY_GROUP,
|
|
2002
|
+
schema: {
|
|
2003
|
+
defaultValue: 10,
|
|
2004
|
+
dataType: 'number',
|
|
2005
|
+
interface: {
|
|
2006
|
+
name: 'maxItems',
|
|
2007
|
+
path: 'options.maxItems',
|
|
2008
|
+
type: AXPWidgetsCatalog.number,
|
|
2009
|
+
options: {
|
|
2010
|
+
minValue: 1,
|
|
2011
|
+
maxValue: 100,
|
|
2012
|
+
},
|
|
2013
|
+
},
|
|
2014
|
+
},
|
|
2015
|
+
visible: true,
|
|
2016
|
+
},
|
|
2017
|
+
{
|
|
2018
|
+
name: 'showAvatar',
|
|
2019
|
+
title: '@communication-management:widgets.my-in-app-inbox-dashboard.show-avatar',
|
|
2020
|
+
description: 'Whether to show avatars in inbox items',
|
|
2021
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
|
2022
|
+
schema: {
|
|
2023
|
+
defaultValue: true,
|
|
2024
|
+
dataType: 'boolean',
|
|
2025
|
+
interface: {
|
|
2026
|
+
name: 'showAvatar',
|
|
2027
|
+
path: 'options.showAvatar',
|
|
2028
|
+
type: AXPWidgetsCatalog.toggle,
|
|
2029
|
+
},
|
|
2030
|
+
},
|
|
2031
|
+
visible: true,
|
|
2032
|
+
},
|
|
2033
|
+
{
|
|
2034
|
+
name: 'showDate',
|
|
2035
|
+
title: '@communication-management:widgets.my-in-app-inbox-dashboard.show-date',
|
|
2036
|
+
description: 'Whether to show date in inbox items',
|
|
2037
|
+
group: AXP_APPEARANCE_PROPERTY_GROUP,
|
|
2038
|
+
schema: {
|
|
2039
|
+
defaultValue: true,
|
|
2040
|
+
dataType: 'boolean',
|
|
2041
|
+
interface: {
|
|
2042
|
+
name: 'showDate',
|
|
2043
|
+
path: 'options.showDate',
|
|
2044
|
+
type: AXPWidgetsCatalog.toggle,
|
|
2045
|
+
},
|
|
2046
|
+
},
|
|
2047
|
+
visible: true,
|
|
2048
|
+
},
|
|
2049
|
+
],
|
|
2050
|
+
components: {
|
|
2051
|
+
view: {
|
|
2052
|
+
component: () => Promise.resolve().then(function () { return communicationInAppInboxWidget_component; }).then((c) => c.AXPCommunicationInAppInboxWidgetViewComponent),
|
|
2053
|
+
},
|
|
2054
|
+
},
|
|
2055
|
+
meta: {
|
|
2056
|
+
dimensions: AXP_MY_IN_APP_INBOX_DASHBOARD_DIMENSIONS,
|
|
2057
|
+
},
|
|
2058
|
+
};
|
|
2059
|
+
//#endregion
|
|
2060
|
+
|
|
2061
|
+
//#endregion
|
|
2062
|
+
//#region ---- Communication Management Widgets Provider ----
|
|
2063
|
+
class AXMCommunicationManagementWidgetsProvider {
|
|
2064
|
+
getWidgets() {
|
|
2065
|
+
return [AXPMyInAppInboxDashboardWidget];
|
|
2066
|
+
}
|
|
2067
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementWidgetsProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2068
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementWidgetsProvider }); }
|
|
2069
|
+
}
|
|
2070
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementWidgetsProvider, decorators: [{
|
|
2071
|
+
type: Injectable
|
|
2072
|
+
}] });
|
|
2073
|
+
|
|
2074
|
+
/** @deprecated Legacy notification-management command keys — shimmed to communication email commands. */
|
|
2075
|
+
const LEGACY_NOTIFICATION_EMAIL_SHOW_DIALOG_COMMAND_KEY = 'NotificationManagement:Email:ShowDialog';
|
|
2076
|
+
const LEGACY_NOTIFICATION_EMAIL_SEND_COMMAND_KEY = 'NotificationManagement:Email:Send';
|
|
2077
|
+
function routesFactory() {
|
|
2078
|
+
return [
|
|
2079
|
+
{
|
|
2080
|
+
path: ':app/my/notification',
|
|
2081
|
+
canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
|
|
2082
|
+
data: { rootLayout: true },
|
|
2083
|
+
loadComponent: () => AXPRootLayoutComponent,
|
|
2084
|
+
title: 'Notifications',
|
|
2085
|
+
children: [
|
|
2086
|
+
{
|
|
2087
|
+
path: '',
|
|
2088
|
+
loadComponent: () => import('./acorex-platform-module-communication-management-client-communication-in-app-inbox-page.component-b7ZqkMTt.mjs').then((m) => m.AXMCommunicationInAppInboxPageComponent),
|
|
2089
|
+
data: { reuse: true },
|
|
2090
|
+
},
|
|
2091
|
+
],
|
|
2092
|
+
},
|
|
2093
|
+
];
|
|
2094
|
+
}
|
|
2095
|
+
class AXMCommunicationManagementModule {
|
|
2096
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
2097
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementModule, imports: [i1$2.AXPComponentSlotModule] }); }
|
|
2098
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementModule, providers: [
|
|
2099
|
+
provideCommandSetups([
|
|
2100
|
+
{
|
|
2101
|
+
key: AXMCommunicationManagementCommandKeys$1.Send,
|
|
2102
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-send.command-D7_MmGQe.mjs').then((m) => m.CommunicationSendCommand),
|
|
2103
|
+
},
|
|
2104
|
+
{
|
|
2105
|
+
key: AXMCommunicationManagementCommandKeys$1.TestSmtp,
|
|
2106
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-test-smtp.command-BySmN1Lz.mjs').then((m) => m.CommunicationTestSmtpCommand),
|
|
2107
|
+
},
|
|
2108
|
+
{
|
|
2109
|
+
key: AXMCommunicationManagementCommandKeys$1.EmailShowDialog,
|
|
2110
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-email-show-dialog.command-CP0zAEe4.mjs').then((m) => m.CommunicationManagementEmailShowDialogCommand),
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
key: AXMCommunicationManagementCommandKeys$1.EmailSend,
|
|
2114
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-email-send.command-wuqLiY8s.mjs').then((m) => m.CommunicationManagementEmailSendCommand),
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
key: AXMCommunicationManagementCommandKeys$1.ShowSentMessage,
|
|
2118
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-show-sent-message.command-D8125Jxi.mjs').then((m) => m.CommunicationShowSentMessageCommand),
|
|
2119
|
+
},
|
|
2120
|
+
{
|
|
2121
|
+
key: LEGACY_NOTIFICATION_EMAIL_SHOW_DIALOG_COMMAND_KEY,
|
|
2122
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-email-show-dialog.command-CP0zAEe4.mjs').then((m) => m.CommunicationManagementEmailShowDialogCommand),
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
key: LEGACY_NOTIFICATION_EMAIL_SEND_COMMAND_KEY,
|
|
2126
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-email-send.command-wuqLiY8s.mjs').then((m) => m.CommunicationManagementEmailSendCommand),
|
|
2127
|
+
},
|
|
2128
|
+
]),
|
|
2129
|
+
{
|
|
2130
|
+
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
2131
|
+
useValue: CommunicationManagementManifest,
|
|
2132
|
+
multi: true,
|
|
2133
|
+
},
|
|
2134
|
+
{
|
|
2135
|
+
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
2136
|
+
useClass: AXMCommunicationManagementPermissionDefinitionProvider,
|
|
2137
|
+
multi: true,
|
|
2138
|
+
},
|
|
2139
|
+
{
|
|
2140
|
+
provide: AXP_MENU_PROVIDER,
|
|
2141
|
+
useClass: AXMCommunicationManagementMenuProvider,
|
|
2142
|
+
multi: true,
|
|
2143
|
+
},
|
|
2144
|
+
{
|
|
2145
|
+
provide: AXP_STATUS_PROVIDERS,
|
|
2146
|
+
useClass: AXMCommunicationStatusProvider,
|
|
2147
|
+
multi: true,
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
provide: AXP_STATUS_PROVIDERS,
|
|
2151
|
+
useClass: AXMCommunicationDeliveryStatusProvider,
|
|
2152
|
+
multi: true,
|
|
2153
|
+
},
|
|
2154
|
+
{
|
|
2155
|
+
provide: AXP_SEARCH_PROVIDER,
|
|
2156
|
+
useClass: AXMCommunicationManagementSearchCommandProvider,
|
|
2157
|
+
multi: true,
|
|
2158
|
+
},
|
|
2159
|
+
{
|
|
2160
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
2161
|
+
useClass: AXMCommunicationManagementSettingProvider,
|
|
2162
|
+
multi: true,
|
|
2163
|
+
},
|
|
2164
|
+
{
|
|
2165
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
2166
|
+
useClass: AXMCommunicationUserNotificationsSettingProvider,
|
|
2167
|
+
multi: true,
|
|
2168
|
+
},
|
|
2169
|
+
communicationTextTemplateChannelProvider,
|
|
2170
|
+
{
|
|
2171
|
+
provide: AXP_WIDGET_DEFINITION_PROVIDER,
|
|
2172
|
+
useClass: AXMCommunicationManagementWidgetsProvider,
|
|
2173
|
+
multi: true,
|
|
2174
|
+
},
|
|
2175
|
+
{
|
|
2176
|
+
provide: AXP_IN_APP_INBOX_PORT,
|
|
2177
|
+
useClass: AXMCommunicationInAppInboxPort,
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
provide: AXP_IN_APP_INBOX_CONFIG,
|
|
2181
|
+
useValue: communicationInAppInboxConfig,
|
|
2182
|
+
},
|
|
2183
|
+
{
|
|
2184
|
+
provide: AXP_IN_APP_INBOX_I18N,
|
|
2185
|
+
useValue: communicationInAppInboxI18n,
|
|
2186
|
+
},
|
|
2187
|
+
{
|
|
2188
|
+
provide: AXP_IN_APP_INBOX_SYNC_STATUS,
|
|
2189
|
+
useExisting: AXMCommunicationInAppInboxSyncStatusService,
|
|
2190
|
+
},
|
|
2191
|
+
communicationInAppNotificationServiceProvider,
|
|
2192
|
+
{
|
|
2193
|
+
provide: AXP_TASK_BADGE_PROVIDERS,
|
|
2194
|
+
useClass: AXMCommunicationInboxBadgeProvider,
|
|
2195
|
+
multi: true,
|
|
2196
|
+
},
|
|
2197
|
+
...provideCommunicationInAppRealtimeHandlers(),
|
|
2198
|
+
...provideCommunicationInAppInboxFallbackSync(),
|
|
2199
|
+
{
|
|
2200
|
+
provide: ROUTES,
|
|
2201
|
+
multi: true,
|
|
2202
|
+
useFactory: routesFactory,
|
|
2203
|
+
},
|
|
2204
|
+
], imports: [AXPComponentSlotModule.forChild({
|
|
2205
|
+
'root-header-end': [
|
|
2206
|
+
{
|
|
2207
|
+
name: 'communication-inbox',
|
|
2208
|
+
component: AXPInAppInboxSlotComponent,
|
|
2209
|
+
},
|
|
2210
|
+
],
|
|
2211
|
+
})] }); }
|
|
2212
|
+
}
|
|
2213
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMCommunicationManagementModule, decorators: [{
|
|
2214
|
+
type: NgModule,
|
|
2215
|
+
args: [{
|
|
2216
|
+
imports: [
|
|
2217
|
+
AXPComponentSlotModule.forChild({
|
|
2218
|
+
'root-header-end': [
|
|
2219
|
+
{
|
|
2220
|
+
name: 'communication-inbox',
|
|
2221
|
+
component: AXPInAppInboxSlotComponent,
|
|
2222
|
+
},
|
|
2223
|
+
],
|
|
2224
|
+
}),
|
|
2225
|
+
],
|
|
2226
|
+
providers: [
|
|
2227
|
+
provideCommandSetups([
|
|
2228
|
+
{
|
|
2229
|
+
key: AXMCommunicationManagementCommandKeys$1.Send,
|
|
2230
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-send.command-D7_MmGQe.mjs').then((m) => m.CommunicationSendCommand),
|
|
2231
|
+
},
|
|
2232
|
+
{
|
|
2233
|
+
key: AXMCommunicationManagementCommandKeys$1.TestSmtp,
|
|
2234
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-test-smtp.command-BySmN1Lz.mjs').then((m) => m.CommunicationTestSmtpCommand),
|
|
2235
|
+
},
|
|
2236
|
+
{
|
|
2237
|
+
key: AXMCommunicationManagementCommandKeys$1.EmailShowDialog,
|
|
2238
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-email-show-dialog.command-CP0zAEe4.mjs').then((m) => m.CommunicationManagementEmailShowDialogCommand),
|
|
2239
|
+
},
|
|
2240
|
+
{
|
|
2241
|
+
key: AXMCommunicationManagementCommandKeys$1.EmailSend,
|
|
2242
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-email-send.command-wuqLiY8s.mjs').then((m) => m.CommunicationManagementEmailSendCommand),
|
|
2243
|
+
},
|
|
2244
|
+
{
|
|
2245
|
+
key: AXMCommunicationManagementCommandKeys$1.ShowSentMessage,
|
|
2246
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-show-sent-message.command-D8125Jxi.mjs').then((m) => m.CommunicationShowSentMessageCommand),
|
|
2247
|
+
},
|
|
2248
|
+
{
|
|
2249
|
+
key: LEGACY_NOTIFICATION_EMAIL_SHOW_DIALOG_COMMAND_KEY,
|
|
2250
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-email-show-dialog.command-CP0zAEe4.mjs').then((m) => m.CommunicationManagementEmailShowDialogCommand),
|
|
2251
|
+
},
|
|
2252
|
+
{
|
|
2253
|
+
key: LEGACY_NOTIFICATION_EMAIL_SEND_COMMAND_KEY,
|
|
2254
|
+
command: () => import('./acorex-platform-module-communication-management-client-communication-email-send.command-wuqLiY8s.mjs').then((m) => m.CommunicationManagementEmailSendCommand),
|
|
2255
|
+
},
|
|
2256
|
+
]),
|
|
2257
|
+
{
|
|
2258
|
+
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
2259
|
+
useValue: CommunicationManagementManifest,
|
|
2260
|
+
multi: true,
|
|
2261
|
+
},
|
|
2262
|
+
{
|
|
2263
|
+
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
2264
|
+
useClass: AXMCommunicationManagementPermissionDefinitionProvider,
|
|
2265
|
+
multi: true,
|
|
2266
|
+
},
|
|
2267
|
+
{
|
|
2268
|
+
provide: AXP_MENU_PROVIDER,
|
|
2269
|
+
useClass: AXMCommunicationManagementMenuProvider,
|
|
2270
|
+
multi: true,
|
|
2271
|
+
},
|
|
2272
|
+
{
|
|
2273
|
+
provide: AXP_STATUS_PROVIDERS,
|
|
2274
|
+
useClass: AXMCommunicationStatusProvider,
|
|
2275
|
+
multi: true,
|
|
2276
|
+
},
|
|
2277
|
+
{
|
|
2278
|
+
provide: AXP_STATUS_PROVIDERS,
|
|
2279
|
+
useClass: AXMCommunicationDeliveryStatusProvider,
|
|
2280
|
+
multi: true,
|
|
2281
|
+
},
|
|
2282
|
+
{
|
|
2283
|
+
provide: AXP_SEARCH_PROVIDER,
|
|
2284
|
+
useClass: AXMCommunicationManagementSearchCommandProvider,
|
|
2285
|
+
multi: true,
|
|
2286
|
+
},
|
|
2287
|
+
{
|
|
2288
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
2289
|
+
useClass: AXMCommunicationManagementSettingProvider,
|
|
2290
|
+
multi: true,
|
|
2291
|
+
},
|
|
2292
|
+
{
|
|
2293
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
2294
|
+
useClass: AXMCommunicationUserNotificationsSettingProvider,
|
|
2295
|
+
multi: true,
|
|
2296
|
+
},
|
|
2297
|
+
communicationTextTemplateChannelProvider,
|
|
2298
|
+
{
|
|
2299
|
+
provide: AXP_WIDGET_DEFINITION_PROVIDER,
|
|
2300
|
+
useClass: AXMCommunicationManagementWidgetsProvider,
|
|
2301
|
+
multi: true,
|
|
2302
|
+
},
|
|
2303
|
+
{
|
|
2304
|
+
provide: AXP_IN_APP_INBOX_PORT,
|
|
2305
|
+
useClass: AXMCommunicationInAppInboxPort,
|
|
2306
|
+
},
|
|
2307
|
+
{
|
|
2308
|
+
provide: AXP_IN_APP_INBOX_CONFIG,
|
|
2309
|
+
useValue: communicationInAppInboxConfig,
|
|
2310
|
+
},
|
|
2311
|
+
{
|
|
2312
|
+
provide: AXP_IN_APP_INBOX_I18N,
|
|
2313
|
+
useValue: communicationInAppInboxI18n,
|
|
2314
|
+
},
|
|
2315
|
+
{
|
|
2316
|
+
provide: AXP_IN_APP_INBOX_SYNC_STATUS,
|
|
2317
|
+
useExisting: AXMCommunicationInAppInboxSyncStatusService,
|
|
2318
|
+
},
|
|
2319
|
+
communicationInAppNotificationServiceProvider,
|
|
2320
|
+
{
|
|
2321
|
+
provide: AXP_TASK_BADGE_PROVIDERS,
|
|
2322
|
+
useClass: AXMCommunicationInboxBadgeProvider,
|
|
2323
|
+
multi: true,
|
|
2324
|
+
},
|
|
2325
|
+
...provideCommunicationInAppRealtimeHandlers(),
|
|
2326
|
+
...provideCommunicationInAppInboxFallbackSync(),
|
|
2327
|
+
{
|
|
2328
|
+
provide: ROUTES,
|
|
2329
|
+
multi: true,
|
|
2330
|
+
useFactory: routesFactory,
|
|
2331
|
+
},
|
|
2332
|
+
],
|
|
2333
|
+
}]
|
|
2334
|
+
}] });
|
|
2335
|
+
|
|
2336
|
+
//#region ----- Imports -----
|
|
2337
|
+
//#endregion
|
|
2338
|
+
//#region ----- Builders -----
|
|
2339
|
+
function buildMyInAppInboxDashboardWidget(id, x, y, size = [4, 3]) {
|
|
2340
|
+
const { config, meta } = layoutFromDimensions(id, AXP_MY_IN_APP_INBOX_DASHBOARD_DIMENSIONS, { x, y, lg: size });
|
|
2341
|
+
return {
|
|
2342
|
+
config: {
|
|
2343
|
+
...config,
|
|
2344
|
+
title: '@communication-management:widgets.my-in-app-inbox-dashboard.widget-title',
|
|
2345
|
+
},
|
|
2346
|
+
node: {
|
|
2347
|
+
type: 'CommunicationManagement:Widget:Dashboard:MyInAppInboxDashboard',
|
|
2348
|
+
meta,
|
|
2349
|
+
name: `CommunicationManagement:Widget:Dashboard:MyInAppInboxDashboard-${id}`,
|
|
2350
|
+
path: `CommunicationManagement:Widget:Dashboard:MyInAppInboxDashboard-${id}`,
|
|
2351
|
+
},
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
//#endregion
|
|
2355
|
+
|
|
2356
|
+
//#region ---- Delivery channels settings section resolver ----
|
|
2357
|
+
function resolveCommunicationDeliveryChannelsSettingsSection(context) {
|
|
2358
|
+
if (!context.hasGroup(AXP_COMMUNICATION_USER_NOTIFICATIONS_SETTINGS_GROUP)) {
|
|
2359
|
+
return null;
|
|
2360
|
+
}
|
|
2361
|
+
const group = context.getGroup(AXP_COMMUNICATION_USER_NOTIFICATIONS_SETTINGS_GROUP);
|
|
2362
|
+
const hasSection = group?.sections.some((section) => section.name === AXP_COMMUNICATION_DELIVERY_CHANNELS_SETTINGS_SECTION);
|
|
2363
|
+
if (!hasSection) {
|
|
2364
|
+
return null;
|
|
2365
|
+
}
|
|
2366
|
+
return context.group(AXP_COMMUNICATION_USER_NOTIFICATIONS_SETTINGS_GROUP)?.section(AXP_COMMUNICATION_DELIVERY_CHANNELS_SETTINGS_SECTION) ?? null;
|
|
2367
|
+
}
|
|
2368
|
+
//#endregion
|
|
2369
|
+
|
|
2370
|
+
/**
|
|
2371
|
+
* Generated bundle index. Do not edit.
|
|
2372
|
+
*/
|
|
2373
|
+
|
|
2374
|
+
export { AXPInAppInboxConnectorService as A, normalizeInAppInboxItem as B, resolveCommunicationDeliveryChannelsSettingsSection as C, sortInAppInboxItems as D, AXPInAppInboxActionService as a, AXP_IN_APP_INBOX_I18N as b, AXPInAppInboxItemComponent as c, AXPCommunicationManagementClient as d, AXPInAppInboxRealtimeService as e, AXMCommunicationManagementMenuProvider as f, AXMCommunicationManagementModule as g, AXMCommunicationManagementPermissionDefinitionProvider as h, AXMCommunicationManagementSearchCommandProvider as i, AXPCommunicationInAppInboxWidgetViewComponent as j, AXPInAppInboxPanelComponent as k, AXPInAppInboxSlotComponent as l, AXPMyInAppInboxDashboardWidget as m, AXP_IN_APP_INBOX_CONFIG as n, AXP_IN_APP_INBOX_LEGACY_DB_NAME as o, AXP_IN_APP_INBOX_LOCAL_ENTITY_KEY as p, AXP_IN_APP_INBOX_LOCAL_MAX_ITEMS as q, AXP_IN_APP_INBOX_PORT as r, AXP_IN_APP_INBOX_SYNC_STATUS as s, AXP_MY_IN_APP_INBOX_DASHBOARD_DIMENSIONS as t, buildMyInAppInboxDashboardWidget as u, filterInAppInboxItemsLocally as v, getInAppInboxPriorityClass as w, isArchiveCategoryFilter as x, isInAppInboxUnread as y, isInAppInboxUnseen as z };
|
|
2375
|
+
//# sourceMappingURL=acorex-platform-module-communication-management-client-acorex-platform-module-communication-management-client-09UhY2Rc.mjs.map
|