@codingfactory/notify-kit-client 0.1.0 → 0.2.0
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/README.md +500 -0
- package/dist/index.d.ts +167 -198
- package/dist/index.js +1126 -184
- package/dist/index.js.map +1 -1
- package/dist/nuxt/index.d.ts +1 -1
- package/dist/{useNotifyKitModals-BZ_NiTKw.d.ts → useNotifyKitModals-CUfVmBsN.d.ts} +205 -59
- package/package.json +1 -6
package/dist/index.js
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { useNotifyKitStore } from './chunk-7LQBNDRD.js';
|
|
2
2
|
export { InvalidSnoozeDurationError, NOTIFY_KIT_MODALS_KEY, NOTIFY_KIT_STORE_KEY, provideNotifyKitModals, provideNotifyKitStore, resetNotifyKitStore, useNotifyKitModals, useNotifyKitStore } from './chunk-7LQBNDRD.js';
|
|
3
|
-
import { provide, inject,
|
|
3
|
+
import { provide, inject, computed, ref, onMounted, onUnmounted, watch, reactive, readonly } from 'vue';
|
|
4
|
+
|
|
5
|
+
// src/types/modal.ts
|
|
6
|
+
function isModalSpec(value) {
|
|
7
|
+
if (typeof value !== "object" || value === null) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const obj = value;
|
|
11
|
+
if (typeof obj["enabled"] !== "boolean") return false;
|
|
12
|
+
if (typeof obj["requires_ack"] !== "boolean") return false;
|
|
13
|
+
if (!Array.isArray(obj["snooze_options_minutes"])) return false;
|
|
14
|
+
const snoozeOptions = obj["snooze_options_minutes"];
|
|
15
|
+
for (const option of snoozeOptions) {
|
|
16
|
+
if (typeof option !== "number" || !Number.isInteger(option) || option < 1) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
4
22
|
|
|
5
23
|
// src/types/notification.ts
|
|
6
24
|
var NOTIFICATION_CATEGORIES = [
|
|
@@ -46,38 +64,49 @@ function isNotifyKitNotification(value) {
|
|
|
46
64
|
return false;
|
|
47
65
|
}
|
|
48
66
|
}
|
|
49
|
-
if (obj["modal"] !== null &&
|
|
67
|
+
if (obj["modal"] !== null && !isModalSpec(obj["modal"])) return false;
|
|
50
68
|
return true;
|
|
51
69
|
}
|
|
52
70
|
function isModalEnabled(notification) {
|
|
53
71
|
return notification.modal?.enabled ?? false;
|
|
54
72
|
}
|
|
55
73
|
|
|
56
|
-
// src/types/
|
|
57
|
-
function
|
|
74
|
+
// src/types/preferences.ts
|
|
75
|
+
function isBooleanRecord(value) {
|
|
58
76
|
if (typeof value !== "object" || value === null) {
|
|
59
77
|
return false;
|
|
60
78
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
for (const option of snoozeOptions) {
|
|
67
|
-
if (typeof option !== "number" || !Number.isInteger(option) || option < 1) {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
79
|
+
return Object.values(value).every((entry) => typeof entry === "boolean");
|
|
80
|
+
}
|
|
81
|
+
function isStringRecord(value) {
|
|
82
|
+
if (typeof value !== "object" || value === null) {
|
|
83
|
+
return false;
|
|
70
84
|
}
|
|
71
|
-
return
|
|
85
|
+
return Object.values(value).every((entry) => typeof entry === "string");
|
|
72
86
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
87
|
+
function isStringArray(value) {
|
|
88
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
89
|
+
}
|
|
90
|
+
function isNotifyKitQuietHours(value) {
|
|
91
|
+
if (typeof value !== "object" || value === null) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const obj = value;
|
|
95
|
+
return typeof obj["start"] === "string" && typeof obj["end"] === "string";
|
|
96
|
+
}
|
|
97
|
+
function isNotifyKitPreferenceSettings(value) {
|
|
76
98
|
if (typeof value !== "object" || value === null) {
|
|
77
99
|
return false;
|
|
78
100
|
}
|
|
79
101
|
const obj = value;
|
|
80
|
-
|
|
102
|
+
const digest = obj["digest"];
|
|
103
|
+
if (typeof digest !== "object" || digest === null) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const digestRecord = digest;
|
|
107
|
+
const quietHours = digestRecord["quiet_hours"];
|
|
108
|
+
const categories = digestRecord["categories"];
|
|
109
|
+
return isBooleanRecord(obj["channels"]) && isStringRecord(obj["channel_modes"]) && isBooleanRecord(obj["topics"]) && isBooleanRecord(obj["email_preferences"]) && isStringArray(obj["keyword_rules"]) && typeof digestRecord["enabled"] === "boolean" && (digestRecord["frequency"] === "daily" || digestRecord["frequency"] === "weekly") && (categories === null || isStringArray(categories)) && (digestRecord["workspace_id"] === null || typeof digestRecord["workspace_id"] === "string") && (digestRecord["timezone"] === null || typeof digestRecord["timezone"] === "string") && typeof digestRecord["hour"] === "number" && (quietHours === null || isNotifyKitQuietHours(quietHours)) && isStringArray(obj["available_channels"]) && isStringArray(obj["available_topics"]) && isStringArray(obj["available_email_preferences"]);
|
|
81
110
|
}
|
|
82
111
|
|
|
83
112
|
// src/types/api.ts
|
|
@@ -103,12 +132,146 @@ function isUnreadCountResponse(value) {
|
|
|
103
132
|
return typeof obj["count"] === "number";
|
|
104
133
|
}
|
|
105
134
|
|
|
135
|
+
// src/client/normalizeNotification.ts
|
|
136
|
+
var RESERVED_PAYLOAD_KEYS = /* @__PURE__ */ new Set([
|
|
137
|
+
"id",
|
|
138
|
+
"key",
|
|
139
|
+
"category",
|
|
140
|
+
"level",
|
|
141
|
+
"title",
|
|
142
|
+
"body",
|
|
143
|
+
"action_url",
|
|
144
|
+
"workspace_id",
|
|
145
|
+
"modal",
|
|
146
|
+
"group_key",
|
|
147
|
+
"idempotency_key",
|
|
148
|
+
"read_at",
|
|
149
|
+
"created_at",
|
|
150
|
+
"data"
|
|
151
|
+
]);
|
|
152
|
+
function isRecord(value) {
|
|
153
|
+
return typeof value === "object" && value !== null;
|
|
154
|
+
}
|
|
155
|
+
function nullableString(value) {
|
|
156
|
+
return typeof value === "string" && value.trim() !== "" ? value : null;
|
|
157
|
+
}
|
|
158
|
+
function stringOrFallback(value, fallback) {
|
|
159
|
+
return typeof value === "string" && value.trim() !== "" ? value : fallback;
|
|
160
|
+
}
|
|
161
|
+
function inferCategory(key) {
|
|
162
|
+
if (key.startsWith("workspace.")) {
|
|
163
|
+
return "workspace";
|
|
164
|
+
}
|
|
165
|
+
if (key.startsWith("security.")) {
|
|
166
|
+
return "security";
|
|
167
|
+
}
|
|
168
|
+
if (key.startsWith("orders.")) {
|
|
169
|
+
return "orders";
|
|
170
|
+
}
|
|
171
|
+
if (key.startsWith("social.") || key.includes("mention") || key.includes("comment")) {
|
|
172
|
+
return "social";
|
|
173
|
+
}
|
|
174
|
+
if (key.startsWith("marketing.")) {
|
|
175
|
+
return "marketing";
|
|
176
|
+
}
|
|
177
|
+
return "system";
|
|
178
|
+
}
|
|
179
|
+
function inferLevel(value) {
|
|
180
|
+
if (isValidLevel(value)) {
|
|
181
|
+
return value;
|
|
182
|
+
}
|
|
183
|
+
return "info";
|
|
184
|
+
}
|
|
185
|
+
function buildUser(payload) {
|
|
186
|
+
const actorId = nullableString(payload["actor_id"]);
|
|
187
|
+
if (actorId === null) {
|
|
188
|
+
return void 0;
|
|
189
|
+
}
|
|
190
|
+
const user = {
|
|
191
|
+
id: actorId,
|
|
192
|
+
name: stringOrFallback(payload["actor_name"], "Someone"),
|
|
193
|
+
handle: nullableString(payload["actor_handle"]) ?? ""
|
|
194
|
+
};
|
|
195
|
+
const avatar = nullableString(payload["actor_avatar"]);
|
|
196
|
+
if (avatar !== null) {
|
|
197
|
+
user["avatar"] = avatar;
|
|
198
|
+
}
|
|
199
|
+
return user;
|
|
200
|
+
}
|
|
201
|
+
function normalizeApiNotification(raw) {
|
|
202
|
+
if (isNotifyKitNotification(raw)) {
|
|
203
|
+
return raw;
|
|
204
|
+
}
|
|
205
|
+
const rawRecord = isRecord(raw) ? {
|
|
206
|
+
id: stringOrFallback(raw["id"], ""),
|
|
207
|
+
type: nullableString(raw["type"]) ?? void 0,
|
|
208
|
+
data: isRecord(raw["data"]) ? raw["data"] : {},
|
|
209
|
+
read_at: nullableString(raw["read_at"]),
|
|
210
|
+
created_at: nullableString(raw["created_at"]) ?? void 0
|
|
211
|
+
} : {
|
|
212
|
+
id: "",
|
|
213
|
+
type: void 0,
|
|
214
|
+
data: {},
|
|
215
|
+
read_at: void 0,
|
|
216
|
+
created_at: void 0
|
|
217
|
+
};
|
|
218
|
+
const payload = isRecord(rawRecord.data) ? rawRecord.data : {};
|
|
219
|
+
const nestedData = isRecord(payload["data"]) ? payload["data"] : {};
|
|
220
|
+
const key = stringOrFallback(payload["key"], stringOrFallback(rawRecord.type, "system.notification"));
|
|
221
|
+
const category = isValidCategory(payload["category"]) ? payload["category"] : inferCategory(key);
|
|
222
|
+
const title = stringOrFallback(payload["title"], stringOrFallback(payload["message"], "Notification"));
|
|
223
|
+
const body = stringOrFallback(payload["body"], stringOrFallback(payload["message"], title));
|
|
224
|
+
const actionUrl = nullableString(payload["action_url"]) ?? nullableString(payload["link"]);
|
|
225
|
+
const user = buildUser(payload);
|
|
226
|
+
const data = {
|
|
227
|
+
...nestedData
|
|
228
|
+
};
|
|
229
|
+
for (const [entryKey, entryValue] of Object.entries(payload)) {
|
|
230
|
+
if (entryKey === "data" || RESERVED_PAYLOAD_KEYS.has(entryKey)) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
data[entryKey] = entryValue;
|
|
234
|
+
}
|
|
235
|
+
if (typeof payload["key"] === "string") {
|
|
236
|
+
data["key"] = payload["key"];
|
|
237
|
+
}
|
|
238
|
+
if (typeof payload["title"] === "string") {
|
|
239
|
+
data["title"] = payload["title"];
|
|
240
|
+
}
|
|
241
|
+
data["body"] = body;
|
|
242
|
+
data["message"] = body;
|
|
243
|
+
if (actionUrl !== null) {
|
|
244
|
+
data["action_url"] = actionUrl;
|
|
245
|
+
data["link"] = actionUrl;
|
|
246
|
+
}
|
|
247
|
+
if (user !== void 0) {
|
|
248
|
+
data["user"] = user;
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
id: stringOrFallback(rawRecord.id, ""),
|
|
252
|
+
key,
|
|
253
|
+
category,
|
|
254
|
+
level: inferLevel(payload["level"]),
|
|
255
|
+
title,
|
|
256
|
+
body,
|
|
257
|
+
action_url: actionUrl,
|
|
258
|
+
workspace_id: nullableString(payload["workspace_id"]),
|
|
259
|
+
modal: isModalSpec(payload["modal"]) ? payload["modal"] : null,
|
|
260
|
+
group_key: nullableString(payload["group_key"]),
|
|
261
|
+
idempotency_key: nullableString(payload["idempotency_key"]),
|
|
262
|
+
data,
|
|
263
|
+
read_at: rawRecord.read_at ?? null,
|
|
264
|
+
created_at: stringOrFallback(rawRecord.created_at, (/* @__PURE__ */ new Date()).toISOString())
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
106
268
|
// src/client/NotifyKitClient.ts
|
|
107
269
|
var NotifyKitApiError = class extends Error {
|
|
108
|
-
constructor(message, status, errors) {
|
|
270
|
+
constructor(message, status, errors, headers) {
|
|
109
271
|
super(message);
|
|
110
272
|
this.status = status;
|
|
111
273
|
this.errors = errors;
|
|
274
|
+
this.headers = headers;
|
|
112
275
|
}
|
|
113
276
|
name = "NotifyKitApiError";
|
|
114
277
|
};
|
|
@@ -140,7 +303,11 @@ var NotifyKitClient = class {
|
|
|
140
303
|
const queryParams = this.buildNotificationParams(params);
|
|
141
304
|
const queryString = queryParams.toString();
|
|
142
305
|
const url = queryString.length > 0 ? `/notifications?${queryString}` : "/notifications";
|
|
143
|
-
|
|
306
|
+
const response = await this.request("GET", url);
|
|
307
|
+
return {
|
|
308
|
+
data: response.data.map((notification) => normalizeApiNotification(notification)),
|
|
309
|
+
meta: response.meta
|
|
310
|
+
};
|
|
144
311
|
}
|
|
145
312
|
/**
|
|
146
313
|
* Get the count of unread notifications.
|
|
@@ -151,11 +318,21 @@ var NotifyKitClient = class {
|
|
|
151
318
|
"/notifications/unread-count"
|
|
152
319
|
);
|
|
153
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* Get a single notification for the current user.
|
|
323
|
+
*/
|
|
324
|
+
async getNotification(id) {
|
|
325
|
+
const response = await this.request(
|
|
326
|
+
"GET",
|
|
327
|
+
`/notifications/${id}`
|
|
328
|
+
);
|
|
329
|
+
return normalizeApiNotification(response.data);
|
|
330
|
+
}
|
|
154
331
|
/**
|
|
155
332
|
* Mark a notification as read.
|
|
156
333
|
*/
|
|
157
334
|
async markRead(id) {
|
|
158
|
-
|
|
335
|
+
return this.request("PATCH", `/notifications/${id}/read`);
|
|
159
336
|
}
|
|
160
337
|
/**
|
|
161
338
|
* Mark all notifications as read.
|
|
@@ -191,7 +368,11 @@ var NotifyKitClient = class {
|
|
|
191
368
|
}
|
|
192
369
|
const queryString = queryParams.toString();
|
|
193
370
|
const url = queryString.length > 0 ? `/notifications/groups/${groupKey}?${queryString}` : `/notifications/groups/${groupKey}`;
|
|
194
|
-
|
|
371
|
+
const response = await this.request("GET", url);
|
|
372
|
+
return {
|
|
373
|
+
data: response.data.map((notification) => normalizeApiNotification(notification)),
|
|
374
|
+
meta: response.meta
|
|
375
|
+
};
|
|
195
376
|
}
|
|
196
377
|
// ============================================
|
|
197
378
|
// Modals
|
|
@@ -222,16 +403,159 @@ var NotifyKitClient = class {
|
|
|
222
403
|
// Preferences
|
|
223
404
|
// ============================================
|
|
224
405
|
/**
|
|
225
|
-
* Get the current user's notification
|
|
406
|
+
* Get the current user's notification preference settings.
|
|
407
|
+
*/
|
|
408
|
+
async getPreferenceSettings(query) {
|
|
409
|
+
const queryParams = new URLSearchParams();
|
|
410
|
+
if (query?.workspace_id !== void 0 && query.workspace_id !== null) {
|
|
411
|
+
queryParams.set("workspace_id", query.workspace_id);
|
|
412
|
+
}
|
|
413
|
+
const queryString = queryParams.toString();
|
|
414
|
+
const url = queryString.length > 0 ? `/preference-settings?${queryString}` : "/preference-settings";
|
|
415
|
+
const response = await this.request("GET", url);
|
|
416
|
+
return response.data;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Alias for getPreferenceSettings.
|
|
226
420
|
*/
|
|
227
|
-
async getPreferences() {
|
|
228
|
-
return this.
|
|
421
|
+
async getPreferences(query) {
|
|
422
|
+
return this.getPreferenceSettings(query);
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Update the current user's notification preference settings.
|
|
426
|
+
*/
|
|
427
|
+
async updatePreferenceSettings(preferences) {
|
|
428
|
+
const response = await this.request(
|
|
429
|
+
"PATCH",
|
|
430
|
+
"/preference-settings",
|
|
431
|
+
preferences
|
|
432
|
+
);
|
|
433
|
+
return response.data;
|
|
229
434
|
}
|
|
230
435
|
/**
|
|
231
|
-
*
|
|
436
|
+
* Alias for updatePreferenceSettings.
|
|
232
437
|
*/
|
|
233
438
|
async updatePreferences(preferences) {
|
|
234
|
-
|
|
439
|
+
return this.updatePreferenceSettings(preferences);
|
|
440
|
+
}
|
|
441
|
+
// ============================================
|
|
442
|
+
// Bulk Actions
|
|
443
|
+
// ============================================
|
|
444
|
+
/**
|
|
445
|
+
* Bulk mark notifications as read.
|
|
446
|
+
*/
|
|
447
|
+
async bulkMarkRead(ids) {
|
|
448
|
+
return this.request("POST", "/notifications/bulk/read", {
|
|
449
|
+
notification_ids: ids
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Bulk mark all matching notifications as read.
|
|
454
|
+
*/
|
|
455
|
+
async bulkMarkAllRead(filters) {
|
|
456
|
+
return this.request("POST", "/notifications/bulk/read", {
|
|
457
|
+
all: true,
|
|
458
|
+
filters
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Bulk archive notifications.
|
|
463
|
+
*/
|
|
464
|
+
async bulkArchive(ids) {
|
|
465
|
+
return this.request("POST", "/notifications/bulk/archive", {
|
|
466
|
+
notification_ids: ids
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Bulk archive all matching notifications.
|
|
471
|
+
*/
|
|
472
|
+
async bulkArchiveAll(filters) {
|
|
473
|
+
return this.request("POST", "/notifications/bulk/archive", {
|
|
474
|
+
all: true,
|
|
475
|
+
filters
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Bulk delete notifications.
|
|
480
|
+
*/
|
|
481
|
+
async bulkDelete(ids) {
|
|
482
|
+
return this.request("POST", "/notifications/bulk/delete", {
|
|
483
|
+
notification_ids: ids
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Bulk delete all matching notifications.
|
|
488
|
+
*/
|
|
489
|
+
async bulkDeleteAll(filters) {
|
|
490
|
+
return this.request("POST", "/notifications/bulk/delete", {
|
|
491
|
+
all: true,
|
|
492
|
+
filters
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
// ============================================
|
|
496
|
+
// Search
|
|
497
|
+
// ============================================
|
|
498
|
+
/**
|
|
499
|
+
* Search notifications by query.
|
|
500
|
+
*/
|
|
501
|
+
async search(query, filters, limit) {
|
|
502
|
+
const queryParams = new URLSearchParams();
|
|
503
|
+
queryParams.set("q", query);
|
|
504
|
+
if (filters?.category !== void 0) {
|
|
505
|
+
queryParams.set("category", filters.category);
|
|
506
|
+
}
|
|
507
|
+
if (filters?.unread === true) {
|
|
508
|
+
queryParams.set("unread", "1");
|
|
509
|
+
}
|
|
510
|
+
if (filters?.level !== void 0) {
|
|
511
|
+
queryParams.set("level", filters.level);
|
|
512
|
+
}
|
|
513
|
+
if (limit !== void 0) {
|
|
514
|
+
queryParams.set("limit", String(limit));
|
|
515
|
+
}
|
|
516
|
+
const response = await this.request("GET", `/notifications/search?${queryParams.toString()}`);
|
|
517
|
+
return {
|
|
518
|
+
data: response.data.map((notification) => normalizeApiNotification(notification)),
|
|
519
|
+
total: response.total
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Get saved filters (system + custom).
|
|
524
|
+
*/
|
|
525
|
+
async getSavedFilters() {
|
|
526
|
+
const response = await this.request("GET", "/notifications/filters");
|
|
527
|
+
return response.data;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Save a custom filter.
|
|
531
|
+
*/
|
|
532
|
+
async saveFilter(name, filters) {
|
|
533
|
+
const response = await this.request("POST", "/notifications/filters", {
|
|
534
|
+
name,
|
|
535
|
+
filters
|
|
536
|
+
});
|
|
537
|
+
return response.data;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Delete a custom filter.
|
|
541
|
+
*/
|
|
542
|
+
async deleteFilter(filterId) {
|
|
543
|
+
await this.request("DELETE", `/notifications/filters/${filterId}`);
|
|
544
|
+
}
|
|
545
|
+
// ============================================
|
|
546
|
+
// Archive
|
|
547
|
+
// ============================================
|
|
548
|
+
/**
|
|
549
|
+
* Archive a notification.
|
|
550
|
+
*/
|
|
551
|
+
async archiveNotification(id) {
|
|
552
|
+
await this.request("POST", `/notifications/${id}/archive`);
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Unarchive a notification.
|
|
556
|
+
*/
|
|
557
|
+
async unarchiveNotification(id) {
|
|
558
|
+
await this.request("POST", `/notifications/${id}/unarchive`);
|
|
235
559
|
}
|
|
236
560
|
// ============================================
|
|
237
561
|
// Private helpers
|
|
@@ -280,11 +604,15 @@ var NotifyKitClient = class {
|
|
|
280
604
|
}
|
|
281
605
|
const response = await this.fetchFn(url, requestInit);
|
|
282
606
|
if (!response.ok) {
|
|
607
|
+
const responseHeaders = Object.fromEntries(
|
|
608
|
+
Array.from(response.headers.entries()).map(([key, value]) => [key.toLowerCase(), value])
|
|
609
|
+
);
|
|
283
610
|
const errorData = await response.json();
|
|
284
611
|
throw new NotifyKitApiError(
|
|
285
612
|
errorData.message ?? `Request failed with status ${String(response.status)}`,
|
|
286
613
|
response.status,
|
|
287
|
-
errorData.errors
|
|
614
|
+
errorData.errors,
|
|
615
|
+
responseHeaders
|
|
288
616
|
);
|
|
289
617
|
}
|
|
290
618
|
const text = await response.text();
|
|
@@ -322,8 +650,9 @@ var ENDPOINTS = {
|
|
|
322
650
|
ACK_MODAL: (id) => `/modals/${id}/ack`,
|
|
323
651
|
/** POST - Snooze a modal notification */
|
|
324
652
|
SNOOZE_MODAL: (id) => `/modals/${id}/snooze`,
|
|
325
|
-
/** GET - Get user's notification
|
|
326
|
-
|
|
653
|
+
/** GET/PATCH - Get or update user's notification preference settings */
|
|
654
|
+
PREFERENCE_SETTINGS: "/preference-settings",
|
|
655
|
+
PREFERENCES: "/preference-settings"
|
|
327
656
|
};
|
|
328
657
|
var NOTIFY_KIT_CLIENT_KEY = /* @__PURE__ */ Symbol(
|
|
329
658
|
"notify-kit-client"
|
|
@@ -353,6 +682,7 @@ function useNotifyKitClient(config) {
|
|
|
353
682
|
// Notifications
|
|
354
683
|
listNotifications: (params) => client.listNotifications(params),
|
|
355
684
|
getUnreadCount: () => client.getUnreadCount(),
|
|
685
|
+
getNotification: (id) => client.getNotification(id),
|
|
356
686
|
markRead: (id) => client.markRead(id),
|
|
357
687
|
markAllRead: () => client.markAllRead(),
|
|
358
688
|
deleteNotification: (id) => client.deleteNotification(id),
|
|
@@ -364,10 +694,493 @@ function useNotifyKitClient(config) {
|
|
|
364
694
|
ackModal: (id) => client.ackModal(id),
|
|
365
695
|
snoozeModal: (id, minutes) => client.snoozeModal(id, minutes),
|
|
366
696
|
// Preferences
|
|
367
|
-
|
|
697
|
+
getPreferenceSettings: (query) => client.getPreferenceSettings(query),
|
|
698
|
+
updatePreferenceSettings: (preferences) => client.updatePreferenceSettings(preferences),
|
|
699
|
+
getPreferences: (query) => client.getPreferences(query),
|
|
368
700
|
updatePreferences: (preferences) => client.updatePreferences(preferences)
|
|
369
701
|
};
|
|
370
702
|
}
|
|
703
|
+
var DEFAULT_UNREAD_COUNT_RETRY_AFTER_MS = 3e4;
|
|
704
|
+
var MIN_UNREAD_COUNT_RETRY_AFTER_MS = 5e3;
|
|
705
|
+
var DEFAULT_UNREAD_COUNT_TRANSIENT_RETRY_MS = 1e4;
|
|
706
|
+
var MAX_UNREAD_COUNT_TRANSIENT_RETRY_MS = 12e4;
|
|
707
|
+
var MIN_UNREAD_COUNT_REFRESH_INTERVAL_MS = 5e3;
|
|
708
|
+
var DEFAULT_PER_PAGE = 20;
|
|
709
|
+
function createInitialInboxState() {
|
|
710
|
+
return {
|
|
711
|
+
error: null,
|
|
712
|
+
currentPage: 0,
|
|
713
|
+
lastPage: 1,
|
|
714
|
+
hasMore: true,
|
|
715
|
+
unreadCountRetryAfterUntil: 0,
|
|
716
|
+
unreadCountLastLoadedAt: 0,
|
|
717
|
+
unreadCountTransientFailureCount: 0,
|
|
718
|
+
unreadCountRequest: null
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
var inboxState = null;
|
|
722
|
+
function getInboxState() {
|
|
723
|
+
inboxState ??= reactive(createInitialInboxState());
|
|
724
|
+
return inboxState;
|
|
725
|
+
}
|
|
726
|
+
function resetNotifyKitInbox() {
|
|
727
|
+
if (inboxState !== null) {
|
|
728
|
+
Object.assign(inboxState, createInitialInboxState());
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
function resolveStatusCode(statusCode) {
|
|
732
|
+
if (typeof statusCode === "number" && Number.isFinite(statusCode)) {
|
|
733
|
+
return statusCode;
|
|
734
|
+
}
|
|
735
|
+
if (typeof statusCode === "string") {
|
|
736
|
+
const parsedStatus = Number.parseInt(statusCode, 10);
|
|
737
|
+
if (Number.isFinite(parsedStatus)) {
|
|
738
|
+
return parsedStatus;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return void 0;
|
|
742
|
+
}
|
|
743
|
+
function resolveRetryAfterMs(retryAfterHeader) {
|
|
744
|
+
if (typeof retryAfterHeader === "number" && Number.isFinite(retryAfterHeader) && retryAfterHeader > 0) {
|
|
745
|
+
return Math.max(MIN_UNREAD_COUNT_RETRY_AFTER_MS, retryAfterHeader * 1e3);
|
|
746
|
+
}
|
|
747
|
+
if (typeof retryAfterHeader === "string") {
|
|
748
|
+
const parsedSeconds = Number.parseInt(retryAfterHeader, 10);
|
|
749
|
+
if (Number.isFinite(parsedSeconds) && parsedSeconds > 0) {
|
|
750
|
+
return Math.max(MIN_UNREAD_COUNT_RETRY_AFTER_MS, parsedSeconds * 1e3);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
return DEFAULT_UNREAD_COUNT_RETRY_AFTER_MS;
|
|
754
|
+
}
|
|
755
|
+
function isServerFailureStatus(statusCode) {
|
|
756
|
+
return typeof statusCode === "number" && statusCode >= 500 && statusCode < 600;
|
|
757
|
+
}
|
|
758
|
+
function resolveTransientRetryMs(failureCount) {
|
|
759
|
+
const sanitizedFailureCount = Math.max(1, failureCount);
|
|
760
|
+
const exponentialRetryMs = DEFAULT_UNREAD_COUNT_TRANSIENT_RETRY_MS * 2 ** (sanitizedFailureCount - 1);
|
|
761
|
+
return Math.min(MAX_UNREAD_COUNT_TRANSIENT_RETRY_MS, exponentialRetryMs);
|
|
762
|
+
}
|
|
763
|
+
function resolveErrorMessage(error) {
|
|
764
|
+
if (error instanceof Error && error.message.length > 0) {
|
|
765
|
+
return error.message;
|
|
766
|
+
}
|
|
767
|
+
if (typeof error === "string" && error.length > 0) {
|
|
768
|
+
return error;
|
|
769
|
+
}
|
|
770
|
+
return "Request failed";
|
|
771
|
+
}
|
|
772
|
+
function asNotifyKitApiError(error) {
|
|
773
|
+
if (typeof error !== "object" || error === null) {
|
|
774
|
+
return null;
|
|
775
|
+
}
|
|
776
|
+
const status = "status" in error ? error.status : void 0;
|
|
777
|
+
const headers = "headers" in error ? error.headers : void 0;
|
|
778
|
+
const resolvedStatus = typeof status === "number" || typeof status === "string" ? status : void 0;
|
|
779
|
+
const resolvedHeaders = typeof headers === "object" && headers !== null ? headers : void 0;
|
|
780
|
+
if (resolvedStatus === void 0 && resolvedHeaders === void 0) {
|
|
781
|
+
return {};
|
|
782
|
+
}
|
|
783
|
+
return {
|
|
784
|
+
...resolvedStatus !== void 0 ? { status: resolvedStatus } : {},
|
|
785
|
+
...resolvedHeaders !== void 0 ? { headers: resolvedHeaders } : {}
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
function useNotifyKitInbox(options) {
|
|
789
|
+
const { client, perPage = DEFAULT_PER_PAGE } = options;
|
|
790
|
+
const store = useNotifyKitStore();
|
|
791
|
+
const state = getInboxState();
|
|
792
|
+
const notifications = computed(() => store.state.notifications);
|
|
793
|
+
const unreadCount = computed(() => store.state.unreadCount);
|
|
794
|
+
const loading = computed(() => store.state.notificationsLoading);
|
|
795
|
+
const error = computed(() => state.error);
|
|
796
|
+
const hasMore = computed(() => state.hasMore);
|
|
797
|
+
const nextPage = computed(() => state.hasMore ? state.currentPage + 1 : null);
|
|
798
|
+
const isUnreadCountCoolingDown = computed(
|
|
799
|
+
() => Date.now() < state.unreadCountRetryAfterUntil
|
|
800
|
+
);
|
|
801
|
+
function reconcileUnreadCountForFullyLoadedList() {
|
|
802
|
+
if (state.hasMore) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
const resolvedUnreadCount = store.state.notifications.filter(
|
|
806
|
+
(notification) => notification.read_at === null
|
|
807
|
+
).length;
|
|
808
|
+
store.setUnreadCount(resolvedUnreadCount);
|
|
809
|
+
}
|
|
810
|
+
async function loadUnreadCount() {
|
|
811
|
+
if (Date.now() < state.unreadCountRetryAfterUntil) {
|
|
812
|
+
return false;
|
|
813
|
+
}
|
|
814
|
+
if (state.unreadCountRequest !== null) {
|
|
815
|
+
return await state.unreadCountRequest;
|
|
816
|
+
}
|
|
817
|
+
const now = Date.now();
|
|
818
|
+
if (now - state.unreadCountLastLoadedAt < MIN_UNREAD_COUNT_REFRESH_INTERVAL_MS) {
|
|
819
|
+
return true;
|
|
820
|
+
}
|
|
821
|
+
store.setUnreadCountLoading(true);
|
|
822
|
+
state.unreadCountRequest = (async () => {
|
|
823
|
+
try {
|
|
824
|
+
const response = await client.getUnreadCount();
|
|
825
|
+
store.setUnreadCount(response.count);
|
|
826
|
+
state.unreadCountLastLoadedAt = Date.now();
|
|
827
|
+
state.unreadCountTransientFailureCount = 0;
|
|
828
|
+
state.unreadCountRetryAfterUntil = 0;
|
|
829
|
+
return true;
|
|
830
|
+
} catch (error2) {
|
|
831
|
+
const apiError = asNotifyKitApiError(error2);
|
|
832
|
+
const statusCode = resolveStatusCode(apiError?.status);
|
|
833
|
+
if (statusCode === 429) {
|
|
834
|
+
const retryAfterHeader = apiError?.headers?.["retry-after"];
|
|
835
|
+
state.unreadCountRetryAfterUntil = Date.now() + resolveRetryAfterMs(retryAfterHeader);
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
if (statusCode === 404) {
|
|
839
|
+
store.setUnreadCount(0);
|
|
840
|
+
state.unreadCountLastLoadedAt = Date.now();
|
|
841
|
+
state.unreadCountTransientFailureCount = 0;
|
|
842
|
+
state.unreadCountRetryAfterUntil = 0;
|
|
843
|
+
return true;
|
|
844
|
+
}
|
|
845
|
+
state.unreadCountTransientFailureCount += 1;
|
|
846
|
+
if (statusCode === void 0 || isServerFailureStatus(statusCode)) {
|
|
847
|
+
state.unreadCountRetryAfterUntil = Date.now() + resolveTransientRetryMs(state.unreadCountTransientFailureCount);
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
state.unreadCountRetryAfterUntil = Date.now() + DEFAULT_UNREAD_COUNT_TRANSIENT_RETRY_MS;
|
|
851
|
+
return false;
|
|
852
|
+
} finally {
|
|
853
|
+
store.setUnreadCountLoading(false);
|
|
854
|
+
}
|
|
855
|
+
})();
|
|
856
|
+
const wasSuccessful = await state.unreadCountRequest.finally(() => {
|
|
857
|
+
state.unreadCountRequest = null;
|
|
858
|
+
});
|
|
859
|
+
return wasSuccessful;
|
|
860
|
+
}
|
|
861
|
+
async function fetchNotifications(page = null, append = false) {
|
|
862
|
+
if (store.state.notificationsLoading) {
|
|
863
|
+
return void 0;
|
|
864
|
+
}
|
|
865
|
+
store.setNotificationsLoading(true);
|
|
866
|
+
state.error = null;
|
|
867
|
+
try {
|
|
868
|
+
const pageNumber = page !== null ? Number(page) : 1;
|
|
869
|
+
const response = await client.listNotifications({
|
|
870
|
+
per_page: perPage,
|
|
871
|
+
page: pageNumber
|
|
872
|
+
});
|
|
873
|
+
const items = [...response.data];
|
|
874
|
+
if (append) {
|
|
875
|
+
store.setNotifications([...store.state.notifications, ...items]);
|
|
876
|
+
} else {
|
|
877
|
+
store.setNotifications(items);
|
|
878
|
+
}
|
|
879
|
+
store.setNotificationsMeta(response.meta);
|
|
880
|
+
store.setLastNotificationsSync(Date.now());
|
|
881
|
+
state.currentPage = response.meta.current_page;
|
|
882
|
+
state.lastPage = response.meta.last_page;
|
|
883
|
+
state.hasMore = response.meta.current_page < response.meta.last_page;
|
|
884
|
+
reconcileUnreadCountForFullyLoadedList();
|
|
885
|
+
return items;
|
|
886
|
+
} catch (error2) {
|
|
887
|
+
state.error = resolveErrorMessage(error2);
|
|
888
|
+
store.setNotificationsMeta(null);
|
|
889
|
+
state.currentPage = 0;
|
|
890
|
+
state.lastPage = 1;
|
|
891
|
+
state.hasMore = false;
|
|
892
|
+
if (!append) {
|
|
893
|
+
store.setNotifications([]);
|
|
894
|
+
store.setUnreadCount(0);
|
|
895
|
+
}
|
|
896
|
+
throw error2;
|
|
897
|
+
} finally {
|
|
898
|
+
store.setNotificationsLoading(false);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
async function markAsRead(notificationId) {
|
|
902
|
+
const notification = store.state.notifications.find((item) => item.id === notificationId);
|
|
903
|
+
const wasUnread = notification?.read_at === null;
|
|
904
|
+
const response = await client.markRead(notificationId);
|
|
905
|
+
if (wasUnread) {
|
|
906
|
+
store.markNotificationRead(notificationId);
|
|
907
|
+
}
|
|
908
|
+
if (typeof response.unread_count === "number") {
|
|
909
|
+
store.setUnreadCount(Math.max(0, response.unread_count));
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
if (wasUnread) {
|
|
913
|
+
store.decrementUnreadCount();
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
async function markAllAsRead() {
|
|
917
|
+
try {
|
|
918
|
+
await client.markAllRead();
|
|
919
|
+
const readTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
920
|
+
const nextNotifications = store.state.notifications.map(
|
|
921
|
+
(notification) => notification.read_at === null ? {
|
|
922
|
+
...notification,
|
|
923
|
+
read_at: readTimestamp
|
|
924
|
+
} : notification
|
|
925
|
+
);
|
|
926
|
+
store.setNotifications(nextNotifications);
|
|
927
|
+
await loadUnreadCount();
|
|
928
|
+
} catch (error2) {
|
|
929
|
+
state.error = resolveErrorMessage(error2);
|
|
930
|
+
throw error2;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
async function deleteNotification(notificationId) {
|
|
934
|
+
await client.deleteNotification(notificationId);
|
|
935
|
+
const notification = store.state.notifications.find((item) => item.id === notificationId);
|
|
936
|
+
const wasUnread = notification?.read_at === null;
|
|
937
|
+
store.removeNotification(notificationId);
|
|
938
|
+
if (wasUnread) {
|
|
939
|
+
store.decrementUnreadCount();
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
async function clearAll() {
|
|
943
|
+
try {
|
|
944
|
+
await client.markAllRead();
|
|
945
|
+
store.setNotifications([]);
|
|
946
|
+
store.setUnreadCount(0);
|
|
947
|
+
} catch (error2) {
|
|
948
|
+
state.error = resolveErrorMessage(error2);
|
|
949
|
+
throw error2;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
async function loadMore() {
|
|
953
|
+
if (!state.hasMore || store.state.notificationsLoading) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
await fetchNotifications(state.currentPage + 1, true);
|
|
957
|
+
}
|
|
958
|
+
function reset() {
|
|
959
|
+
store.reset();
|
|
960
|
+
Object.assign(state, createInitialInboxState());
|
|
961
|
+
}
|
|
962
|
+
return {
|
|
963
|
+
notifications,
|
|
964
|
+
unreadCount,
|
|
965
|
+
loading,
|
|
966
|
+
error,
|
|
967
|
+
hasMore,
|
|
968
|
+
nextPage,
|
|
969
|
+
isUnreadCountCoolingDown,
|
|
970
|
+
loadUnreadCount,
|
|
971
|
+
fetchNotifications,
|
|
972
|
+
loadMore,
|
|
973
|
+
markAsRead,
|
|
974
|
+
markAllAsRead,
|
|
975
|
+
deleteNotification,
|
|
976
|
+
clearAll,
|
|
977
|
+
reset
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// src/composables/useNotifyKitRealtimeState.ts
|
|
982
|
+
function isRecord2(value) {
|
|
983
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
984
|
+
}
|
|
985
|
+
function normalizeNullableString(value) {
|
|
986
|
+
if (value === void 0 || value === null) {
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
return typeof value === "string" ? value : void 0;
|
|
990
|
+
}
|
|
991
|
+
function normalizeModalSpec(value) {
|
|
992
|
+
if (value === void 0 || value === null) {
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
995
|
+
return isModalSpec(value) ? value : void 0;
|
|
996
|
+
}
|
|
997
|
+
function normalizeRealtimeNotificationPayload(payload) {
|
|
998
|
+
if (!isRecord2(payload)) {
|
|
999
|
+
return null;
|
|
1000
|
+
}
|
|
1001
|
+
const id = payload["id"];
|
|
1002
|
+
const key = payload["key"];
|
|
1003
|
+
const category = payload["category"];
|
|
1004
|
+
const level = payload["level"];
|
|
1005
|
+
const title = payload["title"];
|
|
1006
|
+
const body = payload["body"];
|
|
1007
|
+
const createdAt = payload["created_at"];
|
|
1008
|
+
if (typeof id !== "string" || typeof key !== "string" || !isValidCategory(category) || !isValidLevel(level) || typeof title !== "string" || typeof body !== "string" || typeof createdAt !== "string") {
|
|
1009
|
+
return null;
|
|
1010
|
+
}
|
|
1011
|
+
const data = payload["data"];
|
|
1012
|
+
if (data !== void 0 && !isRecord2(data)) {
|
|
1013
|
+
return null;
|
|
1014
|
+
}
|
|
1015
|
+
const actionUrl = normalizeNullableString(payload["action_url"]);
|
|
1016
|
+
const workspaceId = normalizeNullableString(payload["workspace_id"]);
|
|
1017
|
+
const groupKey = normalizeNullableString(payload["group_key"]);
|
|
1018
|
+
const idempotencyKey = normalizeNullableString(payload["idempotency_key"]);
|
|
1019
|
+
const readAt = normalizeNullableString(payload["read_at"]);
|
|
1020
|
+
const modal = normalizeModalSpec(payload["modal"]);
|
|
1021
|
+
if (actionUrl === void 0 || workspaceId === void 0 || groupKey === void 0 || idempotencyKey === void 0 || readAt === void 0 || modal === void 0) {
|
|
1022
|
+
return null;
|
|
1023
|
+
}
|
|
1024
|
+
return {
|
|
1025
|
+
id,
|
|
1026
|
+
key,
|
|
1027
|
+
category,
|
|
1028
|
+
level,
|
|
1029
|
+
title,
|
|
1030
|
+
body,
|
|
1031
|
+
action_url: actionUrl,
|
|
1032
|
+
workspace_id: workspaceId,
|
|
1033
|
+
modal,
|
|
1034
|
+
group_key: groupKey,
|
|
1035
|
+
idempotency_key: idempotencyKey,
|
|
1036
|
+
data: data ?? {},
|
|
1037
|
+
read_at: readAt,
|
|
1038
|
+
created_at: createdAt
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
function useNotifyKitRealtimeState() {
|
|
1042
|
+
const store = useNotifyKitStore();
|
|
1043
|
+
function applyIncomingNotification(notification) {
|
|
1044
|
+
const existingIndex = store.state.notifications.findIndex((item) => item.id === notification.id);
|
|
1045
|
+
if (existingIndex === -1) {
|
|
1046
|
+
store.setNotifications([notification, ...store.state.notifications]);
|
|
1047
|
+
if (notification.read_at === null) {
|
|
1048
|
+
store.incrementUnreadCount();
|
|
1049
|
+
}
|
|
1050
|
+
} else {
|
|
1051
|
+
const existing = store.state.notifications[existingIndex];
|
|
1052
|
+
const wasRead = existing?.read_at !== null;
|
|
1053
|
+
const isNowRead = notification.read_at !== null;
|
|
1054
|
+
const nextNotifications = [...store.state.notifications];
|
|
1055
|
+
nextNotifications.splice(existingIndex, 1);
|
|
1056
|
+
nextNotifications.unshift(notification);
|
|
1057
|
+
store.setNotifications(nextNotifications);
|
|
1058
|
+
if (wasRead && !isNowRead) {
|
|
1059
|
+
store.incrementUnreadCount();
|
|
1060
|
+
} else if (!wasRead && isNowRead) {
|
|
1061
|
+
store.decrementUnreadCount();
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
if (isModalEnabled(notification)) {
|
|
1065
|
+
store.enqueueModal(notification);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
function applyIncomingPayload(payload) {
|
|
1069
|
+
const notification = normalizeRealtimeNotificationPayload(payload);
|
|
1070
|
+
if (notification === null) {
|
|
1071
|
+
return null;
|
|
1072
|
+
}
|
|
1073
|
+
applyIncomingNotification(notification);
|
|
1074
|
+
return notification;
|
|
1075
|
+
}
|
|
1076
|
+
function handleNotificationRead(notificationId) {
|
|
1077
|
+
const notification = store.state.notifications.find((item) => item.id === notificationId);
|
|
1078
|
+
if (notification?.read_at === null) {
|
|
1079
|
+
store.markNotificationRead(notificationId);
|
|
1080
|
+
store.decrementUnreadCount();
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
function handleNotificationDeleted(notificationId) {
|
|
1084
|
+
const notification = store.state.notifications.find((item) => item.id === notificationId);
|
|
1085
|
+
const wasUnread = notification?.read_at === null;
|
|
1086
|
+
store.removeNotification(notificationId);
|
|
1087
|
+
if (wasUnread) {
|
|
1088
|
+
store.decrementUnreadCount();
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return {
|
|
1092
|
+
applyIncomingPayload,
|
|
1093
|
+
applyIncomingNotification,
|
|
1094
|
+
handleNotificationRead,
|
|
1095
|
+
handleNotificationDeleted
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// src/helpers/toastPolicy.ts
|
|
1100
|
+
var DEFAULT_TOAST_CATEGORIES = {
|
|
1101
|
+
workspace: true,
|
|
1102
|
+
security: true,
|
|
1103
|
+
orders: true,
|
|
1104
|
+
social: false,
|
|
1105
|
+
system: true,
|
|
1106
|
+
marketing: true
|
|
1107
|
+
};
|
|
1108
|
+
var DEFAULT_SOUND_LEVELS = ["danger"];
|
|
1109
|
+
var DEFAULT_SOUND_CATEGORIES = ["security"];
|
|
1110
|
+
function isCriticalModal(notification) {
|
|
1111
|
+
return notification.modal !== null && notification.modal.enabled && notification.modal.requires_ack;
|
|
1112
|
+
}
|
|
1113
|
+
function defaultShouldToast(notification, categorySettings) {
|
|
1114
|
+
if (isCriticalModal(notification)) {
|
|
1115
|
+
return false;
|
|
1116
|
+
}
|
|
1117
|
+
return categorySettings[notification.category];
|
|
1118
|
+
}
|
|
1119
|
+
function defaultShouldPlaySound(notification, soundLevels, soundCategories) {
|
|
1120
|
+
if (soundLevels.includes(notification.level)) {
|
|
1121
|
+
return true;
|
|
1122
|
+
}
|
|
1123
|
+
if (soundCategories.includes(notification.category)) {
|
|
1124
|
+
return true;
|
|
1125
|
+
}
|
|
1126
|
+
return false;
|
|
1127
|
+
}
|
|
1128
|
+
var defaultToastPolicy = {
|
|
1129
|
+
shouldToast(notification) {
|
|
1130
|
+
return defaultShouldToast(notification, DEFAULT_TOAST_CATEGORIES);
|
|
1131
|
+
},
|
|
1132
|
+
shouldPlaySound(notification) {
|
|
1133
|
+
return defaultShouldPlaySound(
|
|
1134
|
+
notification,
|
|
1135
|
+
DEFAULT_SOUND_LEVELS,
|
|
1136
|
+
DEFAULT_SOUND_CATEGORIES
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
function createToastPolicy(config) {
|
|
1141
|
+
const categorySettings = {
|
|
1142
|
+
...DEFAULT_TOAST_CATEGORIES,
|
|
1143
|
+
...config.toastCategories
|
|
1144
|
+
};
|
|
1145
|
+
const soundLevels = config.soundLevels ?? DEFAULT_SOUND_LEVELS;
|
|
1146
|
+
const soundCategories = config.soundCategories ?? DEFAULT_SOUND_CATEGORIES;
|
|
1147
|
+
return {
|
|
1148
|
+
shouldToast(notification) {
|
|
1149
|
+
if (config.shouldToast !== void 0) {
|
|
1150
|
+
return config.shouldToast(notification);
|
|
1151
|
+
}
|
|
1152
|
+
return defaultShouldToast(notification, categorySettings);
|
|
1153
|
+
},
|
|
1154
|
+
shouldPlaySound(notification) {
|
|
1155
|
+
if (config.shouldPlaySound !== void 0) {
|
|
1156
|
+
return config.shouldPlaySound(notification);
|
|
1157
|
+
}
|
|
1158
|
+
return defaultShouldPlaySound(notification, soundLevels, soundCategories);
|
|
1159
|
+
}
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// src/helpers/notifyKitRealtimeChannel.ts
|
|
1164
|
+
async function resolveNotifyKitBroadcastChannel(options) {
|
|
1165
|
+
const { client, channel } = options;
|
|
1166
|
+
if (typeof channel === "string" && channel.length > 0) {
|
|
1167
|
+
return channel;
|
|
1168
|
+
}
|
|
1169
|
+
const meResponse = await client.getMe();
|
|
1170
|
+
return meResponse.broadcast_channel;
|
|
1171
|
+
}
|
|
1172
|
+
function bindNotifyKitBroadcastChannel(options) {
|
|
1173
|
+
const { echo, channel, onNotification } = options;
|
|
1174
|
+
echo.private(channel).notification(onNotification);
|
|
1175
|
+
return {
|
|
1176
|
+
channel,
|
|
1177
|
+
unsubscribe: () => {
|
|
1178
|
+
echo.leave(channel);
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
// src/composables/useNotifyKitRealtime.ts
|
|
371
1184
|
function useNotifyKitRealtime(options) {
|
|
372
1185
|
const {
|
|
373
1186
|
echo: echoOption,
|
|
@@ -377,6 +1190,7 @@ function useNotifyKitRealtime(options) {
|
|
|
377
1190
|
onConnectionChange
|
|
378
1191
|
} = options;
|
|
379
1192
|
const store = useNotifyKitStore();
|
|
1193
|
+
const realtimeState = useNotifyKitRealtimeState();
|
|
380
1194
|
const connectionState = ref("disconnected");
|
|
381
1195
|
const currentChannel = ref(null);
|
|
382
1196
|
const isSubscribed = ref(false);
|
|
@@ -390,15 +1204,11 @@ function useNotifyKitRealtime(options) {
|
|
|
390
1204
|
onConnectionChange?.(state);
|
|
391
1205
|
}
|
|
392
1206
|
function handleNotification(payload) {
|
|
393
|
-
|
|
1207
|
+
const notification = realtimeState.applyIncomingPayload(payload);
|
|
1208
|
+
if (notification === null) {
|
|
394
1209
|
return;
|
|
395
1210
|
}
|
|
396
|
-
|
|
397
|
-
store.incrementUnreadCount();
|
|
398
|
-
if (isModalEnabled(payload)) {
|
|
399
|
-
store.enqueueModal(payload);
|
|
400
|
-
}
|
|
401
|
-
onNotification?.(payload);
|
|
1211
|
+
onNotification?.(notification);
|
|
402
1212
|
}
|
|
403
1213
|
async function connect() {
|
|
404
1214
|
if (connectionState.value === "connected" || connectionState.value === "connecting") {
|
|
@@ -406,12 +1216,15 @@ function useNotifyKitRealtime(options) {
|
|
|
406
1216
|
}
|
|
407
1217
|
setConnectionState("connecting");
|
|
408
1218
|
try {
|
|
409
|
-
const
|
|
410
|
-
const channel = meResponse.broadcast_channel;
|
|
1219
|
+
const channel = await resolveNotifyKitBroadcastChannel({ client });
|
|
411
1220
|
currentChannel.value = channel;
|
|
412
1221
|
store.setBroadcastChannel(channel);
|
|
413
1222
|
const echo = getEcho();
|
|
414
|
-
|
|
1223
|
+
bindNotifyKitBroadcastChannel({
|
|
1224
|
+
echo,
|
|
1225
|
+
channel,
|
|
1226
|
+
onNotification: handleNotification
|
|
1227
|
+
});
|
|
415
1228
|
isSubscribed.value = true;
|
|
416
1229
|
setConnectionState("connected");
|
|
417
1230
|
} catch (error) {
|
|
@@ -537,7 +1350,9 @@ function useNotifyKitFallback(options) {
|
|
|
537
1350
|
startPolling();
|
|
538
1351
|
disconnectTimer = null;
|
|
539
1352
|
}, config.disconnectThresholdMs);
|
|
540
|
-
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
if (state === "connected") {
|
|
541
1356
|
if (disconnectTimer !== null) {
|
|
542
1357
|
clearTimeout(disconnectTimer);
|
|
543
1358
|
disconnectTimer = null;
|
|
@@ -566,172 +1381,299 @@ function useNotifyKitFallback(options) {
|
|
|
566
1381
|
pollModals
|
|
567
1382
|
};
|
|
568
1383
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
system: true,
|
|
577
|
-
marketing: true
|
|
578
|
-
};
|
|
579
|
-
var DEFAULT_SOUND_LEVELS = ["danger"];
|
|
580
|
-
var DEFAULT_SOUND_CATEGORIES = ["security"];
|
|
581
|
-
function isCriticalModal(notification) {
|
|
582
|
-
return notification.modal !== null && notification.modal.enabled && notification.modal.requires_ack;
|
|
1384
|
+
function createInitialState() {
|
|
1385
|
+
return {
|
|
1386
|
+
selectedIds: /* @__PURE__ */ new Set(),
|
|
1387
|
+
isSelectionMode: false,
|
|
1388
|
+
isProcessing: false,
|
|
1389
|
+
error: null
|
|
1390
|
+
};
|
|
583
1391
|
}
|
|
584
|
-
function
|
|
585
|
-
|
|
586
|
-
|
|
1392
|
+
function useNotifyKitBulkActions(options) {
|
|
1393
|
+
const { client } = options;
|
|
1394
|
+
const store = useNotifyKitStore();
|
|
1395
|
+
const state = reactive(createInitialState());
|
|
1396
|
+
const selectedCount = computed(() => state.selectedIds.size);
|
|
1397
|
+
const hasSelection = computed(() => state.selectedIds.size > 0);
|
|
1398
|
+
const selectedIdsArray = computed(() => Array.from(state.selectedIds));
|
|
1399
|
+
function toggleSelection(id) {
|
|
1400
|
+
if (state.selectedIds.has(id)) {
|
|
1401
|
+
state.selectedIds.delete(id);
|
|
1402
|
+
} else {
|
|
1403
|
+
state.selectedIds.add(id);
|
|
1404
|
+
}
|
|
587
1405
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
function defaultShouldPlaySound(notification, soundLevels, soundCategories) {
|
|
591
|
-
if (soundLevels.includes(notification.level)) {
|
|
592
|
-
return true;
|
|
1406
|
+
function select(id) {
|
|
1407
|
+
state.selectedIds.add(id);
|
|
593
1408
|
}
|
|
594
|
-
|
|
595
|
-
|
|
1409
|
+
function deselect(id) {
|
|
1410
|
+
state.selectedIds.delete(id);
|
|
596
1411
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
return defaultShouldToast(notification, DEFAULT_TOAST_CATEGORIES);
|
|
602
|
-
},
|
|
603
|
-
shouldPlaySound(notification) {
|
|
604
|
-
return defaultShouldPlaySound(
|
|
605
|
-
notification,
|
|
606
|
-
DEFAULT_SOUND_LEVELS,
|
|
607
|
-
DEFAULT_SOUND_CATEGORIES
|
|
608
|
-
);
|
|
1412
|
+
function selectAll(ids) {
|
|
1413
|
+
for (const id of ids) {
|
|
1414
|
+
state.selectedIds.add(id);
|
|
1415
|
+
}
|
|
609
1416
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
1417
|
+
function clearSelection() {
|
|
1418
|
+
state.selectedIds.clear();
|
|
1419
|
+
}
|
|
1420
|
+
function enterSelectionMode() {
|
|
1421
|
+
state.isSelectionMode = true;
|
|
1422
|
+
}
|
|
1423
|
+
function exitSelectionMode() {
|
|
1424
|
+
state.isSelectionMode = false;
|
|
1425
|
+
state.selectedIds.clear();
|
|
1426
|
+
}
|
|
1427
|
+
async function markSelectedRead() {
|
|
1428
|
+
if (state.selectedIds.size === 0) {
|
|
1429
|
+
return { affected: 0, failed: 0 };
|
|
1430
|
+
}
|
|
1431
|
+
state.isProcessing = true;
|
|
1432
|
+
state.error = null;
|
|
1433
|
+
try {
|
|
1434
|
+
const ids = Array.from(state.selectedIds);
|
|
1435
|
+
const result = await client.bulkMarkRead(ids);
|
|
1436
|
+
for (const id of ids) {
|
|
1437
|
+
store.markNotificationRead(id);
|
|
622
1438
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
shouldPlaySound(notification) {
|
|
626
|
-
if (config.shouldPlaySound !== void 0) {
|
|
627
|
-
return config.shouldPlaySound(notification);
|
|
1439
|
+
if (result.affected > 0) {
|
|
1440
|
+
store.setUnreadCount(Math.max(0, store.state.unreadCount - result.affected));
|
|
628
1441
|
}
|
|
629
|
-
|
|
1442
|
+
clearSelection();
|
|
1443
|
+
return result;
|
|
1444
|
+
} catch (error) {
|
|
1445
|
+
state.error = error instanceof Error ? error.message : "Failed to mark as read";
|
|
1446
|
+
throw error;
|
|
1447
|
+
} finally {
|
|
1448
|
+
state.isProcessing = false;
|
|
630
1449
|
}
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
// src/helpers/modalHelpers.ts
|
|
635
|
-
function getModalAriaAttributes(notification, ids) {
|
|
636
|
-
const ariaRole = notification.modal?.accessibility?.aria_role ?? "alertdialog";
|
|
637
|
-
return {
|
|
638
|
-
role: ariaRole,
|
|
639
|
-
"aria-modal": "true",
|
|
640
|
-
"aria-labelledby": ids.titleId,
|
|
641
|
-
"aria-describedby": ids.bodyId
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
function getEscapeKeyHandler(notification, callbacks) {
|
|
645
|
-
const behavior = notification.modal?.accessibility?.escape_key_behavior ?? "close";
|
|
646
|
-
if (behavior === "disabled") {
|
|
647
|
-
return null;
|
|
648
1450
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
case "snooze": {
|
|
657
|
-
event.preventDefault();
|
|
658
|
-
const minSnooze = notification.modal?.snooze_options_minutes[0] ?? 15;
|
|
659
|
-
callbacks.onSnooze(minSnooze);
|
|
660
|
-
break;
|
|
1451
|
+
async function markAllRead(filters) {
|
|
1452
|
+
state.isProcessing = true;
|
|
1453
|
+
state.error = null;
|
|
1454
|
+
try {
|
|
1455
|
+
const result = await client.bulkMarkAllRead(filters);
|
|
1456
|
+
if (filters === void 0) {
|
|
1457
|
+
store.setUnreadCount(0);
|
|
661
1458
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
function trapFocus(event) {
|
|
670
|
-
if (event.key !== "Tab") return;
|
|
671
|
-
const focusable = modalElement.querySelectorAll(focusableSelector);
|
|
672
|
-
if (focusable.length === 0) return;
|
|
673
|
-
const first = focusable[0];
|
|
674
|
-
const last = focusable[focusable.length - 1];
|
|
675
|
-
if (first === void 0 || last === void 0) return;
|
|
676
|
-
if (event.shiftKey && document.activeElement === first) {
|
|
677
|
-
event.preventDefault();
|
|
678
|
-
last.focus();
|
|
679
|
-
} else if (!event.shiftKey && document.activeElement === last) {
|
|
680
|
-
event.preventDefault();
|
|
681
|
-
first.focus();
|
|
1459
|
+
clearSelection();
|
|
1460
|
+
return result;
|
|
1461
|
+
} catch (error) {
|
|
1462
|
+
state.error = error instanceof Error ? error.message : "Failed to mark all as read";
|
|
1463
|
+
throw error;
|
|
1464
|
+
} finally {
|
|
1465
|
+
state.isProcessing = false;
|
|
682
1466
|
}
|
|
683
1467
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
if (trapHandler !== null) {
|
|
696
|
-
modalElement.removeEventListener("keydown", trapHandler);
|
|
697
|
-
trapHandler = null;
|
|
1468
|
+
async function archiveSelected() {
|
|
1469
|
+
if (state.selectedIds.size === 0) {
|
|
1470
|
+
return { affected: 0, failed: 0 };
|
|
1471
|
+
}
|
|
1472
|
+
state.isProcessing = true;
|
|
1473
|
+
state.error = null;
|
|
1474
|
+
try {
|
|
1475
|
+
const ids = Array.from(state.selectedIds);
|
|
1476
|
+
const result = await client.bulkArchive(ids);
|
|
1477
|
+
for (const id of ids) {
|
|
1478
|
+
store.removeNotification(id);
|
|
698
1479
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
1480
|
+
clearSelection();
|
|
1481
|
+
return result;
|
|
1482
|
+
} catch (error) {
|
|
1483
|
+
state.error = error instanceof Error ? error.message : "Failed to archive";
|
|
1484
|
+
throw error;
|
|
1485
|
+
} finally {
|
|
1486
|
+
state.isProcessing = false;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
async function archiveAll(filters) {
|
|
1490
|
+
state.isProcessing = true;
|
|
1491
|
+
state.error = null;
|
|
1492
|
+
try {
|
|
1493
|
+
const result = await client.bulkArchiveAll(filters);
|
|
1494
|
+
clearSelection();
|
|
1495
|
+
return result;
|
|
1496
|
+
} catch (error) {
|
|
1497
|
+
state.error = error instanceof Error ? error.message : "Failed to archive all";
|
|
1498
|
+
throw error;
|
|
1499
|
+
} finally {
|
|
1500
|
+
state.isProcessing = false;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
async function deleteSelected() {
|
|
1504
|
+
if (state.selectedIds.size === 0) {
|
|
1505
|
+
return { affected: 0, failed: 0 };
|
|
1506
|
+
}
|
|
1507
|
+
state.isProcessing = true;
|
|
1508
|
+
state.error = null;
|
|
1509
|
+
try {
|
|
1510
|
+
const ids = Array.from(state.selectedIds);
|
|
1511
|
+
const result = await client.bulkDelete(ids);
|
|
1512
|
+
for (const id of ids) {
|
|
1513
|
+
store.removeNotification(id);
|
|
702
1514
|
}
|
|
1515
|
+
clearSelection();
|
|
1516
|
+
return result;
|
|
1517
|
+
} catch (error) {
|
|
1518
|
+
state.error = error instanceof Error ? error.message : "Failed to delete";
|
|
1519
|
+
throw error;
|
|
1520
|
+
} finally {
|
|
1521
|
+
state.isProcessing = false;
|
|
703
1522
|
}
|
|
1523
|
+
}
|
|
1524
|
+
async function deleteAll(filters) {
|
|
1525
|
+
state.isProcessing = true;
|
|
1526
|
+
state.error = null;
|
|
1527
|
+
try {
|
|
1528
|
+
const result = await client.bulkDeleteAll(filters);
|
|
1529
|
+
clearSelection();
|
|
1530
|
+
return result;
|
|
1531
|
+
} catch (error) {
|
|
1532
|
+
state.error = error instanceof Error ? error.message : "Failed to delete all";
|
|
1533
|
+
throw error;
|
|
1534
|
+
} finally {
|
|
1535
|
+
state.isProcessing = false;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
function reset() {
|
|
1539
|
+
Object.assign(state, createInitialState());
|
|
1540
|
+
}
|
|
1541
|
+
return {
|
|
1542
|
+
state: readonly(state),
|
|
1543
|
+
selectedCount,
|
|
1544
|
+
hasSelection,
|
|
1545
|
+
selectedIdsArray,
|
|
1546
|
+
toggleSelection,
|
|
1547
|
+
select,
|
|
1548
|
+
deselect,
|
|
1549
|
+
selectAll,
|
|
1550
|
+
clearSelection,
|
|
1551
|
+
enterSelectionMode,
|
|
1552
|
+
exitSelectionMode,
|
|
1553
|
+
markSelectedRead,
|
|
1554
|
+
markAllRead,
|
|
1555
|
+
archiveSelected,
|
|
1556
|
+
archiveAll,
|
|
1557
|
+
deleteSelected,
|
|
1558
|
+
deleteAll,
|
|
1559
|
+
reset
|
|
704
1560
|
};
|
|
705
1561
|
}
|
|
706
|
-
function
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
1562
|
+
function createInitialState2() {
|
|
1563
|
+
return {
|
|
1564
|
+
query: "",
|
|
1565
|
+
results: [],
|
|
1566
|
+
total: 0,
|
|
1567
|
+
isSearching: false,
|
|
1568
|
+
hasSearched: false,
|
|
1569
|
+
filters: null,
|
|
1570
|
+
error: null
|
|
712
1571
|
};
|
|
713
|
-
if (action.primary === true) {
|
|
714
|
-
attrs["data-primary"] = true;
|
|
715
|
-
}
|
|
716
|
-
return attrs;
|
|
717
|
-
}
|
|
718
|
-
function isCriticalModal2(notification) {
|
|
719
|
-
return notification.modal?.enabled === true && notification.modal.requires_ack === true;
|
|
720
1572
|
}
|
|
721
|
-
function
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
1573
|
+
function useNotifyKitSearch(options) {
|
|
1574
|
+
const { client, minQueryLength = 3 } = options;
|
|
1575
|
+
const state = reactive(createInitialState2());
|
|
1576
|
+
const savedFilters = ref([]);
|
|
1577
|
+
const savedFiltersLoading = ref(false);
|
|
1578
|
+
const hasResults = computed(() => state.results.length > 0);
|
|
1579
|
+
const resultCount = computed(() => state.results.length);
|
|
1580
|
+
const isValidQuery = computed(() => state.query.length >= minQueryLength);
|
|
1581
|
+
async function search(query, filters) {
|
|
1582
|
+
state.query = query;
|
|
1583
|
+
if (query.length < minQueryLength) {
|
|
1584
|
+
state.error = `Search query must be at least ${String(minQueryLength)} characters`;
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
state.isSearching = true;
|
|
1588
|
+
state.error = null;
|
|
1589
|
+
try {
|
|
1590
|
+
const effectiveFilters = filters ?? state.filters ?? void 0;
|
|
1591
|
+
const result = await client.search(query, effectiveFilters);
|
|
1592
|
+
state.results = [...result.data];
|
|
1593
|
+
state.total = result.total;
|
|
1594
|
+
state.hasSearched = true;
|
|
1595
|
+
if (filters !== void 0) {
|
|
1596
|
+
state.filters = filters;
|
|
1597
|
+
}
|
|
1598
|
+
} catch (error) {
|
|
1599
|
+
state.error = error instanceof Error ? error.message : "Search failed";
|
|
1600
|
+
state.results = [];
|
|
1601
|
+
state.total = 0;
|
|
1602
|
+
} finally {
|
|
1603
|
+
state.isSearching = false;
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
function clearSearch() {
|
|
1607
|
+
state.query = "";
|
|
1608
|
+
state.results = [];
|
|
1609
|
+
state.total = 0;
|
|
1610
|
+
state.hasSearched = false;
|
|
1611
|
+
state.error = null;
|
|
1612
|
+
}
|
|
1613
|
+
function setFilters(filters) {
|
|
1614
|
+
state.filters = filters;
|
|
728
1615
|
}
|
|
729
|
-
|
|
1616
|
+
async function loadSavedFilters() {
|
|
1617
|
+
savedFiltersLoading.value = true;
|
|
1618
|
+
try {
|
|
1619
|
+
savedFilters.value = await client.getSavedFilters();
|
|
1620
|
+
} catch {
|
|
1621
|
+
} finally {
|
|
1622
|
+
savedFiltersLoading.value = false;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
async function applyFilter(filter) {
|
|
1626
|
+
const searchFilters = {};
|
|
1627
|
+
const categoryValue = filter.filters["category"];
|
|
1628
|
+
const levelValue = filter.filters["level"];
|
|
1629
|
+
if (typeof categoryValue === "string") {
|
|
1630
|
+
searchFilters.category = categoryValue;
|
|
1631
|
+
}
|
|
1632
|
+
if (filter.filters["unread_only"] === true) {
|
|
1633
|
+
searchFilters.unread = true;
|
|
1634
|
+
}
|
|
1635
|
+
if (typeof levelValue === "string") {
|
|
1636
|
+
searchFilters.level = levelValue;
|
|
1637
|
+
}
|
|
1638
|
+
state.filters = searchFilters;
|
|
1639
|
+
if (state.query.length >= minQueryLength) {
|
|
1640
|
+
await search(state.query, searchFilters);
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
async function saveFilter(name, filters) {
|
|
1644
|
+
const createdFilter = await client.saveFilter(name, filters);
|
|
1645
|
+
savedFilters.value = [...savedFilters.value, createdFilter];
|
|
1646
|
+
return createdFilter;
|
|
1647
|
+
}
|
|
1648
|
+
async function deleteFilter(filterId) {
|
|
1649
|
+
await client.deleteFilter(filterId);
|
|
1650
|
+
savedFilters.value = savedFilters.value.filter((filter) => filter.id !== filterId);
|
|
1651
|
+
}
|
|
1652
|
+
function reset() {
|
|
1653
|
+
Object.assign(state, createInitialState2());
|
|
1654
|
+
savedFilters.value = [];
|
|
1655
|
+
}
|
|
1656
|
+
return {
|
|
1657
|
+
state: readonly(state),
|
|
1658
|
+
hasResults,
|
|
1659
|
+
resultCount,
|
|
1660
|
+
isValidQuery,
|
|
1661
|
+
savedFilters,
|
|
1662
|
+
savedFiltersLoading,
|
|
1663
|
+
search,
|
|
1664
|
+
clearSearch,
|
|
1665
|
+
setFilters,
|
|
1666
|
+
loadSavedFilters,
|
|
1667
|
+
applyFilter,
|
|
1668
|
+
saveFilter,
|
|
1669
|
+
deleteFilter,
|
|
1670
|
+
reset
|
|
1671
|
+
};
|
|
730
1672
|
}
|
|
731
1673
|
|
|
732
1674
|
// src/index.ts
|
|
733
1675
|
var VERSION = "0.1.0";
|
|
734
1676
|
|
|
735
|
-
export { ENDPOINTS, NOTIFICATION_CATEGORIES, NOTIFICATION_LEVELS, NOTIFY_KIT_CLIENT_KEY, NotifyKitApiError, NotifyKitClient, VERSION,
|
|
1677
|
+
export { ENDPOINTS, NOTIFICATION_CATEGORIES, NOTIFICATION_LEVELS, NOTIFY_KIT_CLIENT_KEY, NotifyKitApiError, NotifyKitClient, VERSION, bindNotifyKitBroadcastChannel, createNotifyKitClient, createToastPolicy, defaultToastPolicy, isMeResponse, isModalEnabled, isModalSpec, isNotifyKitNotification, isNotifyKitPreferenceSettings, isNotifyKitQuietHours, isPaginationMeta, isUnreadCountResponse, isValidCategory, isValidLevel, provideNotifyKitClient, resetNotifyKitInbox, resolveNotifyKitBroadcastChannel, useNotifyKitBulkActions, useNotifyKitClient, useNotifyKitFallback, useNotifyKitInbox, useNotifyKitRealtime, useNotifyKitRealtimeState, useNotifyKitSearch };
|
|
736
1678
|
//# sourceMappingURL=index.js.map
|
|
737
1679
|
//# sourceMappingURL=index.js.map
|