@quanticjs/notification-ui 8.0.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.
@@ -0,0 +1,1054 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { Socket } from 'socket.io-client';
4
+ import * as _tanstack_react_query from '@tanstack/react-query';
5
+ import * as _quanticjs_react_core from '@quanticjs/react-core';
6
+
7
+ type RealtimeStatus = 'connected' | 'reconnecting' | 'disconnected' | 'disabled';
8
+ interface RealtimeContextValue {
9
+ socket: Socket | null;
10
+ status: RealtimeStatus;
11
+ }
12
+ interface NotificationRealtimeProviderProps {
13
+ /** Socket.IO server base URL — defaults to current origin (BFF proxy). */
14
+ serverUrl?: string;
15
+ /** Disable WebSocket (falls back to polling). Default: false. */
16
+ disabled?: boolean;
17
+ /**
18
+ * Scope realtime invalidation to a producing app (SPEC-application-scoping).
19
+ * When set, `notification:new` events for other apps are ignored; events for
20
+ * this app or system-wide (`appId: null`) still refresh the feed/badge. Omit
21
+ * for a portal that reacts to every app's events.
22
+ */
23
+ appId?: string;
24
+ children: ReactNode;
25
+ className?: string;
26
+ }
27
+ /**
28
+ * Mounts a single shared Socket.IO connection to the engine's `/realtime`
29
+ * namespace using only the BFF httpOnly session cookie (`withCredentials`).
30
+ * On `notification:new` / `unread-count:changed` it invalidates the relevant
31
+ * TanStack Query keys (leading-edge debounced over a 200 ms window) so existing
32
+ * fetch logic is reused rather than patching caches. Exposes connection status
33
+ * via context so hooks can switch to REST polling when the socket is down.
34
+ */
35
+ declare function NotificationRealtimeProvider({ serverUrl, disabled, appId, children, }: NotificationRealtimeProviderProps): react_jsx_runtime.JSX.Element;
36
+ declare function useRealtimeContext(): RealtimeContextValue;
37
+
38
+ /**
39
+ * Resolved notification config shared with every bell / inbox / hook below the
40
+ * provider. A consumer app sets these once; components and hooks read them from
41
+ * context, so the bell dropped into `AppShell`'s `TopBar.actions` scopes to the
42
+ * registered app without prop-drilling `appId` everywhere.
43
+ */
44
+ interface NotificationConfig {
45
+ /**
46
+ * The registered application slug this app's notifications are scoped to
47
+ * (must match a row in the engine's application registry). Flows to `?appId=`
48
+ * on list / unread-count / read-all and filters realtime events. Omit on a
49
+ * shell / portal to get the unified cross-app inbox.
50
+ */
51
+ appId?: string;
52
+ /** API path prefix the engine's notification endpoints are mounted on. Default `/notifications`. */
53
+ basePath: string;
54
+ /** Unread-count / feed poll interval in ms when the socket is down. Default 60_000. */
55
+ pollIntervalMs: number;
56
+ }
57
+ /**
58
+ * Reads the ambient notification config. Returns framework defaults when no
59
+ * `NotificationProvider` is mounted, so components still work with explicit
60
+ * props in isolation (and in tests).
61
+ */
62
+ declare function useNotificationConfig(): NotificationConfig;
63
+ interface NotificationProviderProps extends Pick<NotificationRealtimeProviderProps, 'serverUrl' | 'disabled'> {
64
+ /**
65
+ * The consumer app's registered slug — the one thing an app must declare to
66
+ * scope its bell. Omit on a shell / portal for the unified inbox.
67
+ */
68
+ appId?: string;
69
+ /** Endpoint path prefix (through the host BFF). Default `/notifications`. */
70
+ basePath?: string;
71
+ /** Poll interval (ms) used while the realtime socket is unavailable. Default 60_000. */
72
+ pollIntervalMs?: number;
73
+ children: ReactNode;
74
+ }
75
+ /**
76
+ * Single registration point for notifications. Wrap the app (above `AppShell`)
77
+ * once:
78
+ *
79
+ * ```tsx
80
+ * <NotificationProvider appId="delivery-hub">
81
+ * <AppShell topBar={{ actions: <NotificationBell /> }}>…</AppShell>
82
+ * </NotificationProvider>
83
+ * ```
84
+ *
85
+ * It opens the shared realtime socket (app-filtered) and publishes `appId` /
86
+ * `basePath` / `pollIntervalMs` to every notification component and hook below.
87
+ */
88
+ declare function NotificationProvider({ appId, basePath, pollIntervalMs, serverUrl, disabled, children, }: NotificationProviderProps): react_jsx_runtime.JSX.Element;
89
+
90
+ type NotificationChannel = 'inapp' | 'email';
91
+ type DigestPeriod = 'none' | 'hourly' | 'daily';
92
+ interface NotificationPreferenceDto {
93
+ channel: NotificationChannel;
94
+ type: string;
95
+ enabled: boolean;
96
+ digest: DigestPeriod;
97
+ }
98
+ interface NotificationPreferencesProps {
99
+ /** API path prefix the engine's preference endpoints are mounted on (through the host app's BFF). */
100
+ basePath?: string;
101
+ /** Optional friendly labels per type key; unknown keys fall back to a derived label. */
102
+ typeLabels?: Record<string, string>;
103
+ className?: string;
104
+ }
105
+ /**
106
+ * Type × channel preference matrix with per-type email digest selection.
107
+ * Embeddable in any app fronting the QuanticJS notification engine — the
108
+ * host wraps it in its own page chrome and providers (QuanticProvider,
109
+ * QuanticQueryProvider, ToastProvider).
110
+ */
111
+ declare function NotificationPreferences({ basePath, typeLabels, className, }: NotificationPreferencesProps): react_jsx_runtime.JSX.Element;
112
+
113
+ interface UseUnreadCountOptions {
114
+ /** API path prefix the engine's notification endpoints are mounted on. */
115
+ basePath?: string;
116
+ /** Polling interval in ms when the socket is unavailable. Default: 60_000. */
117
+ pollIntervalMs?: number;
118
+ /** Scope the count to a producing app (its rows + system-wide). Omit for all. */
119
+ appId?: string;
120
+ }
121
+ /**
122
+ * Reads the unread badge count. When the realtime socket is connected, the
123
+ * count is kept fresh by socket-driven cache invalidation and polling is
124
+ * disabled; when the socket is down it transparently falls back to REST polling
125
+ * at `pollIntervalMs`. Any option omitted falls back to the ambient
126
+ * `NotificationProvider` config (where the consumer registered its `appId`).
127
+ */
128
+ declare function useUnreadCount(options?: UseUnreadCountOptions): _tanstack_react_query.UseQueryResult<{
129
+ count: number;
130
+ }, _quanticjs_react_core.ApiError>;
131
+
132
+ interface NotificationFeedItem {
133
+ id: string;
134
+ userId: string;
135
+ type: string;
136
+ title: string;
137
+ body: string;
138
+ metadata: Record<string, unknown> | null;
139
+ isRead: boolean;
140
+ createdAt: string;
141
+ }
142
+ interface PaginatedFeed {
143
+ items: NotificationFeedItem[];
144
+ total: number;
145
+ page: number;
146
+ limit: number;
147
+ totalPages: number;
148
+ }
149
+ interface UseNotificationFeedOptions {
150
+ basePath?: string;
151
+ /** Polling interval in ms when the socket is unavailable. Default: 60_000. */
152
+ pollIntervalMs?: number;
153
+ limit?: number;
154
+ /**
155
+ * Scope the feed to a producing application (SPEC-application-scoping). When
156
+ * set, every request carries `?appId=` so the bell shows only that app's rows
157
+ * plus system-wide notifications. Omit for the unified portal view.
158
+ */
159
+ appId?: string;
160
+ }
161
+ /**
162
+ * Fetches the notification feed (list) and exposes mark-read / mark-all-read
163
+ * mutations. Falls back to REST polling when the socket is down. On socket
164
+ * reconnect it emits `backfill:request` with the newest known timestamp so any
165
+ * notifications created during the disconnect gap are pulled in.
166
+ */
167
+ declare function useNotificationFeed(options?: UseNotificationFeedOptions): {
168
+ markRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, string, unknown>;
169
+ markAllRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, void, unknown>;
170
+ data: PaginatedFeed;
171
+ error: _quanticjs_react_core.ApiError;
172
+ isError: true;
173
+ isPending: false;
174
+ isLoading: false;
175
+ isLoadingError: false;
176
+ isRefetchError: true;
177
+ isSuccess: false;
178
+ isPlaceholderData: false;
179
+ status: "error";
180
+ dataUpdatedAt: number;
181
+ errorUpdatedAt: number;
182
+ failureCount: number;
183
+ failureReason: _quanticjs_react_core.ApiError | null;
184
+ errorUpdateCount: number;
185
+ isFetched: boolean;
186
+ isFetchedAfterMount: boolean;
187
+ isFetching: boolean;
188
+ isInitialLoading: boolean;
189
+ isPaused: boolean;
190
+ isRefetching: boolean;
191
+ isStale: boolean;
192
+ isEnabled: boolean;
193
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<PaginatedFeed, _quanticjs_react_core.ApiError>>;
194
+ fetchStatus: _tanstack_react_query.FetchStatus;
195
+ promise: Promise<PaginatedFeed>;
196
+ } | {
197
+ markRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, string, unknown>;
198
+ markAllRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, void, unknown>;
199
+ data: PaginatedFeed;
200
+ error: null;
201
+ isError: false;
202
+ isPending: false;
203
+ isLoading: false;
204
+ isLoadingError: false;
205
+ isRefetchError: false;
206
+ isSuccess: true;
207
+ isPlaceholderData: false;
208
+ status: "success";
209
+ dataUpdatedAt: number;
210
+ errorUpdatedAt: number;
211
+ failureCount: number;
212
+ failureReason: _quanticjs_react_core.ApiError | null;
213
+ errorUpdateCount: number;
214
+ isFetched: boolean;
215
+ isFetchedAfterMount: boolean;
216
+ isFetching: boolean;
217
+ isInitialLoading: boolean;
218
+ isPaused: boolean;
219
+ isRefetching: boolean;
220
+ isStale: boolean;
221
+ isEnabled: boolean;
222
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<PaginatedFeed, _quanticjs_react_core.ApiError>>;
223
+ fetchStatus: _tanstack_react_query.FetchStatus;
224
+ promise: Promise<PaginatedFeed>;
225
+ } | {
226
+ markRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, string, unknown>;
227
+ markAllRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, void, unknown>;
228
+ data: undefined;
229
+ error: _quanticjs_react_core.ApiError;
230
+ isError: true;
231
+ isPending: false;
232
+ isLoading: false;
233
+ isLoadingError: true;
234
+ isRefetchError: false;
235
+ isSuccess: false;
236
+ isPlaceholderData: false;
237
+ status: "error";
238
+ dataUpdatedAt: number;
239
+ errorUpdatedAt: number;
240
+ failureCount: number;
241
+ failureReason: _quanticjs_react_core.ApiError | null;
242
+ errorUpdateCount: number;
243
+ isFetched: boolean;
244
+ isFetchedAfterMount: boolean;
245
+ isFetching: boolean;
246
+ isInitialLoading: boolean;
247
+ isPaused: boolean;
248
+ isRefetching: boolean;
249
+ isStale: boolean;
250
+ isEnabled: boolean;
251
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<PaginatedFeed, _quanticjs_react_core.ApiError>>;
252
+ fetchStatus: _tanstack_react_query.FetchStatus;
253
+ promise: Promise<PaginatedFeed>;
254
+ } | {
255
+ markRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, string, unknown>;
256
+ markAllRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, void, unknown>;
257
+ data: undefined;
258
+ error: null;
259
+ isError: false;
260
+ isPending: true;
261
+ isLoading: true;
262
+ isLoadingError: false;
263
+ isRefetchError: false;
264
+ isSuccess: false;
265
+ isPlaceholderData: false;
266
+ status: "pending";
267
+ dataUpdatedAt: number;
268
+ errorUpdatedAt: number;
269
+ failureCount: number;
270
+ failureReason: _quanticjs_react_core.ApiError | null;
271
+ errorUpdateCount: number;
272
+ isFetched: boolean;
273
+ isFetchedAfterMount: boolean;
274
+ isFetching: boolean;
275
+ isInitialLoading: boolean;
276
+ isPaused: boolean;
277
+ isRefetching: boolean;
278
+ isStale: boolean;
279
+ isEnabled: boolean;
280
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<PaginatedFeed, _quanticjs_react_core.ApiError>>;
281
+ fetchStatus: _tanstack_react_query.FetchStatus;
282
+ promise: Promise<PaginatedFeed>;
283
+ } | {
284
+ markRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, string, unknown>;
285
+ markAllRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, void, unknown>;
286
+ data: undefined;
287
+ error: null;
288
+ isError: false;
289
+ isPending: true;
290
+ isLoadingError: false;
291
+ isRefetchError: false;
292
+ isSuccess: false;
293
+ isPlaceholderData: false;
294
+ status: "pending";
295
+ dataUpdatedAt: number;
296
+ errorUpdatedAt: number;
297
+ failureCount: number;
298
+ failureReason: _quanticjs_react_core.ApiError | null;
299
+ errorUpdateCount: number;
300
+ isFetched: boolean;
301
+ isFetchedAfterMount: boolean;
302
+ isFetching: boolean;
303
+ isLoading: boolean;
304
+ isInitialLoading: boolean;
305
+ isPaused: boolean;
306
+ isRefetching: boolean;
307
+ isStale: boolean;
308
+ isEnabled: boolean;
309
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<PaginatedFeed, _quanticjs_react_core.ApiError>>;
310
+ fetchStatus: _tanstack_react_query.FetchStatus;
311
+ promise: Promise<PaginatedFeed>;
312
+ } | {
313
+ markRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, string, unknown>;
314
+ markAllRead: _tanstack_react_query.UseMutationResult<void, _quanticjs_react_core.ApiError, void, unknown>;
315
+ data: PaginatedFeed;
316
+ isError: false;
317
+ error: null;
318
+ isPending: false;
319
+ isLoading: false;
320
+ isLoadingError: false;
321
+ isRefetchError: false;
322
+ isSuccess: true;
323
+ isPlaceholderData: true;
324
+ status: "success";
325
+ dataUpdatedAt: number;
326
+ errorUpdatedAt: number;
327
+ failureCount: number;
328
+ failureReason: _quanticjs_react_core.ApiError | null;
329
+ errorUpdateCount: number;
330
+ isFetched: boolean;
331
+ isFetchedAfterMount: boolean;
332
+ isFetching: boolean;
333
+ isInitialLoading: boolean;
334
+ isPaused: boolean;
335
+ isRefetching: boolean;
336
+ isStale: boolean;
337
+ isEnabled: boolean;
338
+ refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<PaginatedFeed, _quanticjs_react_core.ApiError>>;
339
+ fetchStatus: _tanstack_react_query.FetchStatus;
340
+ promise: Promise<PaginatedFeed>;
341
+ };
342
+
343
+ interface NotificationBellProps {
344
+ basePath?: string;
345
+ pollIntervalMs?: number;
346
+ /** Scope the unread badge to a producing app (its rows + system-wide). */
347
+ appId?: string;
348
+ /** Invoked when the bell is activated (e.g. to open the inbox panel). */
349
+ onClick?: () => void;
350
+ className?: string;
351
+ }
352
+ /**
353
+ * Accessible notification bell with an unread badge. The badge is hidden at
354
+ * zero; the wrapper exposes a live `role="status"` with an `aria-label`
355
+ * describing the count so assistive tech announces changes.
356
+ */
357
+ declare function NotificationBell({ basePath, pollIntervalMs, appId, onClick, className, }: NotificationBellProps): react_jsx_runtime.JSX.Element;
358
+
359
+ interface NotificationInboxProps {
360
+ basePath?: string;
361
+ pollIntervalMs?: number;
362
+ /** Scope the inbox to a producing app (its rows + system-wide). Omit for all. */
363
+ appId?: string;
364
+ className?: string;
365
+ }
366
+ /**
367
+ * Notification inbox panel: renders the feed with loading / error / empty
368
+ * states, marks individual items read on click, and offers a "Mark all read"
369
+ * action. All reads invalidate `['notifications']` and
370
+ * `['notifications','unread-count']` so the bell badge converges.
371
+ */
372
+ declare function NotificationInbox({ basePath, pollIntervalMs, appId, className, }: NotificationInboxProps): react_jsx_runtime.JSX.Element;
373
+
374
+ interface DeliveryAnalyticsPageProps {
375
+ basePath?: string;
376
+ organizationId?: string;
377
+ className?: string;
378
+ }
379
+ /**
380
+ * Admin delivery-analytics dashboard: channel/date-range filter, funnel stat
381
+ * cards, per-day trend chart, and a per-type table. Implements the standard
382
+ * loading / error / empty data-list states.
383
+ */
384
+ declare function DeliveryAnalyticsPage({ basePath, organizationId, className, }: DeliveryAnalyticsPageProps): react_jsx_runtime.JSX.Element;
385
+
386
+ interface DailyDeliveryStats {
387
+ day: string;
388
+ sends: number;
389
+ delivered: number;
390
+ opened: number;
391
+ clicked: number;
392
+ bounced: number;
393
+ failed: number;
394
+ deliveryRate: number;
395
+ openRate: number;
396
+ clickRate: number;
397
+ bounceRate: number;
398
+ }
399
+ interface DeliveryAnalyticsFilters {
400
+ from: string;
401
+ to: string;
402
+ channel?: string;
403
+ type?: string;
404
+ organizationId?: string;
405
+ }
406
+ interface UseDeliveryAnalyticsOptions extends DeliveryAnalyticsFilters {
407
+ basePath?: string;
408
+ }
409
+ /** Per-day delivery summary stats for the selected filters. */
410
+ declare function useDeliveryAnalytics({ basePath, ...filters }: UseDeliveryAnalyticsOptions): _tanstack_react_query.UseQueryResult<DailyDeliveryStats[], _quanticjs_react_core.ApiError>;
411
+
412
+ interface DeliveryFunnel {
413
+ sends: number;
414
+ delivered: number;
415
+ opened: number;
416
+ clicked: number;
417
+ bounced: number;
418
+ failed: number;
419
+ openRate: number;
420
+ clickRate: number;
421
+ bounceRate: number;
422
+ deliveryRate: number;
423
+ }
424
+ interface UseFunnelStatsOptions extends DeliveryAnalyticsFilters {
425
+ basePath?: string;
426
+ }
427
+ /** Single aggregated funnel over the selected date range. */
428
+ declare function useFunnelStats({ basePath, ...filters }: UseFunnelStatsOptions): _tanstack_react_query.UseQueryResult<DeliveryFunnel, _quanticjs_react_core.ApiError>;
429
+
430
+ interface FunnelStatsProps {
431
+ funnel: DeliveryFunnel;
432
+ className?: string;
433
+ }
434
+ /** Funnel stat cards: sends → delivered → opened → clicked, plus key rates. */
435
+ declare function FunnelStats({ funnel, className }: FunnelStatsProps): react_jsx_runtime.JSX.Element;
436
+
437
+ interface TrendChartProps {
438
+ data: DailyDeliveryStats[];
439
+ className?: string;
440
+ }
441
+ /**
442
+ * Per-day delivery trend line chart (sends / delivered / opened / clicked).
443
+ * Route-split-friendly — recharts is only loaded with the analytics page.
444
+ */
445
+ declare function TrendChart({ data, className }: TrendChartProps): react_jsx_runtime.JSX.Element;
446
+
447
+ interface DeliveryTypeBreakdown {
448
+ type: string;
449
+ sends: number;
450
+ delivered: number;
451
+ opened: number;
452
+ clicked: number;
453
+ bounced: number;
454
+ failed: number;
455
+ openRate: number;
456
+ clickRate: number;
457
+ }
458
+ interface UseDeliveryTypesOptions extends Pick<DeliveryAnalyticsFilters, 'from' | 'to' | 'organizationId'> {
459
+ basePath?: string;
460
+ }
461
+ /** Per-type breakdown sorted by send volume descending. */
462
+ declare function useDeliveryTypes({ basePath, ...filters }: UseDeliveryTypesOptions): _tanstack_react_query.UseQueryResult<DeliveryTypeBreakdown[], _quanticjs_react_core.ApiError>;
463
+
464
+ interface TypeTableProps {
465
+ rows: DeliveryTypeBreakdown[];
466
+ className?: string;
467
+ }
468
+ /** Per-notification-type delivery breakdown, sorted by send volume. */
469
+ declare function TypeTable({ rows, className }: TypeTableProps): react_jsx_runtime.JSX.Element;
470
+
471
+ type TemplateStatus = 'draft' | 'published' | 'archived' | string;
472
+ /**
473
+ * Small status pill shared across the template admin components. Falls back to
474
+ * a neutral style for unknown status values. Semantic tokens only — no hex.
475
+ */
476
+ declare function TemplateStatusBadge({ status, className, }: {
477
+ status: TemplateStatus;
478
+ className?: string;
479
+ }): react_jsx_runtime.JSX.Element;
480
+
481
+ interface TemplateListItem {
482
+ templateId: string;
483
+ locales: string[];
484
+ latestStatus: TemplateStatus;
485
+ versionCount: number;
486
+ }
487
+ interface TemplateListProps {
488
+ /** API path the template admin endpoints are mounted on (through the BFF). */
489
+ basePath?: string;
490
+ className?: string;
491
+ }
492
+ /**
493
+ * Admin data-list of notification templates. Renders the template id, the
494
+ * latest version status, available locales, and version count with full
495
+ * loading / error / empty / happy coverage.
496
+ */
497
+ declare function TemplateList({ basePath, className }: TemplateListProps): react_jsx_runtime.JSX.Element;
498
+
499
+ interface TemplateEditorFields {
500
+ subject: string;
501
+ heading: string;
502
+ body: string;
503
+ cta: string;
504
+ html: string;
505
+ }
506
+ interface TemplateVersionResponse {
507
+ id: string;
508
+ versionNumber: number;
509
+ status: TemplateStatus;
510
+ }
511
+ interface TemplateEditorProps {
512
+ templateId: string;
513
+ /** Existing version id to publish; falls back to the id returned by the draft save. */
514
+ versionId?: string;
515
+ initialFields?: Partial<TemplateEditorFields>;
516
+ initialStatus?: TemplateStatus;
517
+ basePath?: string;
518
+ className?: string;
519
+ }
520
+ /**
521
+ * Template draft editor. Validates Handlebars brace balance client-side before
522
+ * submitting; saves a draft via PUT and offers a publish action. Surfaces
523
+ * field-level errors and ApiError-aware toasts.
524
+ */
525
+ declare function TemplateEditor({ templateId, versionId, initialFields, initialStatus, basePath, className, }: TemplateEditorProps): react_jsx_runtime.JSX.Element;
526
+
527
+ interface PreviewResult {
528
+ subject: string;
529
+ html: string;
530
+ text: string;
531
+ }
532
+ interface TemplatePreviewPaneProps {
533
+ templateId: string;
534
+ versionId: string;
535
+ /** Sample variables passed to the render. */
536
+ vars?: Record<string, unknown>;
537
+ basePath?: string;
538
+ className?: string;
539
+ }
540
+ /**
541
+ * Renders a server-side preview of a template version. POSTs the version id and
542
+ * sample vars, then displays the rendered subject, sandboxed HTML, and plaintext.
543
+ */
544
+ declare function TemplatePreviewPane({ templateId, versionId, vars, basePath, className, }: TemplatePreviewPaneProps): react_jsx_runtime.JSX.Element;
545
+
546
+ interface TemplateVersion {
547
+ id: string;
548
+ versionNumber: number;
549
+ status: TemplateStatus;
550
+ createdBy: string;
551
+ createdAt: string;
552
+ locale: string;
553
+ }
554
+ interface TemplateVersionHistoryProps {
555
+ templateId: string;
556
+ basePath?: string;
557
+ className?: string;
558
+ /** Whether the roll back action is offered for archived versions. */
559
+ canRollback?: boolean;
560
+ }
561
+ /**
562
+ * Version history data-list for a template. Lists every version with its status,
563
+ * author, and date, and offers a roll back action for archived versions.
564
+ */
565
+ declare function TemplateVersionHistory({ templateId, basePath, className, canRollback, }: TemplateVersionHistoryProps): react_jsx_runtime.JSX.Element;
566
+
567
+ interface DeliveryLogRow {
568
+ id: string;
569
+ recipientEmail: string;
570
+ status: TemplateStatus;
571
+ attempts: number;
572
+ lastError: string | null;
573
+ createdAt: string;
574
+ }
575
+ interface DeliveryLogPage {
576
+ items: DeliveryLogRow[];
577
+ total: number;
578
+ page: number;
579
+ limit: number;
580
+ totalPages: number;
581
+ }
582
+ interface DeliveryLogViewerProps {
583
+ templateId: string;
584
+ basePath?: string;
585
+ className?: string;
586
+ }
587
+ /**
588
+ * Paginated viewer for email delivery logs filtered by template. Renders
589
+ * recipient, status, attempt count, and the last error per row.
590
+ */
591
+ declare function DeliveryLogViewer({ templateId, basePath, className, }: DeliveryLogViewerProps): react_jsx_runtime.JSX.Element;
592
+
593
+ interface BroadcastListItem {
594
+ id: string;
595
+ templateId: string;
596
+ type: string | null;
597
+ status: string;
598
+ channels: string[];
599
+ totalRecipients: number;
600
+ sentCount: number;
601
+ failedCount: number;
602
+ skippedCount: number;
603
+ createdBy: string;
604
+ startedAt: string | null;
605
+ completedAt: string | null;
606
+ createdAt: string;
607
+ }
608
+ interface BroadcastListPage {
609
+ items: BroadcastListItem[];
610
+ total: number;
611
+ page: number;
612
+ limit: number;
613
+ totalPages: number;
614
+ }
615
+ interface UseBroadcastsOptions {
616
+ page?: number;
617
+ status?: string;
618
+ basePath?: string;
619
+ }
620
+ /** Paginated broadcast history. Optionally filters by status. */
621
+ declare function useBroadcasts({ page, status, basePath }?: UseBroadcastsOptions): _tanstack_react_query.UseQueryResult<BroadcastListPage, _quanticjs_react_core.ApiError>;
622
+
623
+ interface BroadcastListProps {
624
+ basePath?: string;
625
+ status?: string;
626
+ onSelect?: (id: string) => void;
627
+ className?: string;
628
+ }
629
+ /**
630
+ * Paginated table of broadcast history. Renders template, status, channels,
631
+ * sent/failed/skipped counts, creator, and creation time. When `onSelect` is
632
+ * supplied each row becomes a button to drill into that broadcast.
633
+ */
634
+ declare function BroadcastList({ basePath, status, onSelect, className, }: BroadcastListProps): react_jsx_runtime.JSX.Element;
635
+
636
+ interface BroadcastDetail {
637
+ id: string;
638
+ templateId: string;
639
+ status: string;
640
+ channels: string[];
641
+ totalRecipients: number;
642
+ sentCount: number;
643
+ failedCount: number;
644
+ skippedCount: number;
645
+ startedAt: string | null;
646
+ completedAt: string | null;
647
+ createdAt: string;
648
+ }
649
+ interface BroadcastProgressProps {
650
+ broadcastId: string;
651
+ basePath?: string;
652
+ onCancelled?: () => void;
653
+ className?: string;
654
+ }
655
+ /**
656
+ * Live progress for a single broadcast. Polls every 5s while the status is
657
+ * non-terminal, then stops. Shows sent/failed/skipped/total counters, a
658
+ * progress bar, and a Cancel action.
659
+ */
660
+ declare function BroadcastProgress({ broadcastId, basePath, onCancelled, className, }: BroadcastProgressProps): react_jsx_runtime.JSX.Element;
661
+
662
+ interface BroadcastCreatedResult {
663
+ id: string;
664
+ }
665
+ interface BroadcastComposerProps {
666
+ basePath?: string;
667
+ onCreated?: (id: string) => void;
668
+ className?: string;
669
+ }
670
+ /**
671
+ * Compose and dispatch a broadcast. Loads templates and segments, lets the user
672
+ * pick channels and either a segment or an explicit recipient list, and submits
673
+ * with a stable idempotency key per compose session.
674
+ */
675
+ declare function BroadcastComposer({ basePath, onCreated, className, }: BroadcastComposerProps): react_jsx_runtime.JSX.Element;
676
+
677
+ interface Segment {
678
+ id: string;
679
+ name: string;
680
+ type: string;
681
+ description: string | null;
682
+ recipientIds: string[] | null;
683
+ createdBy: string;
684
+ createdAt: string;
685
+ }
686
+ interface SegmentListProps {
687
+ basePath?: string;
688
+ onSelect?: (id: string) => void;
689
+ onCreate?: () => void;
690
+ className?: string;
691
+ }
692
+ /**
693
+ * Table of audience segments. Renders name, type, description, recipient count,
694
+ * and creation time. When `onSelect` is supplied each name becomes a button.
695
+ * When `onCreate` is supplied a "New segment" button is rendered in the header.
696
+ */
697
+ declare function SegmentList({ basePath, onSelect, onCreate, className, }: SegmentListProps): react_jsx_runtime.JSX.Element;
698
+
699
+ type SegmentType = 'static' | 'dynamic';
700
+ interface SegmentForm {
701
+ name: string;
702
+ type: SegmentType;
703
+ description: string;
704
+ recipientIds: string[];
705
+ }
706
+ interface SegmentBuilderProps {
707
+ basePath?: string;
708
+ segmentId?: string;
709
+ initial?: Partial<SegmentForm>;
710
+ onSaved?: (id: string) => void;
711
+ onDeleted?: () => void;
712
+ className?: string;
713
+ }
714
+ /**
715
+ * Create/edit form for audience segments. Creates via POST and (when
716
+ * `segmentId` is set) edits via PATCH with a guarded Delete action. Validates
717
+ * client-side and surfaces field-level errors plus ApiError-aware toasts.
718
+ */
719
+ declare function SegmentBuilder({ basePath, segmentId, initial, onSaved, onDeleted, className, }: SegmentBuilderProps): react_jsx_runtime.JSX.Element;
720
+
721
+ type SuppressionChannel = 'inapp' | 'email' | 'push' | 'sms';
722
+ interface Suppression {
723
+ id: string;
724
+ channel: string;
725
+ address: string;
726
+ reason: string;
727
+ createdAt: string;
728
+ }
729
+ interface SuppressionPage {
730
+ items: Suppression[];
731
+ total: number;
732
+ page: number;
733
+ limit: number;
734
+ totalPages: number;
735
+ }
736
+ interface SuppressionManagerProps {
737
+ basePath?: string;
738
+ className?: string;
739
+ }
740
+ /**
741
+ * Manage the delivery suppression list. Lists suppressed addresses (paginated)
742
+ * with per-row removal, and an inline add form. All mutations refetch the list
743
+ * and surface ApiError-aware toasts.
744
+ */
745
+ declare function SuppressionManager({ basePath, className }: SuppressionManagerProps): react_jsx_runtime.JSX.Element;
746
+
747
+ type DlqStatusFilter = 'queued' | 'replayed' | 'discarded';
748
+ interface DlqMessage {
749
+ id: string;
750
+ requestId: string | null;
751
+ failureReason: string;
752
+ status: string;
753
+ attemptCount: number;
754
+ firstSeenAt: string;
755
+ }
756
+ interface DlqPage {
757
+ items: DlqMessage[];
758
+ total: number;
759
+ page: number;
760
+ limit: number;
761
+ totalPages: number;
762
+ }
763
+ interface DlqMessageDetail {
764
+ id: string;
765
+ requestId: string | null;
766
+ failureReason: string;
767
+ errorMessage: string | null;
768
+ status: string;
769
+ attemptCount: number;
770
+ firstSeenAt: string;
771
+ replayedAt: string | null;
772
+ payload?: unknown;
773
+ }
774
+ interface DlqConsoleProps {
775
+ basePath?: string;
776
+ className?: string;
777
+ }
778
+ /**
779
+ * Dead-letter queue console. Lists failed messages (paginated, status-filtered)
780
+ * with per-row expand to view payload/detail, plus Replay and Discard actions.
781
+ * All mutations refetch the list and surface ApiError-aware toasts.
782
+ */
783
+ declare function DlqConsole({ basePath, className }: DlqConsoleProps): react_jsx_runtime.JSX.Element;
784
+
785
+ interface CatalogEntry {
786
+ key: string;
787
+ locale: string;
788
+ value: string;
789
+ }
790
+ interface CatalogEditorProps {
791
+ basePath?: string;
792
+ className?: string;
793
+ }
794
+ /**
795
+ * i18n catalog editor. Lists catalog entries with a key filter, supports inline
796
+ * value editing, per-entry delete, and an add form. All mutations refetch and
797
+ * surface ApiError-aware toasts.
798
+ */
799
+ declare function CatalogEditor({ basePath, className }: CatalogEditorProps): react_jsx_runtime.JSX.Element;
800
+
801
+ interface MissingEntry {
802
+ key: string;
803
+ locale: string;
804
+ type?: string;
805
+ }
806
+ interface MissingTranslationsPanelProps {
807
+ basePath?: string;
808
+ className?: string;
809
+ }
810
+ /**
811
+ * Reports translation keys that have no value for one or more locales. An empty
812
+ * result is the healthy state ("No missing translations").
813
+ */
814
+ declare function MissingTranslationsPanel({ basePath, className, }: MissingTranslationsPanelProps): react_jsx_runtime.JSX.Element;
815
+
816
+ interface FallbackEntry {
817
+ key: string;
818
+ requestedLocale: string;
819
+ resolvedLocale: string;
820
+ steps?: string[];
821
+ }
822
+ interface FallbackReportPanelProps {
823
+ basePath?: string;
824
+ className?: string;
825
+ }
826
+ /**
827
+ * Shows translation keys that resolved through locale fallback, including the
828
+ * requested vs. resolved locale and the resolution chain when available.
829
+ */
830
+ declare function FallbackReportPanel({ basePath, className }: FallbackReportPanelProps): react_jsx_runtime.JSX.Element;
831
+
832
+ interface RecipientSummary {
833
+ userId: string;
834
+ email: string | null;
835
+ emailVerified: boolean;
836
+ phone: string | null;
837
+ phoneVerified: boolean;
838
+ locale: string | null;
839
+ timezone: string | null;
840
+ consentEmail: boolean;
841
+ consentPush: boolean;
842
+ consentSms: boolean;
843
+ createdAt: string;
844
+ }
845
+ interface RecipientPage {
846
+ items: RecipientSummary[];
847
+ total: number;
848
+ page: number;
849
+ limit: number;
850
+ totalPages: number;
851
+ }
852
+ interface RecipientAdminPanelProps {
853
+ basePath?: string;
854
+ className?: string;
855
+ }
856
+ /**
857
+ * Recipient search with GDPR actions. Paginated, searchable recipient table
858
+ * with per-row data export and erase (confirmed). All mutations surface
859
+ * ApiError-aware toasts; erase refetches the list.
860
+ */
861
+ declare function RecipientAdminPanel({ basePath, className }: RecipientAdminPanelProps): react_jsx_runtime.JSX.Element;
862
+
863
+ interface WebhookEndpoint {
864
+ id: string;
865
+ url: string;
866
+ events: string[];
867
+ active: boolean;
868
+ createdAt: string;
869
+ }
870
+ interface WebhookDelivery {
871
+ id: string;
872
+ status: string;
873
+ createdAt: string;
874
+ }
875
+ interface WebhookEndpointManagerProps {
876
+ basePath?: string;
877
+ className?: string;
878
+ }
879
+ /**
880
+ * Manage webhook endpoints. Lists endpoints with create form, per-row active
881
+ * toggle, delete (confirmed), and a lazy deliveries expander. All mutations
882
+ * refetch and surface ApiError-aware toasts.
883
+ */
884
+ declare function WebhookEndpointManager({ basePath, className, }: WebhookEndpointManagerProps): react_jsx_runtime.JSX.Element;
885
+
886
+ interface OperationsChannelStat {
887
+ channel: string;
888
+ sends: number;
889
+ delivered: number;
890
+ failed: number;
891
+ }
892
+ interface OperationsOverviewResponse {
893
+ windowHours: number;
894
+ channels: OperationsChannelStat[];
895
+ totalSends: number;
896
+ totalDelivered: number;
897
+ totalFailed: number;
898
+ dlqPending: number;
899
+ broadcastsInFlight: number;
900
+ queueHealthy: boolean;
901
+ generatedAt: string;
902
+ }
903
+ interface OperationsOverviewProps {
904
+ basePath?: string;
905
+ className?: string;
906
+ }
907
+ /**
908
+ * Operations overview dashboard. Renders summary stat cards (sends / delivered
909
+ * / failed over the reporting window), a per-channel breakdown table, and
910
+ * health indicators (DLQ pending, broadcasts in flight, queue health).
911
+ */
912
+ declare function OperationsOverview({ basePath, className }: OperationsOverviewProps): react_jsx_runtime.JSX.Element;
913
+
914
+ interface DeliveryLogExplorerRow {
915
+ id: string;
916
+ channel: string;
917
+ userId: string;
918
+ recipient: string | null;
919
+ status: string;
920
+ provider: string | null;
921
+ attempts: number;
922
+ sentAt: string | null;
923
+ createdAt: string;
924
+ }
925
+ interface DeliveryLogExplorerPage {
926
+ items: DeliveryLogExplorerRow[];
927
+ total: number;
928
+ page: number;
929
+ limit: number;
930
+ totalPages: number;
931
+ }
932
+ interface DeliveryLogExplorerProps {
933
+ basePath?: string;
934
+ className?: string;
935
+ }
936
+ /**
937
+ * Cross-channel delivery log explorer. Filterable by channel, status,
938
+ * recipient, user, and date range; paginated. Recipients are masked
939
+ * server-side. Changing any filter resets to page 1.
940
+ */
941
+ declare function DeliveryLogExplorer({ basePath, className }: DeliveryLogExplorerProps): react_jsx_runtime.JSX.Element;
942
+
943
+ interface QuietHours {
944
+ enabled: boolean;
945
+ start: string;
946
+ end: string;
947
+ timezone: string;
948
+ }
949
+ interface QuietHoursFormProps {
950
+ basePath?: string;
951
+ className?: string;
952
+ }
953
+ /**
954
+ * Quiet-hours configuration form. Loads the current window via GET and saves
955
+ * via PUT. Tolerates absent/legacy fields (startHour/endHour) and falls back
956
+ * to sensible defaults. ApiError-aware toasts on save.
957
+ */
958
+ declare function QuietHoursForm({ basePath, className }: QuietHoursFormProps): react_jsx_runtime.JSX.Element;
959
+
960
+ interface Cap {
961
+ type: string;
962
+ maxPerDay: number;
963
+ }
964
+ interface FrequencyCapTableProps {
965
+ basePath?: string;
966
+ className?: string;
967
+ }
968
+ /**
969
+ * Frequency-cap editor. Loads the current per-type caps via GET, renders an
970
+ * editable table with add/remove rows, and saves the full list via PUT.
971
+ * Tolerates array | { caps } shapes and limit/maxPerDay/perDay field names.
972
+ */
973
+ declare function FrequencyCapTable({ basePath, className }: FrequencyCapTableProps): react_jsx_runtime.JSX.Element;
974
+
975
+ interface TenantConfig {
976
+ notificationTypes: string[];
977
+ immediateEmailTypes: string[];
978
+ }
979
+ interface TenantConfigFormProps {
980
+ basePath?: string;
981
+ className?: string;
982
+ }
983
+ /**
984
+ * Tenant notification-config form. Edits the set of notification types and the
985
+ * subset enabled for immediate email. Enforces (matching the backend rule)
986
+ * that immediateEmailTypes is a subset of notificationTypes.
987
+ */
988
+ declare function TenantConfigForm({ basePath, className }: TenantConfigFormProps): react_jsx_runtime.JSX.Element;
989
+
990
+ interface TrackingConfig {
991
+ openTrackingEnabled: boolean;
992
+ clickTrackingEnabled: boolean;
993
+ }
994
+ interface TrackingConfigFormProps {
995
+ basePath?: string;
996
+ className?: string;
997
+ }
998
+ /**
999
+ * Email tracking-config form. Loads open/click tracking flags via GET and
1000
+ * persists them via POST. Tolerates absent or legacy field names and defaults
1001
+ * both flags to off. ApiError-aware toasts on save.
1002
+ */
1003
+ declare function TrackingConfigForm({ basePath, className }: TrackingConfigFormProps): react_jsx_runtime.JSX.Element;
1004
+
1005
+ interface ApiKey {
1006
+ id: string;
1007
+ name: string;
1008
+ prefix?: string;
1009
+ /** Bound application slug (SPEC-application-scoping); null/absent = unscoped. */
1010
+ applicationKey?: string | null;
1011
+ createdAt: string;
1012
+ lastUsedAt?: string | null;
1013
+ revoked?: boolean;
1014
+ }
1015
+ interface ApiKeyCreateResponse {
1016
+ id?: string;
1017
+ name?: string;
1018
+ key?: string;
1019
+ secret?: string;
1020
+ }
1021
+ interface ApiKeyManagerProps {
1022
+ basePath?: string;
1023
+ className?: string;
1024
+ }
1025
+ /**
1026
+ * API key manager. Lists keys, creates new keys (surfacing the one-time secret
1027
+ * in a toast), and revokes keys (confirmed). All mutations surface
1028
+ * ApiError-aware toasts. See file-level note re: backend availability.
1029
+ */
1030
+ declare function ApiKeyManager({ basePath, className }: ApiKeyManagerProps): react_jsx_runtime.JSX.Element;
1031
+
1032
+ interface Application {
1033
+ id: string;
1034
+ key: string;
1035
+ displayName: string;
1036
+ description: string | null;
1037
+ status: 'active' | 'disabled';
1038
+ createdAt: string;
1039
+ updatedAt: string;
1040
+ }
1041
+ interface ApplicationRegistryPanelProps {
1042
+ /** API path prefix (BFF). Endpoints are mounted at `${basePath}/admin/applications`. */
1043
+ basePath?: string;
1044
+ className?: string;
1045
+ }
1046
+ /**
1047
+ * Global application registry manager (SPEC-application-scoping-and-registry).
1048
+ * Lists registered applications, registers new ones, and enables/disables them.
1049
+ * Platform-admin only (the backend gates `notification:platform-admin`). All
1050
+ * mutations surface ApiError-aware toasts.
1051
+ */
1052
+ declare function ApplicationRegistryPanel({ basePath, className, }: ApplicationRegistryPanelProps): react_jsx_runtime.JSX.Element;
1053
+
1054
+ export { type ApiKey, type ApiKeyCreateResponse, ApiKeyManager, type ApiKeyManagerProps, type Application, ApplicationRegistryPanel, type ApplicationRegistryPanelProps, BroadcastComposer, type BroadcastComposerProps, type BroadcastCreatedResult, type BroadcastDetail, BroadcastList, type BroadcastListItem, type BroadcastListPage, type BroadcastListProps, BroadcastProgress, type BroadcastProgressProps, type Cap, CatalogEditor, type CatalogEditorProps, type CatalogEntry, type DailyDeliveryStats, type DeliveryAnalyticsFilters, DeliveryAnalyticsPage, type DeliveryAnalyticsPageProps, type DeliveryFunnel, DeliveryLogExplorer, type DeliveryLogExplorerPage, type DeliveryLogExplorerProps, type DeliveryLogExplorerRow, type DeliveryLogPage, type DeliveryLogRow, DeliveryLogViewer, type DeliveryLogViewerProps, type DeliveryTypeBreakdown, type DigestPeriod, DlqConsole, type DlqConsoleProps, type DlqMessage, type DlqMessageDetail, type DlqPage, type DlqStatusFilter, type FallbackEntry, FallbackReportPanel, type FallbackReportPanelProps, FrequencyCapTable, type FrequencyCapTableProps, FunnelStats, type FunnelStatsProps, type MissingEntry, MissingTranslationsPanel, type MissingTranslationsPanelProps, NotificationBell, type NotificationBellProps, type NotificationChannel, type NotificationConfig, type NotificationFeedItem, NotificationInbox, type NotificationInboxProps, type NotificationPreferenceDto, NotificationPreferences, type NotificationPreferencesProps, NotificationProvider, type NotificationProviderProps, NotificationRealtimeProvider, type NotificationRealtimeProviderProps, type OperationsChannelStat, OperationsOverview, type OperationsOverviewProps, type OperationsOverviewResponse, type PaginatedFeed, type PreviewResult, type QuietHours, QuietHoursForm, type QuietHoursFormProps, type RealtimeStatus, RecipientAdminPanel, type RecipientAdminPanelProps, type RecipientPage, type RecipientSummary, type Segment, SegmentBuilder, type SegmentBuilderProps, type SegmentForm, SegmentList, type SegmentListProps, type SegmentType, type Suppression, type SuppressionChannel, SuppressionManager, type SuppressionManagerProps, type SuppressionPage, TemplateEditor, type TemplateEditorFields, type TemplateEditorProps, TemplateList, type TemplateListItem, type TemplateListProps, TemplatePreviewPane, type TemplatePreviewPaneProps, type TemplateStatus, TemplateStatusBadge, type TemplateVersion, TemplateVersionHistory, type TemplateVersionHistoryProps, type TemplateVersionResponse, type TenantConfig, TenantConfigForm, type TenantConfigFormProps, type TrackingConfig, TrackingConfigForm, type TrackingConfigFormProps, TrendChart, type TrendChartProps, TypeTable, type TypeTableProps, type UseBroadcastsOptions, type UseDeliveryAnalyticsOptions, type UseDeliveryTypesOptions, type UseFunnelStatsOptions, type UseNotificationFeedOptions, type UseUnreadCountOptions, type WebhookDelivery, type WebhookEndpoint, WebhookEndpointManager, type WebhookEndpointManagerProps, useBroadcasts, useDeliveryAnalytics, useDeliveryTypes, useFunnelStats, useNotificationConfig, useNotificationFeed, useRealtimeContext, useUnreadCount };