@luxexchange/notifications 1.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.
- package/.depcheckrc +14 -0
- package/.eslintrc.js +20 -0
- package/README.md +548 -0
- package/package.json +42 -0
- package/project.json +30 -0
- package/src/getIsNotificationServiceLocalOverrideEnabled.ts +7 -0
- package/src/global.d.ts +2 -0
- package/src/index.ts +41 -0
- package/src/notification-data-source/NotificationDataSource.ts +8 -0
- package/src/notification-data-source/getNotificationQueryOptions.ts +85 -0
- package/src/notification-data-source/implementations/createIntervalNotificationDataSource.ts +73 -0
- package/src/notification-data-source/implementations/createLocalTriggerDataSource.test.ts +492 -0
- package/src/notification-data-source/implementations/createLocalTriggerDataSource.ts +177 -0
- package/src/notification-data-source/implementations/createNotificationDataSource.ts +19 -0
- package/src/notification-data-source/implementations/createPollingNotificationDataSource.test.ts +398 -0
- package/src/notification-data-source/implementations/createPollingNotificationDataSource.ts +74 -0
- package/src/notification-data-source/implementations/createReactiveDataSource.ts +113 -0
- package/src/notification-data-source/types/ReactiveCondition.ts +60 -0
- package/src/notification-processor/NotificationProcessor.ts +26 -0
- package/src/notification-processor/implementations/createBaseNotificationProcessor.test.ts +854 -0
- package/src/notification-processor/implementations/createBaseNotificationProcessor.ts +239 -0
- package/src/notification-processor/implementations/createNotificationProcessor.test.ts +130 -0
- package/src/notification-processor/implementations/createNotificationProcessor.ts +15 -0
- package/src/notification-renderer/NotificationRenderer.ts +8 -0
- package/src/notification-renderer/components/BannerTemplate.tsx +188 -0
- package/src/notification-renderer/components/InlineBannerNotification.tsx +123 -0
- package/src/notification-renderer/implementations/createNotificationRenderer.ts +16 -0
- package/src/notification-renderer/utils/iconUtils.ts +103 -0
- package/src/notification-service/NotificationService.ts +47 -0
- package/src/notification-service/implementations/createNotificationService.test.ts +1092 -0
- package/src/notification-service/implementations/createNotificationService.ts +364 -0
- package/src/notification-telemetry/NotificationTelemetry.ts +44 -0
- package/src/notification-telemetry/implementations/createNotificationTelemetry.test.ts +99 -0
- package/src/notification-telemetry/implementations/createNotificationTelemetry.ts +33 -0
- package/src/notification-tracker/NotificationTracker.ts +14 -0
- package/src/notification-tracker/implementations/createApiNotificationTracker.test.ts +465 -0
- package/src/notification-tracker/implementations/createApiNotificationTracker.ts +154 -0
- package/src/notification-tracker/implementations/createNoopNotificationTracker.ts +44 -0
- package/src/notification-tracker/implementations/createNotificationTracker.ts +31 -0
- package/src/utils/formatNotificationType.test.ts +25 -0
- package/src/utils/formatNotificationType.ts +25 -0
- package/tsconfig.json +24 -0
- package/tsconfig.lint.json +8 -0
- package/vitest-setup.ts +1 -0
- package/vitest.config.ts +14 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type InAppNotification } from '@luxfi/api'
|
|
2
|
+
import { type NotificationRenderer } from '@luxfi/notifications/src/notification-renderer/NotificationRenderer'
|
|
3
|
+
|
|
4
|
+
export function createNotificationRenderer(ctx: {
|
|
5
|
+
render: (notification: InAppNotification) => () => void
|
|
6
|
+
canRender: (notification: InAppNotification) => boolean
|
|
7
|
+
}): NotificationRenderer {
|
|
8
|
+
return {
|
|
9
|
+
render: (notification: InAppNotification): (() => void) => {
|
|
10
|
+
return ctx.render(notification)
|
|
11
|
+
},
|
|
12
|
+
canRender: (notification: InAppNotification): boolean => {
|
|
13
|
+
return ctx.canRender(notification)
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { GeneratedIcon } from '@luxfi/ui/src/components/factories/createIcon'
|
|
2
|
+
import { AlertTriangle } from '@luxfi/ui/src/components/icons/AlertTriangle'
|
|
3
|
+
import { Bell } from '@luxfi/ui/src/components/icons/Bell'
|
|
4
|
+
import { Chart } from '@luxfi/ui/src/components/icons/Chart'
|
|
5
|
+
import { CheckCircleFilled } from '@luxfi/ui/src/components/icons/CheckCircleFilled'
|
|
6
|
+
import { Coin } from '@luxfi/ui/src/components/icons/Coin'
|
|
7
|
+
import { CoinConvert } from '@luxfi/ui/src/components/icons/CoinConvert'
|
|
8
|
+
import { EthMini } from '@luxfi/ui/src/components/icons/EthMini'
|
|
9
|
+
import { Gas } from '@luxfi/ui/src/components/icons/Gas'
|
|
10
|
+
import { Gift } from '@luxfi/ui/src/components/icons/Gift'
|
|
11
|
+
import { Globe } from '@luxfi/ui/src/components/icons/Globe'
|
|
12
|
+
import { InfoCircleFilled } from '@luxfi/ui/src/components/icons/InfoCircleFilled'
|
|
13
|
+
import { Lightning } from '@luxfi/ui/src/components/icons/Lightning'
|
|
14
|
+
import { Rocket } from '@luxfi/ui/src/components/icons/Rocket'
|
|
15
|
+
import { SendAction } from '@luxfi/ui/src/components/icons/SendAction'
|
|
16
|
+
import { ShieldCheck } from '@luxfi/ui/src/components/icons/ShieldCheck'
|
|
17
|
+
import { Star } from '@luxfi/ui/src/components/icons/Star'
|
|
18
|
+
import { Wallet } from '@luxfi/ui/src/components/icons/Wallet'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Map of custom icon names to their corresponding icon components.
|
|
22
|
+
* Used for parsing notification icon links in the format "custom:<iconName>" or "custom:<iconName>-$<colorToken>".
|
|
23
|
+
*/
|
|
24
|
+
export const CUSTOM_ICON_MAP: Record<string, GeneratedIcon> = {
|
|
25
|
+
lightning: Lightning,
|
|
26
|
+
wallet: Wallet,
|
|
27
|
+
chart: Chart,
|
|
28
|
+
gas: Gas,
|
|
29
|
+
coin: Coin,
|
|
30
|
+
'coin-convert': CoinConvert,
|
|
31
|
+
ethereum: EthMini,
|
|
32
|
+
rocket: Rocket,
|
|
33
|
+
star: Star,
|
|
34
|
+
gift: Gift,
|
|
35
|
+
check: CheckCircleFilled,
|
|
36
|
+
info: InfoCircleFilled,
|
|
37
|
+
shield: ShieldCheck,
|
|
38
|
+
bell: Bell,
|
|
39
|
+
send: SendAction,
|
|
40
|
+
globe: Globe,
|
|
41
|
+
// Alert/warning icons
|
|
42
|
+
'alert-triangle': AlertTriangle,
|
|
43
|
+
'caution-triangle': AlertTriangle,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ParsedCustomIcon {
|
|
47
|
+
iconName: string
|
|
48
|
+
colorToken: string | undefined
|
|
49
|
+
IconComponent: GeneratedIcon | undefined
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Parses a custom icon link string and returns the icon component and color token.
|
|
54
|
+
*
|
|
55
|
+
* Supports two formats:
|
|
56
|
+
* - "custom:<iconName>" - Returns icon with no color token (use default)
|
|
57
|
+
* - "custom:<iconName>-$<colorToken>" - Returns icon with specified color token
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* parseCustomIconLink("custom:globe") // { iconName: "globe", colorToken: undefined, IconComponent: Globe }
|
|
61
|
+
* parseCustomIconLink("custom:lightning-$accent1") // { iconName: "lightning", colorToken: "$accent1", IconComponent: Lightning }
|
|
62
|
+
* parseCustomIconLink("https://example.com/icon.png") // { iconName: "", colorToken: undefined, IconComponent: undefined }
|
|
63
|
+
*/
|
|
64
|
+
export function parseCustomIconLink(iconLink: string | undefined): ParsedCustomIcon {
|
|
65
|
+
if (!iconLink || typeof iconLink !== 'string' || !iconLink.startsWith('custom:')) {
|
|
66
|
+
return { iconName: '', colorToken: undefined, IconComponent: undefined }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Remove "custom:" prefix
|
|
70
|
+
const customPart = iconLink.slice(7)
|
|
71
|
+
|
|
72
|
+
// Check for color token format: "iconName-$colorToken"
|
|
73
|
+
const colorTokenMatch = customPart.match(/^(.+)-(\$\w+)$/)
|
|
74
|
+
if (colorTokenMatch && colorTokenMatch[1] && colorTokenMatch[2]) {
|
|
75
|
+
const iconName = colorTokenMatch[1]
|
|
76
|
+
const colorToken = colorTokenMatch[2]
|
|
77
|
+
return {
|
|
78
|
+
iconName,
|
|
79
|
+
colorToken,
|
|
80
|
+
IconComponent: CUSTOM_ICON_MAP[iconName],
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Simple format: just "iconName"
|
|
85
|
+
const iconName = customPart.toLowerCase()
|
|
86
|
+
return {
|
|
87
|
+
iconName,
|
|
88
|
+
colorToken: undefined,
|
|
89
|
+
IconComponent: CUSTOM_ICON_MAP[iconName],
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Gets the icon component for a custom icon link, returning undefined if not found.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* getCustomIconComponent("custom:globe") // Globe
|
|
98
|
+
* getCustomIconComponent("custom:lightning-$accent1") // Lightning
|
|
99
|
+
* getCustomIconComponent("https://example.com/icon.png") // undefined
|
|
100
|
+
*/
|
|
101
|
+
export function getCustomIconComponent(iconLink: string | undefined): GeneratedIcon | undefined {
|
|
102
|
+
return parseCustomIconLink(iconLink).IconComponent
|
|
103
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type NotificationDataSource } from '@luxfi/notifications/src/notification-data-source/NotificationDataSource'
|
|
2
|
+
import { type NotificationProcessor } from '@luxfi/notifications/src/notification-processor/NotificationProcessor'
|
|
3
|
+
import { type NotificationRenderer } from '@luxfi/notifications/src/notification-renderer/NotificationRenderer'
|
|
4
|
+
import { type NotificationTelemetry } from '@luxfi/notifications/src/notification-telemetry/NotificationTelemetry'
|
|
5
|
+
import { type NotificationTracker } from '@luxfi/notifications/src/notification-tracker/NotificationTracker'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents what was clicked on a notification
|
|
9
|
+
*/
|
|
10
|
+
export type NotificationClickTarget = { type: 'button'; index: number } | { type: 'background' } | { type: 'dismiss' }
|
|
11
|
+
|
|
12
|
+
export interface NotificationServiceConfig {
|
|
13
|
+
// Multiple sources can feed notifications
|
|
14
|
+
dataSources: NotificationDataSource[]
|
|
15
|
+
tracker: NotificationTracker
|
|
16
|
+
processor: NotificationProcessor
|
|
17
|
+
renderer: NotificationRenderer
|
|
18
|
+
telemetry?: NotificationTelemetry
|
|
19
|
+
// Platform-specific handler for navigation/link clicks
|
|
20
|
+
// Should handle both internal navigation (same-origin) and external links
|
|
21
|
+
onNavigate?: (url: string) => void
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface NotificationService {
|
|
25
|
+
// Initialize and start fetching notifications
|
|
26
|
+
initialize(): Promise<void>
|
|
27
|
+
/**
|
|
28
|
+
* Handle a render failure (e.g., unknown notification style)
|
|
29
|
+
* Cleans up the render without marking the notification as processed,
|
|
30
|
+
* allowing it to be re-rendered when correct data arrives
|
|
31
|
+
*/
|
|
32
|
+
onRenderFailed(notificationId: string): void
|
|
33
|
+
/**
|
|
34
|
+
* Handle a click on a notification (button, background, dismiss, or acknowledge)
|
|
35
|
+
* Executes all actions specified in the onClick array for the clicked target
|
|
36
|
+
* @param notificationId - ID of the notification that was clicked
|
|
37
|
+
* @param target - What was clicked (button, background, dismiss, or acknowledge)
|
|
38
|
+
*/
|
|
39
|
+
onNotificationClick(notificationId: string, target: NotificationClickTarget): void
|
|
40
|
+
/**
|
|
41
|
+
* Handle a notification being shown to the user
|
|
42
|
+
* @param notificationId - ID of the notification that was shown
|
|
43
|
+
*/
|
|
44
|
+
onNotificationShown(notificationId: string): void
|
|
45
|
+
// Cleanup and teardown
|
|
46
|
+
destroy(): void
|
|
47
|
+
}
|