@ttt-productions/notification-core 0.12.0 → 0.14.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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/react/components/NotificationHistoryList.d.ts +9 -0
- package/dist/react/components/NotificationHistoryList.d.ts.map +1 -0
- package/dist/react/components/NotificationHistoryList.js +41 -0
- package/dist/react/components/NotificationHistoryList.js.map +1 -0
- package/dist/react/components/NotificationList.d.ts +1 -1
- package/dist/react/components/NotificationList.d.ts.map +1 -1
- package/dist/react/components/NotificationList.js +11 -7
- package/dist/react/components/NotificationList.js.map +1 -1
- package/dist/react/components/index.d.ts +1 -0
- package/dist/react/components/index.d.ts.map +1 -1
- package/dist/react/components/index.js +1 -0
- package/dist/react/components/index.js.map +1 -1
- package/dist/react/hooks/index.d.ts +1 -0
- package/dist/react/hooks/index.d.ts.map +1 -1
- package/dist/react/hooks/index.js +1 -0
- package/dist/react/hooks/index.js.map +1 -1
- package/dist/react/hooks/useArchiveAllNotifications.d.ts +19 -8
- package/dist/react/hooks/useArchiveAllNotifications.d.ts.map +1 -1
- package/dist/react/hooks/useArchiveAllNotifications.js +54 -31
- package/dist/react/hooks/useArchiveAllNotifications.js.map +1 -1
- package/dist/react/hooks/useNotificationHistory.d.ts +17 -0
- package/dist/react/hooks/useNotificationHistory.d.ts.map +1 -0
- package/dist/react/hooks/useNotificationHistory.js +46 -0
- package/dist/react/hooks/useNotificationHistory.js.map +1 -0
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +2 -2
- package/dist/react/index.js.map +1 -1
- package/dist/types.d.ts +106 -27
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { NotificationDoc, PendingNotification, NotificationCategoryConfig, NotificationTypeConfig, NotificationSystemConfig, UseActiveNotificationsOptions, UseUnreadCountOptions, UseArchiveNotificationOptions, UseArchiveAllNotificationsOptions,
|
|
1
|
+
export type { NotificationDoc, PendingNotification, NotificationCategoryConfig, NotificationTypeConfig, NotificationSystemConfig, UseActiveNotificationsOptions, UseNotificationHistoryOptions, NotificationHistoryItem, UseUnreadCountOptions, UseArchiveNotificationOptions, UseArchiveAllNotificationsOptions, ArchiveAllJobStatus, EnqueueArchiveAllResult, ArchiveAllJobSnapshot, ArchiveAllPollResult, NotificationListProps, NotificationHistoryListProps, NotificationEmptyStateProps, NotificationUnreadBadgeProps, } from './types.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,6BAA6B,EAC7B,iCAAiC,EACjC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,6BAA6B,EAC7B,6BAA6B,EAC7B,uBAAuB,EACvB,qBAAqB,EACrB,6BAA6B,EAC7B,iCAAiC,EACjC,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,4BAA4B,EAC5B,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { NotificationHistoryListProps } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Read-only, paginated list of ARCHIVED notifications (the history tier). Rows do
|
|
4
|
+
* not mutate state on click — archive is one-way; there is no re-archive. When
|
|
5
|
+
* `onNotificationClick` is supplied, rows are interactive (e.g. navigate to
|
|
6
|
+
* `targetPath`); otherwise they render non-interactive.
|
|
7
|
+
*/
|
|
8
|
+
export declare function NotificationHistoryList({ config, userId, category, onNotificationClick, pageSize, staleTime, emptyText, }: NotificationHistoryListProps): import("react").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=NotificationHistoryList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationHistoryList.d.ts","sourceRoot":"","sources":["../../../src/react/components/NotificationHistoryList.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA2B,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAE5F;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,QAAQ,EACR,SAAS,EACT,SAAS,GACV,EAAE,4BAA4B,+BA8E9B"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
import { Badge, Button } from '@ttt-productions/ui-core/react';
|
|
5
|
+
import { useNotificationHistory } from '../hooks/useNotificationHistory.js';
|
|
6
|
+
import { NotificationEmptyState } from './NotificationEmptyState.js';
|
|
7
|
+
import { formatRelativeTime } from './relative-time.js';
|
|
8
|
+
/**
|
|
9
|
+
* Read-only, paginated list of ARCHIVED notifications (the history tier). Rows do
|
|
10
|
+
* not mutate state on click — archive is one-way; there is no re-archive. When
|
|
11
|
+
* `onNotificationClick` is supplied, rows are interactive (e.g. navigate to
|
|
12
|
+
* `targetPath`); otherwise they render non-interactive.
|
|
13
|
+
*/
|
|
14
|
+
export function NotificationHistoryList({ config, userId, category, onNotificationClick, pageSize, staleTime, emptyText, }) {
|
|
15
|
+
const { data: notifications, isLoading, hasNextPage, nextPage, } = useNotificationHistory({
|
|
16
|
+
config,
|
|
17
|
+
userId,
|
|
18
|
+
category,
|
|
19
|
+
pageSize,
|
|
20
|
+
staleTime,
|
|
21
|
+
});
|
|
22
|
+
const getTypeIcon = useCallback((type) => config.types[type]?.icon ?? '🔔', [config]);
|
|
23
|
+
const interactive = typeof onNotificationClick === 'function';
|
|
24
|
+
return (_jsx("div", { className: "ntf-list ntf-list-history", children: _jsx("div", { className: "ntf-list-body", children: isLoading ? (_jsx("div", { className: "ntf-loading", children: "Loading..." })) : !notifications || notifications.length === 0 ? (_jsx(NotificationEmptyState, { text: emptyText })) : (_jsxs(_Fragment, { children: [notifications.map((notification) => {
|
|
25
|
+
const interactiveProps = interactive
|
|
26
|
+
? {
|
|
27
|
+
role: 'button',
|
|
28
|
+
tabIndex: 0,
|
|
29
|
+
onClick: () => onNotificationClick?.(notification),
|
|
30
|
+
onKeyDown: (e) => {
|
|
31
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
onNotificationClick?.(notification);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
: {};
|
|
38
|
+
return (_jsxs("div", { className: "ntf-item ntf-item-archived", ...interactiveProps, children: [_jsx("div", { className: "ntf-item-icon", children: getTypeIcon(notification.type) }), _jsxs("div", { className: "ntf-item-content", children: [_jsx("div", { className: "ntf-item-title", children: notification.title }), _jsx("div", { className: "ntf-item-message", children: notification.message }), _jsx("div", { className: "ntf-item-timestamp", children: formatRelativeTime(notification.archivedAt) })] }), notification.count > 1 && (_jsx("div", { className: "ntf-item-count", children: _jsxs(Badge, { variant: "secondary", children: ["\u00D7", notification.count] }) }))] }, notification.archiveOccurrenceId));
|
|
39
|
+
}), hasNextPage && (_jsx("div", { className: "ntf-list-footer", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: nextPage, children: "Load more" }) }))] })) }) }));
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=NotificationHistoryList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationHistoryList.js","sourceRoot":"","sources":["../../../src/react/components/NotificationHistoryList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2,5 +2,5 @@ import type { NotificationListProps } from '../../types.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Scrollable list of active notifications with click-to-archive and clear-all.
|
|
4
4
|
*/
|
|
5
|
-
export declare function NotificationList({ config, userId, category, onNotificationClick, archiveFn,
|
|
5
|
+
export declare function NotificationList({ config, userId, category, onNotificationClick, archiveFn, enqueueArchiveAllFn, getArchiveAllStatusFn, onClearAll, refetchInterval, emptyText, }: NotificationListProps): import("react").JSX.Element;
|
|
6
6
|
//# sourceMappingURL=NotificationList.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationList.d.ts","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,
|
|
1
|
+
{"version":3,"file":"NotificationList.d.ts","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,mBAAmB,EACnB,qBAAqB,EACrB,UAAU,EACV,eAAe,EACf,SAAS,GACV,EAAE,qBAAqB,+BA+IvB"}
|
|
@@ -10,7 +10,7 @@ import { formatRelativeTime } from './relative-time.js';
|
|
|
10
10
|
/**
|
|
11
11
|
* Scrollable list of active notifications with click-to-archive and clear-all.
|
|
12
12
|
*/
|
|
13
|
-
export function NotificationList({ config, userId, category, onNotificationClick, archiveFn,
|
|
13
|
+
export function NotificationList({ config, userId, category, onNotificationClick, archiveFn, enqueueArchiveAllFn, getArchiveAllStatusFn, onClearAll, refetchInterval, emptyText, }) {
|
|
14
14
|
const { data: notifications, isLoading, hasNextPage, nextPage, } = useActiveNotifications({
|
|
15
15
|
config,
|
|
16
16
|
userId,
|
|
@@ -25,7 +25,8 @@ export function NotificationList({ config, userId, category, onNotificationClick
|
|
|
25
25
|
const archiveAllMutation = useArchiveAllNotifications({
|
|
26
26
|
userId,
|
|
27
27
|
category,
|
|
28
|
-
|
|
28
|
+
enqueueArchiveAllFn,
|
|
29
|
+
getArchiveAllStatusFn,
|
|
29
30
|
});
|
|
30
31
|
const handleNotificationClick = useCallback(async (notification) => {
|
|
31
32
|
try {
|
|
@@ -36,9 +37,11 @@ export function NotificationList({ config, userId, category, onNotificationClick
|
|
|
36
37
|
}
|
|
37
38
|
onNotificationClick(notification);
|
|
38
39
|
}, [archiveMutation, onNotificationClick]);
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
40
|
+
// Surface a failed/incomplete clear instead of swallowing it. `onClearAll` (and the tray-closing
|
|
41
|
+
// side effects the app wires to it) fires ONLY when the server job fully drained the category —
|
|
42
|
+
// otherwise the user keeps the "notifications remain — try again" affordance. The poller resolves
|
|
43
|
+
// with an explicit terminal result (`complete` | `incomplete` | `failed`) and only rejects on a
|
|
44
|
+
// hard enqueue/poll throw.
|
|
42
45
|
const [clearIncomplete, setClearIncomplete] = useState(false);
|
|
43
46
|
const handleClearAll = useCallback(async () => {
|
|
44
47
|
setClearIncomplete(false);
|
|
@@ -47,12 +50,13 @@ export function NotificationList({ config, userId, category, onNotificationClick
|
|
|
47
50
|
result = await archiveAllMutation.mutateAsync();
|
|
48
51
|
}
|
|
49
52
|
catch {
|
|
50
|
-
// Hard failure: do not fire onClearAll; surface the retry affordance.
|
|
53
|
+
// Hard failure (enqueue/poll threw): do not fire onClearAll; surface the retry affordance.
|
|
51
54
|
setClearIncomplete(true);
|
|
52
55
|
return;
|
|
53
56
|
}
|
|
54
57
|
if (!result.complete) {
|
|
55
|
-
//
|
|
58
|
+
// Job terminated without fully draining the category (incomplete/failed) — keep the
|
|
59
|
+
// notifications and prompt a retry.
|
|
56
60
|
setClearIncomplete(true);
|
|
57
61
|
return;
|
|
58
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationList.js","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGxD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,
|
|
1
|
+
{"version":3,"file":"NotificationList.js","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { NotificationList } from './NotificationList.js';
|
|
2
|
+
export { NotificationHistoryList } from './NotificationHistoryList.js';
|
|
2
3
|
export { NotificationEmptyState } from './NotificationEmptyState.js';
|
|
3
4
|
export { NotificationUnreadBadge } from './NotificationUnreadBadge.js';
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { NotificationList } from './NotificationList.js';
|
|
2
|
+
export { NotificationHistoryList } from './NotificationHistoryList.js';
|
|
2
3
|
export { NotificationEmptyState } from './NotificationEmptyState.js';
|
|
3
4
|
export { NotificationUnreadBadge } from './NotificationUnreadBadge.js';
|
|
4
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { useActiveNotifications } from './useActiveNotifications.js';
|
|
2
|
+
export { useNotificationHistory } from './useNotificationHistory.js';
|
|
2
3
|
export { useUnreadCount } from './useUnreadCount.js';
|
|
3
4
|
export { useArchiveNotification } from './useArchiveNotification.js';
|
|
4
5
|
export { useArchiveAllNotifications } from './useArchiveAllNotifications.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { useActiveNotifications } from './useActiveNotifications.js';
|
|
2
|
+
export { useNotificationHistory } from './useNotificationHistory.js';
|
|
2
3
|
export { useUnreadCount } from './useUnreadCount.js';
|
|
3
4
|
export { useArchiveNotification } from './useArchiveNotification.js';
|
|
4
5
|
export { useArchiveAllNotifications } from './useArchiveAllNotifications.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC"}
|
|
@@ -1,22 +1,33 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ArchiveAllPollResult, UseArchiveAllNotificationsOptions } from '../../types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Trigger + poll a SERVER-OWNED archive-all job for one notification category.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* This is a THIN STATUS POLLER, not a client loop. It:
|
|
6
|
+
* 1. enqueues ONE server job via `enqueueArchiveAllFn(category)` (the category — the tab the tray
|
|
7
|
+
* was invoked on — flows into the job, preserving per-tab scoping: the worker archives ONLY
|
|
8
|
+
* that category's active cards, never all tabs);
|
|
9
|
+
* 2. polls `getArchiveAllStatusFn(jobId)` until the job reaches a terminal state
|
|
10
|
+
* (`complete` | `incomplete` | `failed`);
|
|
11
|
+
* 3. resolves an {@link ArchiveAllPollResult} the caller gates side effects on, and invalidates
|
|
12
|
+
* the read keys on a completed drain.
|
|
13
|
+
*
|
|
14
|
+
* All paging + ownership-checked per-card deletion happen server-side. The hook performs no client
|
|
15
|
+
* Firestore writes and never chains archive calls. The generic package hardcodes no callable name —
|
|
16
|
+
* the app injects both adapters.
|
|
8
17
|
*
|
|
9
18
|
* @example
|
|
10
19
|
* ```tsx
|
|
11
|
-
* const
|
|
20
|
+
* const enqueue = httpsCallable(functions, 'enqueueArchiveAll');
|
|
21
|
+
* const getStatus = httpsCallable(functions, 'getArchiveAllStatus');
|
|
12
22
|
* const archiveAll = useArchiveAllNotifications({
|
|
13
23
|
* userId: user.uid,
|
|
14
24
|
* category: 'user',
|
|
15
|
-
*
|
|
25
|
+
* enqueueArchiveAllFn: (category) => enqueue({ category }).then((r) => r.data),
|
|
26
|
+
* getArchiveAllStatusFn: (jobId) => getStatus({ jobId }).then((r) => r.data),
|
|
16
27
|
* });
|
|
17
28
|
*
|
|
18
29
|
* archiveAll.mutate();
|
|
19
30
|
* ```
|
|
20
31
|
*/
|
|
21
|
-
export declare function useArchiveAllNotifications({ userId, category,
|
|
32
|
+
export declare function useArchiveAllNotifications({ userId, category, enqueueArchiveAllFn, getArchiveAllStatusFn, pollIntervalMs, maxPolls, invalidateKeys, }: UseArchiveAllNotificationsOptions): import("@tanstack/react-query").UseMutationResult<ArchiveAllPollResult, Error, void, unknown>;
|
|
22
33
|
//# sourceMappingURL=useArchiveAllNotifications.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useArchiveAllNotifications.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"useArchiveAllNotifications.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,oBAAoB,EACpB,iCAAiC,EAClC,MAAM,gBAAgB,CAAC;AASxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,qBAAqB,EACrB,cAAyC,EACzC,QAA4B,EAC5B,cAAc,GACf,EAAE,iCAAiC,iGAqDnC"}
|
|
@@ -1,25 +1,41 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
const DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
4
|
+
const DEFAULT_MAX_POLLS = 120; // ~3 min at the default interval
|
|
5
|
+
function sleep(ms) {
|
|
6
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
}
|
|
3
8
|
/**
|
|
4
|
-
*
|
|
9
|
+
* Trigger + poll a SERVER-OWNED archive-all job for one notification category.
|
|
10
|
+
*
|
|
11
|
+
* This is a THIN STATUS POLLER, not a client loop. It:
|
|
12
|
+
* 1. enqueues ONE server job via `enqueueArchiveAllFn(category)` (the category — the tab the tray
|
|
13
|
+
* was invoked on — flows into the job, preserving per-tab scoping: the worker archives ONLY
|
|
14
|
+
* that category's active cards, never all tabs);
|
|
15
|
+
* 2. polls `getArchiveAllStatusFn(jobId)` until the job reaches a terminal state
|
|
16
|
+
* (`complete` | `incomplete` | `failed`);
|
|
17
|
+
* 3. resolves an {@link ArchiveAllPollResult} the caller gates side effects on, and invalidates
|
|
18
|
+
* the read keys on a completed drain.
|
|
5
19
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* app
|
|
20
|
+
* All paging + ownership-checked per-card deletion happen server-side. The hook performs no client
|
|
21
|
+
* Firestore writes and never chains archive calls. The generic package hardcodes no callable name —
|
|
22
|
+
* the app injects both adapters.
|
|
9
23
|
*
|
|
10
24
|
* @example
|
|
11
25
|
* ```tsx
|
|
12
|
-
* const
|
|
26
|
+
* const enqueue = httpsCallable(functions, 'enqueueArchiveAll');
|
|
27
|
+
* const getStatus = httpsCallable(functions, 'getArchiveAllStatus');
|
|
13
28
|
* const archiveAll = useArchiveAllNotifications({
|
|
14
29
|
* userId: user.uid,
|
|
15
30
|
* category: 'user',
|
|
16
|
-
*
|
|
31
|
+
* enqueueArchiveAllFn: (category) => enqueue({ category }).then((r) => r.data),
|
|
32
|
+
* getArchiveAllStatusFn: (jobId) => getStatus({ jobId }).then((r) => r.data),
|
|
17
33
|
* });
|
|
18
34
|
*
|
|
19
35
|
* archiveAll.mutate();
|
|
20
36
|
* ```
|
|
21
37
|
*/
|
|
22
|
-
export function useArchiveAllNotifications({ userId, category,
|
|
38
|
+
export function useArchiveAllNotifications({ userId, category, enqueueArchiveAllFn, getArchiveAllStatusFn, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, maxPolls = DEFAULT_MAX_POLLS, invalidateKeys, }) {
|
|
23
39
|
const queryClient = useQueryClient();
|
|
24
40
|
const defaultInvalidateKeys = [
|
|
25
41
|
['notifications', 'active', category, userId],
|
|
@@ -27,37 +43,44 @@ export function useArchiveAllNotifications({ userId, category, archiveAllFn, inv
|
|
|
27
43
|
['notifications', 'history', category, userId],
|
|
28
44
|
];
|
|
29
45
|
return useMutation({
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
// gates side effects on (it is NOT a plain success — see ArchiveAllLoopResult).
|
|
46
|
+
// Server-owned archive-all: enqueue ONE job scoped to `category`, then poll its status until it
|
|
47
|
+
// reaches a terminal state. No browser loop, no chain of archive transactions. The mutation
|
|
48
|
+
// resolves with an explicit terminal result (never throws for an incomplete drain) — `complete`
|
|
49
|
+
// is the load-bearing flag callers gate post-clear side effects on.
|
|
35
50
|
mutationFn: async () => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
const { jobId } = await enqueueArchiveAllFn(category);
|
|
52
|
+
// Poll until terminal or until the guard bound is hit. A job that never terminates resolves
|
|
53
|
+
// `incomplete` (mirrors the old loop's honest "some remain" result) rather than hanging. The
|
|
54
|
+
// first poll happens immediately so a fast/already-complete job resolves without a delay.
|
|
55
|
+
let lastArchived = 0;
|
|
56
|
+
for (let poll = 0; poll < maxPolls; poll += 1) {
|
|
57
|
+
const snap = await getArchiveAllStatusFn(jobId);
|
|
58
|
+
lastArchived = snap.archived ?? 0;
|
|
59
|
+
if (snap.state === 'complete') {
|
|
60
|
+
return { status: 'complete', category, archived: lastArchived, complete: true };
|
|
61
|
+
}
|
|
62
|
+
if (snap.state === 'incomplete') {
|
|
63
|
+
return { status: 'incomplete', category, archived: lastArchived, complete: false };
|
|
64
|
+
}
|
|
65
|
+
if (snap.state === 'failed') {
|
|
66
|
+
return { status: 'failed', category, archived: lastArchived, complete: false, error: snap.error };
|
|
67
|
+
}
|
|
68
|
+
// Still in-progress — wait before the next poll unless this was the last allowed poll.
|
|
69
|
+
if (poll < maxPolls - 1)
|
|
70
|
+
await sleep(pollIntervalMs);
|
|
50
71
|
}
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
// incomplete result, never a plain success.
|
|
54
|
-
return { archived, hasMore, complete: !hasMore };
|
|
72
|
+
// Guard: the job never reached a terminal state within the poll budget — report incomplete.
|
|
73
|
+
return { status: 'incomplete', category, archived: lastArchived, complete: false };
|
|
55
74
|
},
|
|
56
|
-
onSuccess: () => {
|
|
75
|
+
onSuccess: (result) => {
|
|
76
|
+
// Only a completed drain changed the active set; still invalidate on an incomplete drain since
|
|
77
|
+
// SOME cards were archived. A hard enqueue/poll failure rejects the mutation (onError), so this
|
|
78
|
+
// never runs for `failed`.
|
|
57
79
|
const keysToInvalidate = invalidateKeys ?? defaultInvalidateKeys;
|
|
58
80
|
keysToInvalidate.forEach((key) => {
|
|
59
81
|
queryClient.invalidateQueries({ queryKey: [...key], exact: false });
|
|
60
82
|
});
|
|
83
|
+
void result;
|
|
61
84
|
},
|
|
62
85
|
});
|
|
63
86
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useArchiveAllNotifications.js","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"useArchiveAllNotifications.js","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMpE,MAAM,wBAAwB,GAAG,IAAI,CAAC;AACtC,MAAM,iBAAiB,GAAG,GAAG,CAAC,CAAC,iCAAiC;AAEhE,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,0BAA0B,CAAC,EACzC,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GAAG,wBAAwB,EACzC,QAAQ,GAAG,iBAAiB,EAC5B,cAAc,GACoB;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,qBAAqB,GAAG;QAC5B,CAAC,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;QAC7C,CAAC,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC;QACnD,CAAC,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC;KAC/C,CAAC;IAEF,OAAO,WAAW,CAAC;QACjB,gGAAgG;QAChG,4FAA4F;QAC5F,gGAAgG;QAChG,oEAAoE;QACpE,UAAU,EAAE,KAAK,IAAmC,EAAE;YACpD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YAEtD,4FAA4F;YAC5F,6FAA6F;YAC7F,0FAA0F;YAC1F,IAAI,YAAY,GAAG,CAAC,CAAC;YACrB,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,QAAQ,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;gBAC9C,MAAM,IAAI,GAAG,MAAM,qBAAqB,CAAC,KAAK,CAAC,CAAC;gBAChD,YAAY,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;gBAElC,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;oBAC9B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBAClF,CAAC;gBACD,IAAI,IAAI,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;oBAChC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;gBACrF,CAAC;gBACD,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC5B,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;gBACpG,CAAC;gBAED,uFAAuF;gBACvF,IAAI,IAAI,GAAG,QAAQ,GAAG,CAAC;oBAAE,MAAM,KAAK,CAAC,cAAc,CAAC,CAAC;YACvD,CAAC;YAED,4FAA4F;YAC5F,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QACrF,CAAC;QACD,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE;YACpB,+FAA+F;YAC/F,gGAAgG;YAChG,2BAA2B;YAC3B,MAAM,gBAAgB,GAAG,cAAc,IAAI,qBAAqB,CAAC;YACjE,gBAAgB,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC/B,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACtE,CAAC,CAAC,CAAC;YACH,KAAK,MAAM,CAAC;QACd,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { NotificationHistoryItem, UseNotificationHistoryOptions } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Paginated read of ARCHIVED notification history (the two-tier system's history
|
|
4
|
+
* tier). Personal history lives under a per-user path
|
|
5
|
+
* (`userProfiles/{uid}/notificationHistory`) and shared/admin history under a
|
|
6
|
+
* top-level collection (`adminNotificationHistory`) — both resolved from the
|
|
7
|
+
* category's `historyPath`, so no `where` clause is needed either way. Rows are
|
|
8
|
+
* immutable and ordered newest-first by `archivedAt`.
|
|
9
|
+
*
|
|
10
|
+
* Each history doc is a wrapper (`archivedSnapshot` + archive metadata + a
|
|
11
|
+
* native-TTL `expireAt`); the `select` mapper flattens it into a
|
|
12
|
+
* {@link NotificationHistoryItem} so the read surface renders like the active
|
|
13
|
+
* list. Owner-only (user) / admin-only (admin) reads are enforced by Firestore
|
|
14
|
+
* rules — this hook performs no writes.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useNotificationHistory({ config, userId, category, enabled, pageSize, staleTime, }: UseNotificationHistoryOptions): import("@ttt-productions/query-core/react").UseFirestorePaginatedResult<NotificationHistoryItem>;
|
|
17
|
+
//# sourceMappingURL=useNotificationHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNotificationHistory.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useNotificationHistory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,uBAAuB,EACvB,6BAA6B,EAC9B,MAAM,gBAAgB,CAAC;AAKxB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAc,EACd,QAA4B,EAC5B,SAA8B,GAC/B,EAAE,6BAA6B,oGA4B/B"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useFirestorePaginated } from '@ttt-productions/query-core/react';
|
|
3
|
+
import { orderBy } from 'firebase/firestore';
|
|
4
|
+
const DEFAULT_PAGE_SIZE = 20;
|
|
5
|
+
const DEFAULT_STALE_TIME = 60_000;
|
|
6
|
+
/**
|
|
7
|
+
* Paginated read of ARCHIVED notification history (the two-tier system's history
|
|
8
|
+
* tier). Personal history lives under a per-user path
|
|
9
|
+
* (`userProfiles/{uid}/notificationHistory`) and shared/admin history under a
|
|
10
|
+
* top-level collection (`adminNotificationHistory`) — both resolved from the
|
|
11
|
+
* category's `historyPath`, so no `where` clause is needed either way. Rows are
|
|
12
|
+
* immutable and ordered newest-first by `archivedAt`.
|
|
13
|
+
*
|
|
14
|
+
* Each history doc is a wrapper (`archivedSnapshot` + archive metadata + a
|
|
15
|
+
* native-TTL `expireAt`); the `select` mapper flattens it into a
|
|
16
|
+
* {@link NotificationHistoryItem} so the read surface renders like the active
|
|
17
|
+
* list. Owner-only (user) / admin-only (admin) reads are enforced by Firestore
|
|
18
|
+
* rules — this hook performs no writes.
|
|
19
|
+
*/
|
|
20
|
+
export function useNotificationHistory({ config, userId, category, enabled = true, pageSize = DEFAULT_PAGE_SIZE, staleTime = DEFAULT_STALE_TIME, }) {
|
|
21
|
+
const categoryConfig = config.categories[category];
|
|
22
|
+
if (!categoryConfig) {
|
|
23
|
+
throw new Error(`[notification-core] Unknown category: ${category}`);
|
|
24
|
+
}
|
|
25
|
+
const collectionPath = categoryConfig.historyPath(userId);
|
|
26
|
+
const constraints = [orderBy('archivedAt', 'desc')];
|
|
27
|
+
return useFirestorePaginated({
|
|
28
|
+
collectionPath,
|
|
29
|
+
queryKey: ['notifications', 'history', category, userId, { pageSize }],
|
|
30
|
+
constraints,
|
|
31
|
+
pageSize,
|
|
32
|
+
enabled: enabled && !!userId,
|
|
33
|
+
staleTime,
|
|
34
|
+
select: (data) => {
|
|
35
|
+
const snapshot = (data.archivedSnapshot ?? {});
|
|
36
|
+
return {
|
|
37
|
+
...snapshot,
|
|
38
|
+
// The archive occurrence id is the stable history-doc key; expose
|
|
39
|
+
// archivedAt for ordering/display.
|
|
40
|
+
archiveOccurrenceId: data.id,
|
|
41
|
+
archivedAt: data.archivedAt ?? snapshot.updatedAt ?? 0,
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=useNotificationHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNotificationHistory.js","sourceRoot":"","sources":["../../../src/react/hooks/useNotificationHistory.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAwB,MAAM,oBAAoB,CAAC;AAOnE,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,GAAG,IAAI,EACd,QAAQ,GAAG,iBAAiB,EAC5B,SAAS,GAAG,kBAAkB,GACA;IAC9B,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,cAAc,GAAG,cAAc,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAE1D,MAAM,WAAW,GAAsB,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAEvE,OAAO,qBAAqB,CAA0B;QACpD,cAAc;QACd,QAAQ,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC;QACtE,WAAW;QACX,QAAQ;QACR,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC,MAAM;QAC5B,SAAS;QACT,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACf,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAoB,CAAC;YAClE,OAAO;gBACL,GAAG,QAAQ;gBACX,kEAAkE;gBAClE,mCAAmC;gBACnC,mBAAmB,EAAE,IAAI,CAAC,EAAE;gBAC5B,UAAU,EAAG,IAAI,CAAC,UAAiC,IAAI,QAAQ,CAAC,SAAS,IAAI,CAAC;aAC/E,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { useActiveNotifications, useUnreadCount, useArchiveNotification, useArchiveAllNotifications, } from './hooks/index.js';
|
|
2
|
-
export { NotificationList, NotificationEmptyState, NotificationUnreadBadge, } from './components/index.js';
|
|
1
|
+
export { useActiveNotifications, useNotificationHistory, useUnreadCount, useArchiveNotification, useArchiveAllNotifications, } from './hooks/index.js';
|
|
2
|
+
export { NotificationList, NotificationHistoryList, NotificationEmptyState, NotificationUnreadBadge, } from './components/index.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,cAAc,EACd,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC"}
|
package/dist/react/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
// Hooks
|
|
3
|
-
export { useActiveNotifications, useUnreadCount, useArchiveNotification, useArchiveAllNotifications, } from './hooks/index.js';
|
|
3
|
+
export { useActiveNotifications, useNotificationHistory, useUnreadCount, useArchiveNotification, useArchiveAllNotifications, } from './hooks/index.js';
|
|
4
4
|
// Components
|
|
5
|
-
export { NotificationList, NotificationEmptyState, NotificationUnreadBadge, } from './components/index.js';
|
|
5
|
+
export { NotificationList, NotificationHistoryList, NotificationEmptyState, NotificationUnreadBadge, } from './components/index.js';
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,QAAQ;AACR,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAE1B,aAAa;AACb,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,QAAQ;AACR,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,cAAc,EACd,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAE1B,aAAa;AACb,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -147,6 +147,28 @@ export interface UseActiveNotificationsOptions {
|
|
|
147
147
|
pageSize?: number;
|
|
148
148
|
refetchInterval?: number;
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* A flattened archived-history item for the read surface. The history doc is a
|
|
152
|
+
* wrapper (`archivedSnapshot` + archive metadata + TTL); this shape lifts the
|
|
153
|
+
* snapshot's display fields to the top level so the history list renders exactly
|
|
154
|
+
* like the active list, plus `archivedAt` for ordering/display and
|
|
155
|
+
* `archiveOccurrenceId` as the stable React key.
|
|
156
|
+
*/
|
|
157
|
+
export interface NotificationHistoryItem extends NotificationDoc {
|
|
158
|
+
/** The history doc id (stable key — the `archiveOccurrenceId`). */
|
|
159
|
+
archiveOccurrenceId: string;
|
|
160
|
+
/** Epoch ms the notification was archived (history docs order by this). */
|
|
161
|
+
archivedAt: number;
|
|
162
|
+
}
|
|
163
|
+
export interface UseNotificationHistoryOptions {
|
|
164
|
+
config: NotificationSystemConfig;
|
|
165
|
+
userId: string;
|
|
166
|
+
category: string;
|
|
167
|
+
enabled?: boolean;
|
|
168
|
+
pageSize?: number;
|
|
169
|
+
/** Read-freshness stale time in ms (archived rows are immutable; default 60s). */
|
|
170
|
+
staleTime?: number;
|
|
171
|
+
}
|
|
150
172
|
export interface UseUnreadCountOptions {
|
|
151
173
|
config: NotificationSystemConfig;
|
|
152
174
|
userId: string;
|
|
@@ -168,42 +190,79 @@ export interface UseArchiveNotificationOptions {
|
|
|
168
190
|
invalidateKeys?: readonly unknown[][];
|
|
169
191
|
}
|
|
170
192
|
/**
|
|
171
|
-
*
|
|
172
|
-
* cap and the caller's active set was NOT fully drained — `useArchiveAllNotifications` loops the
|
|
173
|
-
* adapter until `hasMore` is false so "Clear All" actually clears all (I3).
|
|
193
|
+
* Terminal + transient states of a server-owned archive-all job, as surfaced to the UI.
|
|
174
194
|
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
195
|
+
* - `idle` — nothing enqueued yet (initial / reset state).
|
|
196
|
+
* - `enqueuing` — the enqueue adapter is in flight (job not yet acknowledged).
|
|
197
|
+
* - `in-progress` — the job is enqueued/running; the worker is still draining the category.
|
|
198
|
+
* - `complete` — TERMINAL: the worker fully drained the category's active set.
|
|
199
|
+
* - `incomplete` — TERMINAL: the job stopped without draining everything (e.g. hit its own
|
|
200
|
+
* bound / a non-advanceable card). The tray keeps a "some remain — try again"
|
|
201
|
+
* affordance, mirroring the old loop's incomplete result.
|
|
202
|
+
* - `failed` — TERMINAL: the enqueue call threw, or the job dead-lettered / reported failure.
|
|
178
203
|
*/
|
|
179
|
-
export
|
|
180
|
-
|
|
181
|
-
|
|
204
|
+
export type ArchiveAllJobStatus = 'idle' | 'enqueuing' | 'in-progress' | 'complete' | 'incomplete' | 'failed';
|
|
205
|
+
/**
|
|
206
|
+
* Result of the INJECTED enqueue adapter — triggers exactly one server-owned archive-all job for
|
|
207
|
+
* the given category and returns immediately with the job's id (idempotent per user+category+request
|
|
208
|
+
* on the app side). The app wires this to its `httpsCallable(functions, 'enqueueArchiveAll')`
|
|
209
|
+
* (or equivalent); the generic package never names the callable.
|
|
210
|
+
*/
|
|
211
|
+
export interface EnqueueArchiveAllResult {
|
|
212
|
+
/** Server job id the poller then polls via the status adapter. */
|
|
213
|
+
jobId: string;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Snapshot of a server-owned archive-all job, returned by the INJECTED status-query adapter.
|
|
217
|
+
* The poller maps `state` → {@link ArchiveAllJobStatus} and stops polling on any terminal state.
|
|
218
|
+
* `category` echoes the tab/category the job was enqueued for so the UI can assert per-tab scoping.
|
|
219
|
+
*/
|
|
220
|
+
export interface ArchiveAllJobSnapshot {
|
|
221
|
+
/** Job lifecycle state as owned by the server worker. */
|
|
222
|
+
state: 'in-progress' | 'complete' | 'incomplete' | 'failed';
|
|
223
|
+
/** The notification category/tab this job is scoped to (must match the enqueue category). */
|
|
224
|
+
category: string;
|
|
225
|
+
/** Cards archived so far (monotonic); optional progress for the UI. */
|
|
226
|
+
archived?: number;
|
|
227
|
+
/** Human-readable failure reason when `state === 'failed'` (optional). */
|
|
228
|
+
error?: string;
|
|
182
229
|
}
|
|
183
230
|
/**
|
|
184
|
-
* Aggregate result
|
|
185
|
-
* load-bearing completion contract
|
|
186
|
-
*
|
|
187
|
-
* guard tripped (a pass archived nothing yet still reported `hasMore`, e.g. a generation-less head
|
|
188
|
-
* card that can't advance) or the per-mutation pass bound was hit with `hasMore` still `true`.
|
|
189
|
-
* Callers MUST gate post-clear side effects (closing the tray, `onClearAll`) on `complete`, not on
|
|
190
|
-
* mere resolution — the mutation resolves on an incomplete drain rather than throwing.
|
|
231
|
+
* Aggregate result the poller resolves with once the job reaches a terminal state.
|
|
232
|
+
* `complete` is the load-bearing completion contract (true ONLY when the whole category was
|
|
233
|
+
* drained), preserved from the old loop so callers gate side effects the same way.
|
|
191
234
|
*/
|
|
192
|
-
export interface
|
|
235
|
+
export interface ArchiveAllPollResult {
|
|
236
|
+
status: Extract<ArchiveAllJobStatus, 'complete' | 'incomplete' | 'failed'>;
|
|
237
|
+
category: string;
|
|
193
238
|
archived: number;
|
|
194
|
-
hasMore: boolean;
|
|
195
239
|
complete: boolean;
|
|
240
|
+
error?: string;
|
|
196
241
|
}
|
|
197
242
|
export interface UseArchiveAllNotificationsOptions {
|
|
198
243
|
userId: string;
|
|
199
244
|
category: string;
|
|
200
245
|
/**
|
|
201
|
-
* App-supplied adapter that
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
246
|
+
* App-supplied adapter that ENQUEUES one server-owned archive-all job scoped to `category` and
|
|
247
|
+
* returns its `jobId`. The `category` is passed so the app callable can carry the tab/source into
|
|
248
|
+
* the job (per-tab scoping is REQUIRED — the worker archives only that category's active cards).
|
|
249
|
+
* Typically `(category) => enqueueArchiveAll({ category })` over an `httpsCallable`.
|
|
250
|
+
*/
|
|
251
|
+
enqueueArchiveAllFn: (category: string) => Promise<EnqueueArchiveAllResult>;
|
|
252
|
+
/**
|
|
253
|
+
* App-supplied adapter that returns the current {@link ArchiveAllJobSnapshot} for a job id — the
|
|
254
|
+
* hook polls it until the job reaches a terminal state. Typically
|
|
255
|
+
* `(jobId) => getArchiveAllStatus({ jobId })` over an `httpsCallable`, or a Firestore read of the
|
|
256
|
+
* job doc. No client Firestore writes.
|
|
257
|
+
*/
|
|
258
|
+
getArchiveAllStatusFn: (jobId: string) => Promise<ArchiveAllJobSnapshot>;
|
|
259
|
+
/** Poll interval in ms while the job is in-progress (default 1500). */
|
|
260
|
+
pollIntervalMs?: number;
|
|
261
|
+
/**
|
|
262
|
+
* Max number of status polls before the poller gives up and resolves `incomplete` (guards a job
|
|
263
|
+
* that never reaches a terminal state — default 120, i.e. ~3 min at the default interval).
|
|
205
264
|
*/
|
|
206
|
-
|
|
265
|
+
maxPolls?: number;
|
|
207
266
|
invalidateKeys?: readonly unknown[][];
|
|
208
267
|
}
|
|
209
268
|
export interface NotificationListProps {
|
|
@@ -217,15 +276,35 @@ export interface NotificationListProps {
|
|
|
217
276
|
*/
|
|
218
277
|
archiveFn: (notificationId: string) => Promise<unknown>;
|
|
219
278
|
/**
|
|
220
|
-
* Adapter that
|
|
221
|
-
* `
|
|
222
|
-
*
|
|
279
|
+
* Adapter that ENQUEUES one server-owned archive-all job scoped to `category` and returns its
|
|
280
|
+
* `jobId`. Passed straight through to `useArchiveAllNotifications`; the app wires it to its
|
|
281
|
+
* enqueue callable. Per-tab scoping: the category flows through to the job.
|
|
282
|
+
*/
|
|
283
|
+
enqueueArchiveAllFn: (category: string) => Promise<EnqueueArchiveAllResult>;
|
|
284
|
+
/**
|
|
285
|
+
* Adapter that returns the current status snapshot for an archive-all `jobId`. Passed straight
|
|
286
|
+
* through to `useArchiveAllNotifications`, which polls it until the job is terminal; the app wires
|
|
287
|
+
* it to its status callable / job-doc read.
|
|
223
288
|
*/
|
|
224
|
-
|
|
289
|
+
getArchiveAllStatusFn: (jobId: string) => Promise<ArchiveAllJobSnapshot>;
|
|
225
290
|
onClearAll?: () => void;
|
|
226
291
|
refetchInterval?: number;
|
|
227
292
|
emptyText?: string;
|
|
228
293
|
}
|
|
294
|
+
export interface NotificationHistoryListProps {
|
|
295
|
+
config: NotificationSystemConfig;
|
|
296
|
+
userId: string;
|
|
297
|
+
category: string;
|
|
298
|
+
/**
|
|
299
|
+
* Optional click handler for an archived row (e.g. navigate to `targetPath`).
|
|
300
|
+
* Archived rows are read-only — there is no re-archive; the row does not mutate
|
|
301
|
+
* state on click. Omit to render non-interactive rows.
|
|
302
|
+
*/
|
|
303
|
+
onNotificationClick?: (notification: NotificationHistoryItem) => void;
|
|
304
|
+
pageSize?: number;
|
|
305
|
+
staleTime?: number;
|
|
306
|
+
emptyText?: string;
|
|
307
|
+
}
|
|
229
308
|
export interface NotificationEmptyStateProps {
|
|
230
309
|
text?: string;
|
|
231
310
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttt-productions/notification-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Shared notification system for TTT Productions apps — active/history two-tier architecture with dedup, batch processing, and themed UI components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|