@edusight/notification-widget 1.0.30 → 1.0.32
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/{components-DgV3nlCC.js → components-D8XxiFEB.js} +2 -1
- package/dist/{components-DgV3nlCC.js.map → components-D8XxiFEB.js.map} +1 -1
- package/dist/{components-B9Z6HsnI.cjs → components-KafszaqK.cjs} +2 -1
- package/dist/{components-B9Z6HsnI.cjs.map → components-KafszaqK.cjs.map} +1 -1
- package/dist/{hooks-Cv5k48VE.js → hooks-BTG0z6yd.js} +65 -48
- package/dist/hooks-BTG0z6yd.js.map +1 -0
- package/dist/hooks-kLhwdW29.cjs +2 -0
- package/dist/hooks-kLhwdW29.cjs.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.css +1 -1
- package/dist/index.esm.js +3 -3
- package/package.json +2 -2
- package/dist/hooks-CggRWw6Q.cjs +0 -2
- package/dist/hooks-CggRWw6Q.cjs.map +0 -1
- package/dist/hooks-Cv5k48VE.js.map +0 -1
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { useState as
|
|
2
|
-
const R = () => window.__notificationSDK?.client,
|
|
1
|
+
import { useState as E, useRef as j, useCallback as _, useEffect as N } from "react";
|
|
2
|
+
const R = () => window.__notificationSDK?.client, T = ({
|
|
3
3
|
preferences: t,
|
|
4
|
-
onPreferencesChange:
|
|
4
|
+
onPreferencesChange: f,
|
|
5
5
|
onError: e
|
|
6
6
|
}) => {
|
|
7
|
-
const n = R(), [c, i] =
|
|
7
|
+
const n = R(), [c, i] = E(!1), [r, l] = E(null), u = j(), m = j({}), y = _(
|
|
8
8
|
(g, v) => {
|
|
9
9
|
try {
|
|
10
10
|
l(null);
|
|
11
|
-
const
|
|
12
|
-
let p =
|
|
11
|
+
const o = { ...t }, s = g.split(".");
|
|
12
|
+
let p = o;
|
|
13
13
|
for (let a = 0; a < s.length - 1; a++)
|
|
14
14
|
p[s[a]] === void 0 && (p[s[a]] = {}), p = p[s[a]];
|
|
15
|
-
p[s[s.length - 1]] = v, o
|
|
15
|
+
p[s[s.length - 1]] = v, f(o), m.current[g] = v, u.current && clearTimeout(u.current), i(!0), u.current = setTimeout(async () => {
|
|
16
16
|
try {
|
|
17
17
|
if (!n)
|
|
18
18
|
throw new Error("Notification client not available");
|
|
19
19
|
const a = window.__notificationSDK?.config;
|
|
20
20
|
if (!a)
|
|
21
21
|
throw new Error("SDK configuration not available");
|
|
22
|
-
const { subscriberId: h, tenantId:
|
|
23
|
-
if (!h || !
|
|
22
|
+
const { subscriberId: h, tenantId: A, environmentId: D } = a;
|
|
23
|
+
if (!h || !A || !D)
|
|
24
24
|
throw new Error("SubscriberId, TenantId or EnvironmentId not available in SDK configuration.");
|
|
25
|
-
const
|
|
26
|
-
emailEnabled:
|
|
27
|
-
pushEnabled:
|
|
28
|
-
inAppEnabled:
|
|
29
|
-
smsEnabled:
|
|
25
|
+
const d = {
|
|
26
|
+
emailEnabled: o.channels.email,
|
|
27
|
+
pushEnabled: o.channels.push,
|
|
28
|
+
inAppEnabled: o.channels.inApp,
|
|
29
|
+
smsEnabled: o.channels.sms
|
|
30
30
|
};
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
o.subscriptions.length > 0 && (d.categories = {}, o.subscriptions.forEach((b) => {
|
|
32
|
+
d.categories[b.workflowId] = {
|
|
33
33
|
emailEnabled: b.channels.email,
|
|
34
34
|
pushEnabled: b.channels.push,
|
|
35
35
|
inAppEnabled: b.channels.inApp,
|
|
36
36
|
smsEnabled: b.channels.sms
|
|
37
37
|
};
|
|
38
|
-
})), await n.preferences.update(
|
|
38
|
+
})), await n.preferences.update(A, h, d), m.current = {}, l(null);
|
|
39
39
|
} catch (a) {
|
|
40
40
|
const h = a instanceof Error ? a : new Error("Failed to save preferences");
|
|
41
41
|
process.env.NODE_ENV, l(h), e?.(h);
|
|
@@ -43,21 +43,21 @@ const R = () => window.__notificationSDK?.client, I = ({
|
|
|
43
43
|
i(!1);
|
|
44
44
|
}
|
|
45
45
|
}, 500);
|
|
46
|
-
} catch (
|
|
47
|
-
const s =
|
|
46
|
+
} catch (o) {
|
|
47
|
+
const s = o instanceof Error ? o : new Error("Failed to update preference");
|
|
48
48
|
l(s), e?.(s), i(!1);
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
|
-
[t,
|
|
51
|
+
[t, f, n, e]
|
|
52
52
|
);
|
|
53
|
-
return
|
|
53
|
+
return N(() => () => {
|
|
54
54
|
u.current && clearTimeout(u.current);
|
|
55
55
|
}, []), {
|
|
56
|
-
updatePreference:
|
|
56
|
+
updatePreference: y,
|
|
57
57
|
isSaving: c,
|
|
58
|
-
error:
|
|
58
|
+
error: r
|
|
59
59
|
};
|
|
60
|
-
}, S = (t) => !(!t || typeof t != "object" || ["notificationId", "channel", "renderedContent", "read", "archived"].filter((n) => !(n in t)).length > 0 || typeof t.channel != "string" || typeof t.read != "boolean" || typeof t.archived != "boolean" || typeof t.renderedContent != "object" || t.renderedContent === null),
|
|
60
|
+
}, S = (t) => !(!t || typeof t != "object" || ["notificationId", "channel", "renderedContent", "read", "archived"].filter((n) => !(n in t)).length > 0 || typeof t.channel != "string" || typeof t.read != "boolean" || typeof t.archived != "boolean" || typeof t.renderedContent != "object" || t.renderedContent === null), w = (t, f, e) => ({
|
|
61
61
|
type: "custom",
|
|
62
62
|
label: t.label,
|
|
63
63
|
icon: void 0,
|
|
@@ -72,30 +72,42 @@ const R = () => window.__notificationSDK?.client, I = ({
|
|
|
72
72
|
throw n;
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
}),
|
|
75
|
+
}), I = () => {
|
|
76
76
|
const t = (e, n) => {
|
|
77
77
|
if (!e || typeof e != "object")
|
|
78
78
|
return { subject: "", body: "" };
|
|
79
79
|
let c = "", i = "";
|
|
80
80
|
return e.push ? (c = e.push.title || "", i = e.push.body || "") : e.email ? (c = e.email.subject || "", i = e.email.html || e.email.text || "") : e.in_app ? (c = e.in_app.title || "", i = e.in_app.message || "") : e.sms ? (c = "SMS", i = e.sms.message || "") : n === "in_app" ? (c = e.title || "", i = e.message || "") : (c = e.title || e.subject || "", i = e.message || e.body || e.text || ""), { subject: c, body: i };
|
|
81
|
-
},
|
|
81
|
+
}, f = (e, n, c) => {
|
|
82
82
|
if (!e) return [];
|
|
83
83
|
const i = [];
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
}
|
|
84
|
+
if (Array.isArray(e))
|
|
85
|
+
return e.forEach((r) => {
|
|
86
|
+
i.push(w(r, n || "", c));
|
|
87
|
+
}), i;
|
|
88
|
+
if (e.primary) {
|
|
89
|
+
const r = e.primary;
|
|
90
|
+
i.push({
|
|
91
|
+
type: "custom",
|
|
92
|
+
label: r.label || "Primary Action",
|
|
93
|
+
icon: void 0,
|
|
94
|
+
handler: async (l) => {
|
|
95
|
+
r.url && window.open(r.url, "_self");
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (e.secondary) {
|
|
100
|
+
const r = e.secondary;
|
|
101
|
+
i.push({
|
|
102
|
+
type: "custom",
|
|
103
|
+
label: r.label || "Secondary Action",
|
|
104
|
+
icon: void 0,
|
|
105
|
+
handler: async (l) => {
|
|
106
|
+
r.url && window.open(r.url, "_self");
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return i;
|
|
99
111
|
};
|
|
100
112
|
return {
|
|
101
113
|
toWidgetNotification(e) {
|
|
@@ -108,7 +120,9 @@ const R = () => window.__notificationSDK?.client, I = ({
|
|
|
108
120
|
isArchived: e.archived,
|
|
109
121
|
timestamp: e.createdAt ? new Date(e.createdAt) : /* @__PURE__ */ new Date(),
|
|
110
122
|
tags: [],
|
|
111
|
-
actions:
|
|
123
|
+
actions: f(
|
|
124
|
+
e.renderedContent?.actions || e.actions
|
|
125
|
+
),
|
|
112
126
|
metadata: {
|
|
113
127
|
channel: e.channel,
|
|
114
128
|
renderedContent: e.renderedContent
|
|
@@ -117,10 +131,10 @@ const R = () => window.__notificationSDK?.client, I = ({
|
|
|
117
131
|
},
|
|
118
132
|
toWidgetNotificationFromWebSocket(e) {
|
|
119
133
|
if (!S(e)) {
|
|
120
|
-
const i = e?.renderedContent && typeof e.renderedContent == "object" ? e.renderedContent : {}, { subject:
|
|
134
|
+
const i = e?.renderedContent && typeof e.renderedContent == "object" ? e.renderedContent : {}, { subject: r, body: l } = t(i, e?.channel);
|
|
121
135
|
return {
|
|
122
136
|
id: e?.notificationId || `notification-${Date.now()}`,
|
|
123
|
-
subject:
|
|
137
|
+
subject: r || "Notification",
|
|
124
138
|
body: l || "",
|
|
125
139
|
isRead: e?.read || !1,
|
|
126
140
|
isArchived: e?.archived || !1,
|
|
@@ -142,7 +156,10 @@ const R = () => window.__notificationSDK?.client, I = ({
|
|
|
142
156
|
isArchived: e.archived || !1,
|
|
143
157
|
timestamp: e.createdAt ? new Date(e.createdAt) : /* @__PURE__ */ new Date(),
|
|
144
158
|
tags: [],
|
|
145
|
-
actions:
|
|
159
|
+
actions: f(
|
|
160
|
+
e.renderedContent?.actions || e.actions,
|
|
161
|
+
e.notificationId
|
|
162
|
+
),
|
|
146
163
|
metadata: {
|
|
147
164
|
channel: e.channel,
|
|
148
165
|
renderedContent: e.renderedContent
|
|
@@ -153,7 +170,7 @@ const R = () => window.__notificationSDK?.client, I = ({
|
|
|
153
170
|
};
|
|
154
171
|
};
|
|
155
172
|
export {
|
|
156
|
-
|
|
157
|
-
|
|
173
|
+
I as c,
|
|
174
|
+
T as u
|
|
158
175
|
};
|
|
159
|
-
//# sourceMappingURL=hooks-
|
|
176
|
+
//# sourceMappingURL=hooks-BTG0z6yd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-BTG0z6yd.js","sources":["../src/hooks/useLivePreferences.ts","../src/utils/notification-mapper.ts"],"sourcesContent":["import { useCallback, useRef, useState, useEffect } from 'react';\r\nimport { NotificationPreferences } from '../types/core';\r\n\r\nconst useNotificationsClient = () => {\r\n return (window as any).__notificationSDK?.client;\r\n};\r\n\r\nexport interface UseLivePreferencesProps {\r\n preferences: NotificationPreferences;\r\n onPreferencesChange: (preferences: NotificationPreferences) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport interface UseLivePreferencesResult {\r\n updatePreference: (path: string, value: any) => void;\r\n isSaving: boolean;\r\n error: Error | null;\r\n}\r\n\r\nexport const useLivePreferences = ({\r\n preferences,\r\n onPreferencesChange,\r\n onError,\r\n}: UseLivePreferencesProps): UseLivePreferencesResult => {\r\n const notificationClient = useNotificationsClient();\r\n const [isSaving, setIsSaving] = useState(false);\r\n const [error, setError] = useState<Error | null>(null);\r\n const saveTimeoutRef = useRef<NodeJS.Timeout>();\r\n const pendingUpdatesRef = useRef<{ [key: string]: any }>({});\r\n\r\n const updatePreference = useCallback(\r\n (path: string, value: any) => {\r\n try {\r\n setError(null);\r\n\r\n const updatedPreferences = { ...preferences };\r\n const pathParts = path.split('.');\r\n\r\n let current: any = updatedPreferences;\r\n for (let i = 0; i < pathParts.length - 1; i++) {\r\n if (current[pathParts[i]] === undefined) {\r\n current[pathParts[i]] = {};\r\n }\r\n current = current[pathParts[i]];\r\n }\r\n current[pathParts[pathParts.length - 1]] = value;\r\n\r\n onPreferencesChange(updatedPreferences);\r\n\r\n pendingUpdatesRef.current[path] = value;\r\n\r\n if (saveTimeoutRef.current) {\r\n clearTimeout(saveTimeoutRef.current);\r\n }\r\n\r\n setIsSaving(true);\r\n\r\n saveTimeoutRef.current = setTimeout(async () => {\r\n try {\r\n if (!notificationClient) {\r\n throw new Error('Notification client not available');\r\n }\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n\r\n if (!sdkConfig) {\r\n throw new Error('SDK configuration not available');\r\n }\r\n\r\n const { subscriberId, tenantId, environmentId } = sdkConfig;\r\n\r\n if (!subscriberId || !tenantId || !environmentId) {\r\n throw new Error('SubscriberId, TenantId or EnvironmentId not available in SDK configuration.');\r\n }\r\n\r\n const savePayload: any = {\r\n emailEnabled: updatedPreferences.channels.email,\r\n pushEnabled: updatedPreferences.channels.push,\r\n inAppEnabled: updatedPreferences.channels.inApp,\r\n smsEnabled: updatedPreferences.channels.sms,\r\n };\r\n\r\n if (updatedPreferences.subscriptions.length > 0) {\r\n savePayload.categories = {};\r\n updatedPreferences.subscriptions.forEach(sub => {\r\n savePayload.categories[sub.workflowId] = {\r\n emailEnabled: sub.channels.email,\r\n pushEnabled: sub.channels.push,\r\n inAppEnabled: sub.channels.inApp,\r\n smsEnabled: sub.channels.sms,\r\n };\r\n });\r\n }\r\n\r\n // NOTE: deliverySchedule removed as backend doesn't accept it (returns 400)\r\n // Quiet hours and weekdays management will be added when backend supports it\r\n\r\n await notificationClient.preferences.update(tenantId, subscriberId, savePayload);\r\n\r\n pendingUpdatesRef.current = {};\r\n setError(null);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to save preferences');\r\n\r\n if (process.env.NODE_ENV === 'development') {\r\n console.error('Failed to save preferences:', error);\r\n }\r\n\r\n setError(error);\r\n onError?.(error);\r\n\r\n } finally {\r\n setIsSaving(false);\r\n }\r\n }, 500);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to update preference');\r\n setError(error);\r\n onError?.(error);\r\n setIsSaving(false);\r\n }\r\n },\r\n [preferences, onPreferencesChange, notificationClient, onError]\r\n );\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (saveTimeoutRef.current) {\r\n clearTimeout(saveTimeoutRef.current);\r\n }\r\n };\r\n }, []);\r\n\r\n return {\r\n updatePreference,\r\n isSaving,\r\n error,\r\n };\r\n};","import type { RenderedNotificationItem, RenderedNotificationActionMap, NotificationAction as SDKNotificationAction } from '@edusight/notification-sdk';\nimport type { Notification, NotificationAction } from '../types/core';\n\nexport interface WebSocketNotificationReceivedPayload extends RenderedNotificationItem {}\n\nexport interface NotificationMapper {\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification;\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification;\n validateWebSocketPayload(payload: any): payload is WebSocketNotificationReceivedPayload;\n}\n\nconst validateWebSocketPayload = (payload: any): payload is WebSocketNotificationReceivedPayload => {\n if (!payload || typeof payload !== 'object') {\n console.warn('Invalid WebSocket payload: not an object', payload);\n return false;\n }\n\n const requiredFields = ['notificationId', 'channel', 'renderedContent', 'read', 'archived'];\n const missingFields = requiredFields.filter(field => !(field in payload));\n\n if (missingFields.length > 0) {\n console.warn('WebSocket payload missing required fields:', missingFields, payload);\n return false;\n }\n\n if (typeof payload.channel !== 'string') {\n console.warn('WebSocket payload channel is invalid', payload);\n return false;\n }\n\n if (typeof payload.read !== 'boolean' || typeof payload.archived !== 'boolean') {\n console.warn('WebSocket payload read/archived flags are invalid', payload);\n return false;\n }\n\n if (typeof payload.renderedContent !== 'object' || payload.renderedContent === null) {\n console.warn('WebSocket payload renderedContent is not an object', payload);\n return false;\n }\n\n return true;\n};\n\n\nconst mapSDKActionToWidgetAction = (\n sdkAction: SDKNotificationAction,\n notificationId: string,\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>\n): NotificationAction => {\n return {\n type: 'custom',\n label: sdkAction.label,\n icon: undefined,\n handler: async () => {\n try {\n if (onActionExecute) {\n await onActionExecute(sdkAction.id, notificationId);\n }\n\n if (sdkAction.url) {\n const target = sdkAction.target || '_self';\n window.open(sdkAction.url, target);\n }\n\n if (sdkAction.markAsReadOnClick) {\n // This will be handled by the widget's action handler\n }\n } catch (error) {\n console.error('Error executing action:', error);\n throw error;\n }\n },\n };\n};\n\nexport const createNotificationMapper = (): NotificationMapper => {\n const extractSubjectAndBody = (\n renderedContent: Record<string, any>,\n channel?: string\n ): { subject: string; body: string } => {\n if (!renderedContent || typeof renderedContent !== 'object') {\n return { subject: '', body: '' };\n }\n\n let subject = '';\n let body = '';\n\n if (renderedContent.push) {\n subject = renderedContent.push.title || '';\n body = renderedContent.push.body || '';\n } else if (renderedContent.email) {\n subject = renderedContent.email.subject || '';\n body = renderedContent.email.html || renderedContent.email.text || '';\n } else if (renderedContent.in_app) {\n subject = renderedContent.in_app.title || '';\n body = renderedContent.in_app.message || '';\n } else if (renderedContent.sms) {\n subject = 'SMS';\n body = renderedContent.sms.message || '';\n } else if (channel === 'in_app') {\n subject = renderedContent.title || '';\n body = renderedContent.message || '';\n } else {\n subject = renderedContent.title || renderedContent.subject || '';\n body = renderedContent.message || renderedContent.body || renderedContent.text || '';\n }\n\n return { subject, body };\n };\n\n const mapActionsToNotificationActions = (\n actions?: RenderedNotificationActionMap | SDKNotificationAction[],\n notificationId?: string,\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>\n ): NotificationAction[] => {\n if (!actions) return [];\n\n const result: NotificationAction[] = [];\n\n if (Array.isArray(actions)) {\n actions.forEach((sdkAction) => {\n result.push(mapSDKActionToWidgetAction(sdkAction, notificationId || '', onActionExecute));\n });\n return result;\n }\n\n if (actions.primary) {\n const primaryAction = actions.primary;\n result.push({\n type: 'custom',\n label: primaryAction.label || 'Primary Action',\n icon: undefined,\n handler: async (notificationId: string) => {\n if (primaryAction.url) {\n window.open(primaryAction.url, '_self');\n }\n if (onActionExecute) {\n await onActionExecute('primary', notificationId);\n }\n },\n });\n }\n\n if (actions.secondary) {\n const secondaryAction = actions.secondary;\n result.push({\n type: 'custom',\n label: secondaryAction.label || 'Secondary Action',\n icon: undefined,\n handler: async (notificationId: string) => {\n if (secondaryAction.url) {\n window.open(secondaryAction.url, '_self');\n }\n if (onActionExecute) {\n await onActionExecute('secondary', notificationId);\n }\n },\n });\n }\n\n return result;\n };\n\n return {\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification {\n const { subject, body } = extractSubjectAndBody(renderedItem.renderedContent, renderedItem.channel);\n\n return {\n id: renderedItem.notificationId,\n subject: subject || 'Notification',\n body: body || '',\n isRead: renderedItem.read,\n isArchived: renderedItem.archived,\n timestamp: renderedItem.createdAt ? new Date(renderedItem.createdAt) : new Date(),\n tags: [],\n actions: mapActionsToNotificationActions(\n renderedItem.renderedContent?.actions || renderedItem.actions\n ),\n metadata: {\n channel: renderedItem.channel,\n renderedContent: renderedItem.renderedContent,\n },\n };\n },\n\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification {\n if (!validateWebSocketPayload(wsPayload)) {\n console.error('Invalid WebSocket payload structure, using fallback', wsPayload);\n const fallbackRenderedContent =\n wsPayload?.renderedContent && typeof wsPayload.renderedContent === 'object'\n ? wsPayload.renderedContent\n : {};\n const { subject, body } = extractSubjectAndBody(fallbackRenderedContent, wsPayload?.channel);\n return {\n id: wsPayload?.notificationId || `notification-${Date.now()}`,\n subject: subject || 'Notification',\n body: body || '',\n isRead: wsPayload?.read || false,\n isArchived: wsPayload?.archived || false,\n timestamp: wsPayload?.createdAt ? new Date(wsPayload.createdAt) : new Date(),\n tags: [],\n actions: [],\n metadata: {\n channel: wsPayload?.channel || 'in_app',\n renderedContent: fallbackRenderedContent,\n },\n };\n }\n\n const { subject, body } = extractSubjectAndBody(wsPayload.renderedContent, wsPayload.channel);\n\n return {\n id: wsPayload.notificationId,\n subject: subject || 'Notification',\n body: body || '',\n isRead: wsPayload.read || false,\n isArchived: wsPayload.archived || false,\n timestamp: wsPayload.createdAt ? new Date(wsPayload.createdAt) : new Date(),\n tags: [],\n actions: mapActionsToNotificationActions(\n wsPayload.renderedContent?.actions || wsPayload.actions, \n wsPayload.notificationId\n ),\n metadata: {\n channel: wsPayload.channel,\n renderedContent: wsPayload.renderedContent,\n },\n };\n },\n\n validateWebSocketPayload,\n };\n};\n"],"names":["useNotificationsClient","useLivePreferences","preferences","onPreferencesChange","onError","notificationClient","isSaving","setIsSaving","useState","error","setError","saveTimeoutRef","useRef","pendingUpdatesRef","updatePreference","useCallback","path","value","updatedPreferences","pathParts","current","i","sdkConfig","subscriberId","tenantId","environmentId","savePayload","sub","err","useEffect","validateWebSocketPayload","payload","field","mapSDKActionToWidgetAction","sdkAction","notificationId","onActionExecute","target","createNotificationMapper","extractSubjectAndBody","renderedContent","channel","subject","body","mapActionsToNotificationActions","actions","result","primaryAction","secondaryAction","renderedItem","wsPayload","fallbackRenderedContent"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const u=require("react"),D=()=>window.__notificationSDK?.client,_=({preferences:t,onPreferencesChange:f,onError:e})=>{const n=D(),[c,i]=u.useState(!1),[r,l]=u.useState(null),p=u.useRef(),g=u.useRef({}),S=u.useCallback((v,A)=>{try{l(null);const a={...t},o=v.split(".");let h=a;for(let s=0;s<o.length-1;s++)h[o[s]]===void 0&&(h[o[s]]={}),h=h[o[s]];h[o[o.length-1]]=A,f(a),g.current[v]=A,p.current&&clearTimeout(p.current),i(!0),p.current=setTimeout(async()=>{try{if(!n)throw new Error("Notification client not available");const s=window.__notificationSDK?.config;if(!s)throw new Error("SDK configuration not available");const{subscriberId:b,tenantId:E,environmentId:y}=s;if(!b||!E||!y)throw new Error("SubscriberId, TenantId or EnvironmentId not available in SDK configuration.");const m={emailEnabled:a.channels.email,pushEnabled:a.channels.push,inAppEnabled:a.channels.inApp,smsEnabled:a.channels.sms};a.subscriptions.length>0&&(m.categories={},a.subscriptions.forEach(d=>{m.categories[d.workflowId]={emailEnabled:d.channels.email,pushEnabled:d.channels.push,inAppEnabled:d.channels.inApp,smsEnabled:d.channels.sms}})),await n.preferences.update(E,b,m),g.current={},l(null)}catch(s){const b=s instanceof Error?s:new Error("Failed to save preferences");process.env.NODE_ENV,l(b),e?.(b)}finally{i(!1)}},500)}catch(a){const o=a instanceof Error?a:new Error("Failed to update preference");l(o),e?.(o),i(!1)}},[t,f,n,e]);return u.useEffect(()=>()=>{p.current&&clearTimeout(p.current)},[]),{updatePreference:S,isSaving:c,error:r}},j=t=>!(!t||typeof t!="object"||["notificationId","channel","renderedContent","read","archived"].filter(n=>!(n in t)).length>0||typeof t.channel!="string"||typeof t.read!="boolean"||typeof t.archived!="boolean"||typeof t.renderedContent!="object"||t.renderedContent===null),N=(t,f,e)=>({type:"custom",label:t.label,icon:void 0,handler:async()=>{try{if(t.url){const n=t.target||"_self";window.open(t.url,n)}t.markAsReadOnClick}catch(n){throw n}}}),R=()=>{const t=(e,n)=>{if(!e||typeof e!="object")return{subject:"",body:""};let c="",i="";return e.push?(c=e.push.title||"",i=e.push.body||""):e.email?(c=e.email.subject||"",i=e.email.html||e.email.text||""):e.in_app?(c=e.in_app.title||"",i=e.in_app.message||""):e.sms?(c="SMS",i=e.sms.message||""):n==="in_app"?(c=e.title||"",i=e.message||""):(c=e.title||e.subject||"",i=e.message||e.body||e.text||""),{subject:c,body:i}},f=(e,n,c)=>{if(!e)return[];const i=[];if(Array.isArray(e))return e.forEach(r=>{i.push(N(r,n||"",c))}),i;if(e.primary){const r=e.primary;i.push({type:"custom",label:r.label||"Primary Action",icon:void 0,handler:async l=>{r.url&&window.open(r.url,"_self")}})}if(e.secondary){const r=e.secondary;i.push({type:"custom",label:r.label||"Secondary Action",icon:void 0,handler:async l=>{r.url&&window.open(r.url,"_self")}})}return i};return{toWidgetNotification(e){const{subject:n,body:c}=t(e.renderedContent,e.channel);return{id:e.notificationId,subject:n||"Notification",body:c||"",isRead:e.read,isArchived:e.archived,timestamp:e.createdAt?new Date(e.createdAt):new Date,tags:[],actions:f(e.renderedContent?.actions||e.actions),metadata:{channel:e.channel,renderedContent:e.renderedContent}}},toWidgetNotificationFromWebSocket(e){if(!j(e)){const i=e?.renderedContent&&typeof e.renderedContent=="object"?e.renderedContent:{},{subject:r,body:l}=t(i,e?.channel);return{id:e?.notificationId||`notification-${Date.now()}`,subject:r||"Notification",body:l||"",isRead:e?.read||!1,isArchived:e?.archived||!1,timestamp:e?.createdAt?new Date(e.createdAt):new Date,tags:[],actions:[],metadata:{channel:e?.channel||"in_app",renderedContent:i}}}const{subject:n,body:c}=t(e.renderedContent,e.channel);return{id:e.notificationId,subject:n||"Notification",body:c||"",isRead:e.read||!1,isArchived:e.archived||!1,timestamp:e.createdAt?new Date(e.createdAt):new Date,tags:[],actions:f(e.renderedContent?.actions||e.actions,e.notificationId),metadata:{channel:e.channel,renderedContent:e.renderedContent}}},validateWebSocketPayload:j}};exports.createNotificationMapper=R;exports.useLivePreferences=_;
|
|
2
|
+
//# sourceMappingURL=hooks-kLhwdW29.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-kLhwdW29.cjs","sources":["../src/hooks/useLivePreferences.ts","../src/utils/notification-mapper.ts"],"sourcesContent":["import { useCallback, useRef, useState, useEffect } from 'react';\r\nimport { NotificationPreferences } from '../types/core';\r\n\r\nconst useNotificationsClient = () => {\r\n return (window as any).__notificationSDK?.client;\r\n};\r\n\r\nexport interface UseLivePreferencesProps {\r\n preferences: NotificationPreferences;\r\n onPreferencesChange: (preferences: NotificationPreferences) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport interface UseLivePreferencesResult {\r\n updatePreference: (path: string, value: any) => void;\r\n isSaving: boolean;\r\n error: Error | null;\r\n}\r\n\r\nexport const useLivePreferences = ({\r\n preferences,\r\n onPreferencesChange,\r\n onError,\r\n}: UseLivePreferencesProps): UseLivePreferencesResult => {\r\n const notificationClient = useNotificationsClient();\r\n const [isSaving, setIsSaving] = useState(false);\r\n const [error, setError] = useState<Error | null>(null);\r\n const saveTimeoutRef = useRef<NodeJS.Timeout>();\r\n const pendingUpdatesRef = useRef<{ [key: string]: any }>({});\r\n\r\n const updatePreference = useCallback(\r\n (path: string, value: any) => {\r\n try {\r\n setError(null);\r\n\r\n const updatedPreferences = { ...preferences };\r\n const pathParts = path.split('.');\r\n\r\n let current: any = updatedPreferences;\r\n for (let i = 0; i < pathParts.length - 1; i++) {\r\n if (current[pathParts[i]] === undefined) {\r\n current[pathParts[i]] = {};\r\n }\r\n current = current[pathParts[i]];\r\n }\r\n current[pathParts[pathParts.length - 1]] = value;\r\n\r\n onPreferencesChange(updatedPreferences);\r\n\r\n pendingUpdatesRef.current[path] = value;\r\n\r\n if (saveTimeoutRef.current) {\r\n clearTimeout(saveTimeoutRef.current);\r\n }\r\n\r\n setIsSaving(true);\r\n\r\n saveTimeoutRef.current = setTimeout(async () => {\r\n try {\r\n if (!notificationClient) {\r\n throw new Error('Notification client not available');\r\n }\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n\r\n if (!sdkConfig) {\r\n throw new Error('SDK configuration not available');\r\n }\r\n\r\n const { subscriberId, tenantId, environmentId } = sdkConfig;\r\n\r\n if (!subscriberId || !tenantId || !environmentId) {\r\n throw new Error('SubscriberId, TenantId or EnvironmentId not available in SDK configuration.');\r\n }\r\n\r\n const savePayload: any = {\r\n emailEnabled: updatedPreferences.channels.email,\r\n pushEnabled: updatedPreferences.channels.push,\r\n inAppEnabled: updatedPreferences.channels.inApp,\r\n smsEnabled: updatedPreferences.channels.sms,\r\n };\r\n\r\n if (updatedPreferences.subscriptions.length > 0) {\r\n savePayload.categories = {};\r\n updatedPreferences.subscriptions.forEach(sub => {\r\n savePayload.categories[sub.workflowId] = {\r\n emailEnabled: sub.channels.email,\r\n pushEnabled: sub.channels.push,\r\n inAppEnabled: sub.channels.inApp,\r\n smsEnabled: sub.channels.sms,\r\n };\r\n });\r\n }\r\n\r\n // NOTE: deliverySchedule removed as backend doesn't accept it (returns 400)\r\n // Quiet hours and weekdays management will be added when backend supports it\r\n\r\n await notificationClient.preferences.update(tenantId, subscriberId, savePayload);\r\n\r\n pendingUpdatesRef.current = {};\r\n setError(null);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to save preferences');\r\n\r\n if (process.env.NODE_ENV === 'development') {\r\n console.error('Failed to save preferences:', error);\r\n }\r\n\r\n setError(error);\r\n onError?.(error);\r\n\r\n } finally {\r\n setIsSaving(false);\r\n }\r\n }, 500);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to update preference');\r\n setError(error);\r\n onError?.(error);\r\n setIsSaving(false);\r\n }\r\n },\r\n [preferences, onPreferencesChange, notificationClient, onError]\r\n );\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (saveTimeoutRef.current) {\r\n clearTimeout(saveTimeoutRef.current);\r\n }\r\n };\r\n }, []);\r\n\r\n return {\r\n updatePreference,\r\n isSaving,\r\n error,\r\n };\r\n};","import type { RenderedNotificationItem, RenderedNotificationActionMap, NotificationAction as SDKNotificationAction } from '@edusight/notification-sdk';\nimport type { Notification, NotificationAction } from '../types/core';\n\nexport interface WebSocketNotificationReceivedPayload extends RenderedNotificationItem {}\n\nexport interface NotificationMapper {\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification;\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification;\n validateWebSocketPayload(payload: any): payload is WebSocketNotificationReceivedPayload;\n}\n\nconst validateWebSocketPayload = (payload: any): payload is WebSocketNotificationReceivedPayload => {\n if (!payload || typeof payload !== 'object') {\n console.warn('Invalid WebSocket payload: not an object', payload);\n return false;\n }\n\n const requiredFields = ['notificationId', 'channel', 'renderedContent', 'read', 'archived'];\n const missingFields = requiredFields.filter(field => !(field in payload));\n\n if (missingFields.length > 0) {\n console.warn('WebSocket payload missing required fields:', missingFields, payload);\n return false;\n }\n\n if (typeof payload.channel !== 'string') {\n console.warn('WebSocket payload channel is invalid', payload);\n return false;\n }\n\n if (typeof payload.read !== 'boolean' || typeof payload.archived !== 'boolean') {\n console.warn('WebSocket payload read/archived flags are invalid', payload);\n return false;\n }\n\n if (typeof payload.renderedContent !== 'object' || payload.renderedContent === null) {\n console.warn('WebSocket payload renderedContent is not an object', payload);\n return false;\n }\n\n return true;\n};\n\n\nconst mapSDKActionToWidgetAction = (\n sdkAction: SDKNotificationAction,\n notificationId: string,\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>\n): NotificationAction => {\n return {\n type: 'custom',\n label: sdkAction.label,\n icon: undefined,\n handler: async () => {\n try {\n if (onActionExecute) {\n await onActionExecute(sdkAction.id, notificationId);\n }\n\n if (sdkAction.url) {\n const target = sdkAction.target || '_self';\n window.open(sdkAction.url, target);\n }\n\n if (sdkAction.markAsReadOnClick) {\n // This will be handled by the widget's action handler\n }\n } catch (error) {\n console.error('Error executing action:', error);\n throw error;\n }\n },\n };\n};\n\nexport const createNotificationMapper = (): NotificationMapper => {\n const extractSubjectAndBody = (\n renderedContent: Record<string, any>,\n channel?: string\n ): { subject: string; body: string } => {\n if (!renderedContent || typeof renderedContent !== 'object') {\n return { subject: '', body: '' };\n }\n\n let subject = '';\n let body = '';\n\n if (renderedContent.push) {\n subject = renderedContent.push.title || '';\n body = renderedContent.push.body || '';\n } else if (renderedContent.email) {\n subject = renderedContent.email.subject || '';\n body = renderedContent.email.html || renderedContent.email.text || '';\n } else if (renderedContent.in_app) {\n subject = renderedContent.in_app.title || '';\n body = renderedContent.in_app.message || '';\n } else if (renderedContent.sms) {\n subject = 'SMS';\n body = renderedContent.sms.message || '';\n } else if (channel === 'in_app') {\n subject = renderedContent.title || '';\n body = renderedContent.message || '';\n } else {\n subject = renderedContent.title || renderedContent.subject || '';\n body = renderedContent.message || renderedContent.body || renderedContent.text || '';\n }\n\n return { subject, body };\n };\n\n const mapActionsToNotificationActions = (\n actions?: RenderedNotificationActionMap | SDKNotificationAction[],\n notificationId?: string,\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>\n ): NotificationAction[] => {\n if (!actions) return [];\n\n const result: NotificationAction[] = [];\n\n if (Array.isArray(actions)) {\n actions.forEach((sdkAction) => {\n result.push(mapSDKActionToWidgetAction(sdkAction, notificationId || '', onActionExecute));\n });\n return result;\n }\n\n if (actions.primary) {\n const primaryAction = actions.primary;\n result.push({\n type: 'custom',\n label: primaryAction.label || 'Primary Action',\n icon: undefined,\n handler: async (notificationId: string) => {\n if (primaryAction.url) {\n window.open(primaryAction.url, '_self');\n }\n if (onActionExecute) {\n await onActionExecute('primary', notificationId);\n }\n },\n });\n }\n\n if (actions.secondary) {\n const secondaryAction = actions.secondary;\n result.push({\n type: 'custom',\n label: secondaryAction.label || 'Secondary Action',\n icon: undefined,\n handler: async (notificationId: string) => {\n if (secondaryAction.url) {\n window.open(secondaryAction.url, '_self');\n }\n if (onActionExecute) {\n await onActionExecute('secondary', notificationId);\n }\n },\n });\n }\n\n return result;\n };\n\n return {\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification {\n const { subject, body } = extractSubjectAndBody(renderedItem.renderedContent, renderedItem.channel);\n\n return {\n id: renderedItem.notificationId,\n subject: subject || 'Notification',\n body: body || '',\n isRead: renderedItem.read,\n isArchived: renderedItem.archived,\n timestamp: renderedItem.createdAt ? new Date(renderedItem.createdAt) : new Date(),\n tags: [],\n actions: mapActionsToNotificationActions(\n renderedItem.renderedContent?.actions || renderedItem.actions\n ),\n metadata: {\n channel: renderedItem.channel,\n renderedContent: renderedItem.renderedContent,\n },\n };\n },\n\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification {\n if (!validateWebSocketPayload(wsPayload)) {\n console.error('Invalid WebSocket payload structure, using fallback', wsPayload);\n const fallbackRenderedContent =\n wsPayload?.renderedContent && typeof wsPayload.renderedContent === 'object'\n ? wsPayload.renderedContent\n : {};\n const { subject, body } = extractSubjectAndBody(fallbackRenderedContent, wsPayload?.channel);\n return {\n id: wsPayload?.notificationId || `notification-${Date.now()}`,\n subject: subject || 'Notification',\n body: body || '',\n isRead: wsPayload?.read || false,\n isArchived: wsPayload?.archived || false,\n timestamp: wsPayload?.createdAt ? new Date(wsPayload.createdAt) : new Date(),\n tags: [],\n actions: [],\n metadata: {\n channel: wsPayload?.channel || 'in_app',\n renderedContent: fallbackRenderedContent,\n },\n };\n }\n\n const { subject, body } = extractSubjectAndBody(wsPayload.renderedContent, wsPayload.channel);\n\n return {\n id: wsPayload.notificationId,\n subject: subject || 'Notification',\n body: body || '',\n isRead: wsPayload.read || false,\n isArchived: wsPayload.archived || false,\n timestamp: wsPayload.createdAt ? new Date(wsPayload.createdAt) : new Date(),\n tags: [],\n actions: mapActionsToNotificationActions(\n wsPayload.renderedContent?.actions || wsPayload.actions, \n wsPayload.notificationId\n ),\n metadata: {\n channel: wsPayload.channel,\n renderedContent: wsPayload.renderedContent,\n },\n };\n },\n\n validateWebSocketPayload,\n };\n};\n"],"names":["useNotificationsClient","useLivePreferences","preferences","onPreferencesChange","onError","notificationClient","isSaving","setIsSaving","useState","error","setError","saveTimeoutRef","useRef","pendingUpdatesRef","updatePreference","useCallback","path","value","updatedPreferences","pathParts","current","i","sdkConfig","subscriberId","tenantId","environmentId","savePayload","sub","err","useEffect","validateWebSocketPayload","payload","field","mapSDKActionToWidgetAction","sdkAction","notificationId","onActionExecute","target","createNotificationMapper","extractSubjectAndBody","renderedContent","channel","subject","body","mapActionsToNotificationActions","actions","result","primaryAction","secondaryAction","renderedItem","wsPayload","fallbackRenderedContent"],"mappings":"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"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),i=require("react"),F=require("socket.io-client"),U=require("@edusight/notification-sdk"),E=require("./components-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),i=require("react"),F=require("socket.io-client"),U=require("@edusight/notification-sdk"),E=require("./components-KafszaqK.cjs"),v=require("./hooks-kLhwdW29.cjs"),B=({error:t,onRetry:r})=>s.jsxs("div",{className:"p-4 bg-[var(--widget-error)]/10 border border-[var(--widget-error)]/20 rounded-lg",role:"alert","data-testid":"error-boundary-fallback",children:[s.jsxs("div",{className:"flex items-center mb-2",children:[s.jsx(E.MdError,{className:"w-6 h-6 text-[var(--widget-error)] mr-2","aria-hidden":"true"}),s.jsx("h3",{className:"text-sm font-medium text-[var(--widget-error)]",children:"Something went wrong"})]}),s.jsx("p",{className:"text-sm mb-3 text-[var(--widget-error)]/80",children:"The notification widget encountered an error and couldn't load properly."}),process.env.NODE_ENV==="development"&&t&&s.jsxs("details",{className:"mb-3",children:[s.jsx("summary",{className:"text-xs cursor-pointer text-[var(--widget-error)] hover:text-[var(--widget-error)]/80 transition-colors",children:"Error details (development only)"}),s.jsxs("pre",{className:"mt-2 text-xs bg-[var(--widget-error)]/5 p-2 rounded overflow-auto max-h-32 text-[var(--widget-error)]",children:[t.message,t.stack&&`
|
|
2
2
|
|
|
3
3
|
${t.stack}`]})]}),s.jsxs("button",{type:"button",className:"inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-[var(--widget-error)] bg-[var(--widget-error)]/10 hover:bg-[var(--widget-error)]/20 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--widget-error)] transition-colors",onClick:r,"data-testid":"error-retry-button",children:[s.jsx(E.MdRefresh,{className:"mr-1 w-4 h-4","aria-hidden":"true"}),"Try again"]})]});class A extends i.Component{constructor(r){super(r),this.handleRetry=()=>{this.setState({hasError:!1,error:null,errorInfo:null})},this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(r){return{hasError:!0,error:r}}componentDidCatch(r,u){this.setState({errorInfo:u}),this.props.onError&&this.props.onError(r,u)}render(){return this.state.hasError?s.jsx(B,{error:this.state.error,onRetry:this.handleRetry}):this.props.children}}const L=()=>window.__notificationSDK?.client,M=({onPreferencesLoaded:t,onError:r})=>{const u=L(),[w,c]=i.useState(!0),[o,n]=i.useState(null),[l,f]=i.useState(null),m=i.useCallback(async()=>{try{if(c(!0),n(null),!u)throw new Error("Notification client not available");const p=window.__notificationSDK?.config;if(!p)throw new Error("SDK configuration not available");const{subscriberId:S,tenantId:T,environmentId:b}=p;if(!S||!T||!b)throw new Error("SubscriberId, TenantId or EnvironmentId not available in config");const y=await u.preferences.get(T,S,b),k={channels:{email:y.emailEnabled??!0,push:y.pushEnabled??!0,sms:y.smsEnabled??!1,inApp:y.inAppEnabled??!0},subscriptions:[],deliverySchedule:{timezone:"UTC",quietHours:{start:y.quietHoursStart??"22:00",end:y.quietHoursEnd??"08:00"},weekdays:[!0,!0,!0,!0,!0,!1,!1]}};y.categories&&Object.entries(y.categories).forEach(([N,C])=>{k.subscriptions.push({workflowId:N,name:N,enabled:!0,channels:{email:C.emailEnabled??!0,push:C.pushEnabled??!0,sms:C.smsEnabled??!1,inApp:C.inAppEnabled??!0}})}),f(k),t(k)}catch(p){const S=p instanceof Error?p:new Error("Failed to load preferences");p?.response?.status===404||p?.status===404||(n(S),r?.(S));const b={channels:{email:!0,push:!0,sms:!1,inApp:!0},subscriptions:[],deliverySchedule:{timezone:"UTC",quietHours:{start:"22:00",end:"08:00"},weekdays:[!0,!0,!0,!0,!0,!1,!1]}};f(b),t(b)}finally{c(!1)}},[u,t,r]);return i.useEffect(()=>{u&&m()},[u,m]),{isLoading:w,error:o,preferences:l}},q=()=>window.__notificationSDK?.client,V=()=>{const t=q(),[r,u]=i.useState([]),[w,c]=i.useState(!0),[o,n]=i.useState(null),l=i.useCallback(async()=>{try{if(c(!0),n(null),!t)throw new Error("Notification client not available");const f=window.__notificationSDK?.config;if(!f)throw new Error("SDK configuration not available");const{tenantId:m,environmentId:p}=f;if(!m||!p)throw new Error("TenantId or EnvironmentId not available in config");const T=((await t.workflows.list({status:"active"},m,p))?.workflows||[]).map(b=>({workflowId:b.workflowId,name:b.name||b.workflowId,description:b.description}));u(T)}catch(f){const m=f instanceof Error?f:new Error("Failed to load workflows");n(m),u([])}finally{c(!1)}},[t]);return i.useEffect(()=>{t&&l()},[t,l]),{workflows:r,isLoading:w,error:o,refetch:l}},O=i.createContext(null),z=()=>{const t=i.useContext(O);if(!t)throw new Error("useSDK must be used within a NotificationWidget");return t},$={notifications:[],unreadCount:0,preferences:{channels:{email:!0,push:!0,sms:!1,inApp:!0},subscriptions:[],deliverySchedule:{timezone:"UTC",quietHours:{start:"22:00",end:"08:00"},weekdays:[!0,!0,!0,!0,!0,!1,!1]}},ui:{isOpen:!1,currentView:"notifications",selectedNotifications:[],isLoading:!1,error:null},websocket:{connected:!1,reconnecting:!1}},H=({config:t,children:r})=>{const[u,w]=i.useState({client:null,isInitialized:!1,error:null});return i.useEffect(()=>{let c=!0;return(async()=>{try{const n=window.__notificationSDK;if(n?.client&&JSON.stringify(n.config)===JSON.stringify(t)){c&&w({client:n.client,isInitialized:!0,error:null});return}const l=new U.NotificationClient({apiUrl:t.baseUrl,apiKey:t.apiKey,tenantId:t.tenantId,environmentId:t.environmentId});window.__notificationSDK={client:l,config:t},c&&w({client:l,isInitialized:!0,error:null})}catch(n){c&&w({client:null,isInitialized:!1,error:n})}})(),()=>{c=!1}},[t]),s.jsx(O.Provider,{value:u,children:r})},J=(t,r)=>{switch(r.type){case"SET_NOTIFICATIONS":return{...t,notifications:r.payload,unreadCount:r.payload.filter(o=>!o.isRead).length};case"ADD_NOTIFICATION":const u=[r.payload,...t.notifications];return{...t,notifications:u,unreadCount:u.filter(o=>!o.isRead).length};case"UPDATE_NOTIFICATION":const w=t.notifications.map(o=>o.id===r.payload.id?{...o,...r.payload.updates}:o);return{...t,notifications:w,unreadCount:w.filter(o=>!o.isRead).length};case"DELETE_NOTIFICATION":const c=t.notifications.filter(o=>o.id!==r.payload);return{...t,notifications:c,unreadCount:c.filter(o=>!o.isRead).length};case"SET_PREFERENCES":return{...t,preferences:r.payload};case"SET_UI_STATE":return{...t,ui:{...t.ui,...r.payload}};case"SET_WEBSOCKET_STATE":return{...t,websocket:{...t.websocket,...r.payload}};default:return t}},G=({position:t="right",size:r="medium",theme:u="light",className:w="",onError:c})=>{const[o,n]=i.useReducer(J,$),{client:l,isInitialized:f,error:m}=z(),p=i.useRef(null),S=i.useCallback(e=>{n({type:"SET_PREFERENCES",payload:e})},[]),T=i.useCallback(e=>{c&&c(e)},[c]),{error:b}=M({onPreferencesLoaded:S,onError:T}),{workflows:y,isLoading:k}=V(),{updatePreference:N,isSaving:C,error:x}=v.useLivePreferences({preferences:o.preferences,onPreferencesChange:S,onError:T});i.useEffect(()=>{if(!k&&y.length>0){const e=y.map(a=>o.preferences.subscriptions.find(g=>g.workflowId===a.workflowId)||{workflowId:a.workflowId,name:a.name,enabled:!0,channels:{email:!0,push:!0,sms:!1,inApp:!0}});JSON.stringify(e)!==JSON.stringify(o.preferences.subscriptions)&&n({type:"SET_PREFERENCES",payload:{...o.preferences,subscriptions:e}})}},[y,k,o.preferences]);const _=i.useCallback(e=>{try{const a=v.createNotificationMapper();switch(e.type){case"notification_received":{const d=e.data;if(!a.validateWebSocketPayload(d))break;const g=a.toWidgetNotificationFromWebSocket(d);n({type:"ADD_NOTIFICATION",payload:g});break}case"notification_updated":n({type:"UPDATE_NOTIFICATION",payload:{id:e.data.id||e.data.notificationId,updates:e.data}});break;case"notification_deleted":n({type:"DELETE_NOTIFICATION",payload:e.data.id||e.data.notificationId});break;case"preferences_updated":n({type:"SET_PREFERENCES",payload:e.data});break;default:}}catch{}},[]),D=i.useCallback(async()=>{if(!(!l||!f||p.current))try{n({type:"SET_WEBSOCKET_STATE",payload:{reconnecting:!0}});const e=window.__notificationSDK?.config;if(!e)throw new Error("SDK configuration not available for WebSocket connection");const g=`${l.getApiHost()}/v1/notifications`,h=F.io(g,{query:{tenantId:e.tenantId,subscriberId:e.subscriberId,environmentId:e.environmentId},transports:["websocket"],autoConnect:!1,reconnection:!0,reconnectionAttempts:10,reconnectionDelay:1e3,reconnectionDelayMax:5e3});p.current=h,h.on("notification",I=>{_({type:"notification_received",data:I})}),h.on("connect",()=>{n({type:"SET_WEBSOCKET_STATE",payload:{connected:!0,reconnecting:!1}})}),h.on("disconnect",I=>{n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}})}),h.on("reconnect_attempt",I=>{n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!0}})}),h.on("connect_error",I=>{n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}}),c&&c(I)}),h.connect()}catch(e){n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}}),c&&c(e)}},[l,f,_,c]),K=i.useCallback(()=>{if(p.current)try{p.current.disconnect&&p.current.disconnect(),p.current=null,n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}})}catch{}},[]),j=i.useCallback(()=>{n({type:"SET_UI_STATE",payload:{isOpen:!o.ui.isOpen}})},[o.ui.isOpen]),W=i.useCallback(()=>{n({type:"SET_UI_STATE",payload:{isOpen:!1}})},[]),R=i.useCallback(e=>{n({type:"SET_UI_STATE",payload:{currentView:e}})},[]),P=i.useCallback(async(e,a)=>{if(!l||!f)return;const d=window.__notificationSDK?.config;if(d){if(!e)throw new Error("notificationId is required");try{switch(a.type){case"mark_read":await l.inbox.markAsRead(e,d.tenantId,d.environmentId,d.subscriberId);break;case"mark_unread":await l.inbox.markAsUnread(e,d.tenantId,d.environmentId,d.subscriberId);break;case"archive":await l.inbox.archive(e,d.tenantId,d.environmentId,d.subscriberId);break;case"delete":await l.inbox.delete(e,d.tenantId,d.environmentId,d.subscriberId);break;default:a.handler&&await a.handler(e);break}switch(a.type){case"mark_read":n({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isRead:!0}}});break;case"mark_unread":n({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isRead:!1}}});break;case"archive":n({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isArchived:!0}}});break;case"delete":n({type:"DELETE_NOTIFICATION",payload:e});break}}catch(g){c&&c(g)}}},[l]);return i.useEffect(()=>{if(!l||!f)return;(async()=>{try{n({type:"SET_UI_STATE",payload:{isLoading:!0}});const a=window.__notificationSDK?.config;if(!a)throw new Error("SDK configuration not available");const d=v.createNotificationMapper(),h=((await l.inbox.getRenderedNotifications({channel:"in_app",limit:50,offset:0},a.tenantId,a.environmentId,a.subscriberId))?.items||[]).map(I=>d.toWidgetNotification(I));n({type:"SET_NOTIFICATIONS",payload:h}),n({type:"SET_UI_STATE",payload:{isLoading:!1,error:null}})}catch(a){n({type:"SET_UI_STATE",payload:{isLoading:!1,error:a}}),c&&c(a)}})()},[l,f,c]),i.useEffect(()=>(l&&f&&D(),()=>{K()}),[l]),i.useEffect(()=>{if(!l||!f||o.websocket.connected)return;const e=setInterval(async()=>{try{const a=window.__notificationSDK?.config;if(!a)return;const d=v.createNotificationMapper(),h=((await l.inbox.getRenderedNotifications({channel:"in_app",limit:50,offset:0},a.tenantId,a.environmentId,a.subscriberId))?.items||[]).map(I=>d.toWidgetNotification(I));n({type:"SET_NOTIFICATIONS",payload:h})}catch{}},3e4);return()=>clearInterval(e)},[l,o.websocket.connected]),i.useEffect(()=>{const e=a=>{if(a.key==="notification_widget_sync"&&a.newValue)try{const d=JSON.parse(a.newValue);_(d)}catch{}};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)},[_]),i.useEffect(()=>{n({type:"SET_UI_STATE",payload:{isLoading:C}})},[C]),i.useEffect(()=>{const e=m||x||b;e&&n({type:"SET_UI_STATE",payload:{error:e}})},[m,x,b]),!f&&!m?s.jsx("div",{className:`relative inline-block ${w}`,"data-widget-size":r||"small","data-theme":u,"data-testid":"notification-widget",children:s.jsx(E.ComponentErrorBoundary,{componentName:"BellComponent",children:s.jsx(E.BellComponent,{unreadCount:0,onClick:()=>{},size:r,disabled:!0})})}):m?s.jsx("div",{className:`relative inline-block ${w}`,"data-widget-size":r||"small","data-theme":u,"data-testid":"notification-widget",children:s.jsx(E.ComponentErrorBoundary,{componentName:"BellComponent",fallback:s.jsx(E.SDKConnectionFallback,{error:m.message,onRetry:()=>window.location.reload()}),children:s.jsx(E.BellComponent,{unreadCount:0,onClick:()=>{},size:r,disabled:!0})})}):s.jsxs("div",{className:`relative inline-block ${w}`,"data-widget-size":r||"small","data-theme":u,"data-testid":"notification-widget",children:[s.jsx(E.ComponentErrorBoundary,{componentName:"BellComponent",children:s.jsx(E.BellComponent,{unreadCount:o.unreadCount,onClick:j,size:r,disabled:o.ui.isLoading})}),s.jsx(E.ComponentErrorBoundary,{componentName:"InboxPopover",fallback:s.jsx(E.LoadingFallback,{message:"Unable to load notifications"}),children:s.jsx(E.InboxPopover,{isOpen:o.ui.isOpen,onClose:W,position:t,currentView:o.ui.currentView,onViewChange:R,notifications:o.notifications,onNotificationAction:P,preferences:o.preferences,onPreferenceChange:N,isPreferencesLoading:C})})]})},Q=({sdkConfig:t,...r})=>s.jsx(A,{onError:r.onError,children:s.jsx(H,{config:t,children:s.jsx(G,{...r})})}),X="3.0.0",Y="@edusight/notification-widget";exports.BellComponent=E.BellComponent;exports.InboxPopover=E.InboxPopover;exports.NotificationItem=E.NotificationItem;exports.PreferencesView=E.PreferencesView;exports.NotificationWidget=Q;exports.NotificationWidgetErrorBoundary=A;exports.VERSION=X;exports.WIDGET_NAME=Y;
|
|
4
4
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--widget-font-family, -apple-system),BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--widget-primary: #6366f1;--widget-primary-hover: #4f46e5;--widget-primary-light: #eef2ff;--widget-background: #ffffff;--widget-bg: var(--widget-background);--widget-bg-secondary: #f9fafb;--widget-bg-hover: #f3f4f6;--widget-hover: var(--widget-bg-hover);--widget-text: #111827;--widget-text-secondary: #6b7280;--widget-text-tertiary: #9ca3af;--widget-border: #e5e7eb;--widget-border-light: #f3f4f6;--widget-unread-bg: #eff6ff;--widget-unread-dot: #3b82f6;--widget-unread-badge-bg: #ef4444;--widget-success: #10b981;--widget-warning: #f59e0b;--widget-error: #ef4444;--widget-font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--widget-popover-width: 480px;--widget-popover-max-height: 600px;--widget-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .05);--widget-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--widget-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--widget-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1)}[data-theme=dark]{--widget-background: #1f2937;--widget-bg: var(--widget-background);--widget-bg-secondary: #111827;--widget-bg-hover: #374151;--widget-hover: var(--widget-bg-hover);--widget-text: #f9fafb;--widget-text-secondary: #d1d5db;--widget-text-tertiary: #9ca3af;--widget-border: #374151;--widget-border-light: #1f2937;--widget-primary: #818cf8;--widget-primary-hover: #a5b4fc;--widget-primary-light: rgba(99, 102, 241, .1);--widget-unread-bg: rgba(59, 130, 246, .1);--widget-unread-dot: #60a5fa;--widget-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .3);--widget-shadow: 0 4px 6px -1px rgb(0 0 0 / .3), 0 2px 4px -2px rgb(0 0 0 / .3);--widget-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .4), 0 4px 6px -4px rgb(0 0 0 / .4);--widget-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / .5), 0 8px 10px -6px rgb(0 0 0 / .5)}.notification-item{height:var(--widget-item-height, 80px);display:flex;align-items:flex-start;transition:background-color .2s ease-in-out;cursor:pointer}.notification-item:hover{background-color:var(--widget-hover, #f9fafb)}.notification-item.unread{background-color:var(--widget-unread-bg, #f0f4ff)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-16px}.-top-2{top:-16px}.left-0{left:0}.right-0{right:0}.top-full{top:100%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2 / span 2}.mx-auto{margin-left:auto;margin-right:auto}.mb-0\.5{margin-bottom:4px}.mb-2{margin-bottom:16px}.mb-3{margin-bottom:24px}.mb-4{margin-bottom:32px}.ml-1{margin-left:8px}.mr-1{margin-right:8px}.mr-2{margin-right:16px}.mt-1\.5{margin-top:12px}.mt-2{margin-top:16px}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:80px}.h-12{height:96px}.h-2{height:16px}.h-3{height:24px}.h-4{height:32px}.h-5{height:40px}.h-6{height:48px}.h-7{height:1.75rem}.h-8{height:64px}.h-\[16px\]{height:16px}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-\[var\(--widget-popover-max-height\,580px\)\]{max-height:var(--widget-popover-max-height,580px)}.min-h-\[20px\]{min-height:20px}.w-10{width:80px}.w-12{width:96px}.w-16{width:128px}.w-2{width:16px}.w-3\/4{width:75%}.w-4{width:32px}.w-5{width:40px}.w-5\/6{width:83.333333%}.w-6{width:48px}.w-7{width:1.75rem}.w-8{width:64px}.w-9{width:2.25rem}.w-\[16px\]{width:16px}.w-\[88px\]{width:88px}.w-\[var\(--widget-popover-width\,400px\)\]{width:var(--widget-popover-width,400px)}.w-full{width:100%}.min-w-0{min-width:0px}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.origin-top-left{transform-origin:top left}.origin-top-right{transform-origin:top right}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-4{--tw-translate-x: 32px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.grid-cols-\[auto_1fr_auto_auto\]{grid-template-columns:auto 1fr auto auto}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:8px}.gap-2{gap:16px}.gap-3{gap:24px}.gap-x-4{-moz-column-gap:32px;column-gap:32px}.gap-y-3{row-gap:24px}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(16px * var(--tw-space-x-reverse));margin-left:calc(16px * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(8px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(8px * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(16px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(16px * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border-light>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(243 244 246 / var(--tw-divide-opacity, 1))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:var(--widget-radius-card, 8px)}.rounded-2xl{border-radius:16px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:8px}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-t{border-top-width:1px}.border-\[var\(--widget-border\)\]{border-color:var(--widget-border)}.border-\[var\(--widget-primary\)\]{border-color:var(--widget-primary)}.border-blue-300{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity, 1))}.border-border{border-color:var(--widget-border, #e5e7eb)}.border-border-light{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-white{--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.border-t-blue-500{--tw-border-opacity: 1;border-top-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-t-transparent{border-top-color:transparent}.bg-\[var\(--widget-bg-secondary\)\]{background-color:var(--widget-bg-secondary)}.bg-\[var\(--widget-primary\)\]{background-color:var(--widget-primary)}.bg-\[var\(--widget-text\)\]{background-color:var(--widget-text)}.bg-\[var\(--widget-warning\)\]{background-color:var(--widget-warning)}.bg-black\/20{background-color:#0003}.bg-gray-300{--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-unread-indicator{background-color:var(--widget-unread-indicator, #2563eb)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-widget-background{background-color:var(--widget-background, #ffffff)}.bg-widget-hover{background-color:var(--widget-hover, #f9fafb)}.bg-widget-primary{background-color:var(--widget-primary, #2563eb)}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.from-widget-primary{--tw-gradient-from: var(--widget-primary, #2563eb) var(--tw-gradient-from-position);--tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:8px}.p-2{padding:16px}.p-3{padding:24px}.p-4{padding:32px}.px-1{padding-left:8px;padding-right:8px}.px-2{padding-left:16px;padding-right:16px}.px-3{padding-left:24px;padding-right:24px}.px-4{padding-left:32px;padding-right:32px}.py-1{padding-top:8px;padding-bottom:8px}.py-1\.5{padding-top:12px;padding-bottom:12px}.py-12{padding-top:96px;padding-bottom:96px}.py-2{padding-top:16px;padding-bottom:16px}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:24px;padding-bottom:24px}.py-8{padding-top:64px;padding-bottom:64px}.pb-1\.5{padding-bottom:12px}.pl-1{padding-left:8px}.pl-10{padding-left:80px}.pl-3{padding-left:24px}.pr-3{padding-right:24px}.pt-0\.5{padding-top:4px}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[10px\]{font-size:10px}.text-base{font-size:var(--widget-font-size-subject, 14px);line-height:20px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:var(--widget-font-size-body, 13px);line-height:18px}.text-xs{font-size:var(--widget-font-size-timestamp, 12px);line-height:16px}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.text-\[var\(--widget-error\)\]{color:var(--widget-error)}.text-\[var\(--widget-primary\)\]{color:var(--widget-primary)}.text-\[var\(--widget-success\)\]{color:var(--widget-success)}.text-\[var\(--widget-text\)\]{color:var(--widget-text)}.text-\[var\(--widget-text-secondary\)\]{color:var(--widget-text-secondary)}.text-\[var\(--widget-text-tertiary\)\]{color:var(--widget-text-tertiary)}.text-\[var\(--widget-warning\)\]{color:var(--widget-warning)}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-text-primary{color:var(--widget-text, #1f2937)}.text-text-secondary{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-text-tertiary{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-widget-primary{color:var(--widget-primary, #2563eb)}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-80{opacity:.8}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[var\(--widget-shadow-xl\)\]{--tw-shadow-color: var(--widget-shadow-xl);--tw-shadow: var(--tw-shadow-colored)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:ease-in-out;transition-duration:.2s}.transition-all{transition-property:all;transition-timing-function:ease-in-out;transition-duration:.2s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:ease-in-out;transition-duration:.2s}.transition-opacity{transition-property:opacity;transition-timing-function:ease-in-out;transition-duration:.2s}.transition-transform{transition-property:transform;transition-timing-function:ease-in-out;transition-duration:.2s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.widget-scrollbar{scrollbar-width:thin;scrollbar-color:var(--widget-border) transparent}.widget-scrollbar::-webkit-scrollbar{width:6px}.widget-scrollbar::-webkit-scrollbar-track{background:transparent}.widget-scrollbar::-webkit-scrollbar-thumb{background-color:var(--widget-border);border-radius:20px}.widget-scrollbar::-webkit-scrollbar-thumb:hover{background-color:var(--widget-text-tertiary)}.tab-inactive:hover{background-color:var(--widget-bg-hover);color:var(--widget-text)}.placeholder\:text-\[var\(--widget-text-tertiary\)\]::-moz-placeholder{color:var(--widget-text-tertiary)}.placeholder\:text-\[var\(--widget-text-tertiary\)\]::placeholder{color:var(--widget-text-tertiary)}.hover\:bg-\[var\(--widget-bg-hover\)\]:hover{background-color:var(--widget-bg-hover)}.hover\:bg-\[var\(--widget-primary-hover\)\]:hover{background-color:var(--widget-primary-hover)}.hover\:bg-\[var\(--widget-primary-light\)\]:hover{background-color:var(--widget-primary-light)}.hover\:bg-blue-50:hover{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-widget-hover:hover{background-color:var(--widget-hover, #f9fafb)}.hover\:text-\[var\(--widget-primary-hover\)\]:hover{color:var(--widget-primary-hover)}.hover\:text-\[var\(--widget-text\)\]:hover{color:var(--widget-text)}.hover\:text-text-primary:hover{color:var(--widget-text, #1f2937)}.focus\:border-transparent:focus{border-color:transparent}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-\[var\(--widget-error\)\]:focus{--tw-ring-color: var(--widget-error)}.focus\:ring-\[var\(--widget-primary\)\]:focus{--tw-ring-color: var(--widget-primary)}.focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1))}.focus\:ring-text-secondary:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(107 114 128 / var(--tw-ring-opacity, 1))}.focus\:ring-widget-primary:focus{--tw-ring-color: var(--widget-primary, #2563eb)}.focus\:ring-offset-0:focus{--tw-ring-offset-width: 0px}.focus\:ring-offset-1:focus{--tw-ring-offset-width: 1px}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-widget-hover:disabled{background-color:var(--widget-hover, #f9fafb)}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-70:disabled{opacity:.7}.dark\:border-gray-600:is([data-theme=dark] *){--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.dark\:border-gray-900:is([data-theme=dark] *){--tw-border-opacity: 1;border-color:rgb(17 24 39 / var(--tw-border-opacity, 1))}.dark\:border-t-blue-400:is([data-theme=dark] *){--tw-border-opacity: 1;border-top-color:rgb(96 165 250 / var(--tw-border-opacity, 1))}.dark\:bg-gray-600:is([data-theme=dark] *){--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}.dark\:text-gray-400:is([data-theme=dark] *){--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.dark\:hover\:bg-gray-800:hover:is([data-theme=dark] *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}@media not all and (min-width:640px){.max-sm\:fixed{position:fixed}.max-sm\:inset-x-4{left:32px;right:32px}.max-sm\:bottom-4{bottom:32px}.max-sm\:top-16{top:128px}.max-sm\:max-h-\[calc\(100vh-120px\)\]{max-height:calc(100vh - 120px)}.max-sm\:w-auto{width:auto}.max-sm\:max-w-none{max-width:none}}@media(min-width:768px){.md\:hidden{display:none}}
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--widget-font-family, -apple-system),BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--widget-primary: #6366f1;--widget-primary-hover: #4f46e5;--widget-primary-light: #eef2ff;--widget-background: #ffffff;--widget-bg: var(--widget-background);--widget-bg-secondary: #f9fafb;--widget-bg-hover: #f3f4f6;--widget-hover: var(--widget-bg-hover);--widget-text: #111827;--widget-text-secondary: #6b7280;--widget-text-tertiary: #9ca3af;--widget-border: #e5e7eb;--widget-border-light: #f3f4f6;--widget-unread-bg: #eff6ff;--widget-unread-dot: #3b82f6;--widget-unread-badge-bg: #ef4444;--widget-success: #10b981;--widget-warning: #f59e0b;--widget-error: #ef4444;--widget-font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--widget-popover-width: 480px;--widget-popover-max-height: 600px;--widget-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .05);--widget-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--widget-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--widget-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1)}[data-theme=dark]{--widget-background: #1f2937;--widget-bg: var(--widget-background);--widget-bg-secondary: #111827;--widget-bg-hover: #374151;--widget-hover: var(--widget-bg-hover);--widget-text: #f9fafb;--widget-text-secondary: #d1d5db;--widget-text-tertiary: #9ca3af;--widget-border: #374151;--widget-border-light: #1f2937;--widget-primary: #818cf8;--widget-primary-hover: #a5b4fc;--widget-primary-light: rgba(99, 102, 241, .1);--widget-unread-bg: rgba(59, 130, 246, .1);--widget-unread-dot: #60a5fa;--widget-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .3);--widget-shadow: 0 4px 6px -1px rgb(0 0 0 / .3), 0 2px 4px -2px rgb(0 0 0 / .3);--widget-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .4), 0 4px 6px -4px rgb(0 0 0 / .4);--widget-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / .5), 0 8px 10px -6px rgb(0 0 0 / .5)}.notification-item{height:var(--widget-item-height, 80px);display:flex;align-items:flex-start;transition:background-color .2s ease-in-out;cursor:pointer}.notification-item:hover{background-color:var(--widget-hover, #f9fafb)}.notification-item.unread{background-color:var(--widget-unread-bg, #f0f4ff)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-right-2{right:-16px}.-top-2{top:-16px}.left-0{left:0}.right-0{right:0}.top-full{top:100%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2 / span 2}.mx-auto{margin-left:auto;margin-right:auto}.mb-0\.5{margin-bottom:4px}.mb-2{margin-bottom:16px}.mb-3{margin-bottom:24px}.mb-4{margin-bottom:32px}.ml-1{margin-left:8px}.mr-1{margin-right:8px}.mr-2{margin-right:16px}.mt-1\.5{margin-top:12px}.mt-2{margin-top:16px}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:80px}.h-12{height:96px}.h-2{height:16px}.h-3{height:24px}.h-4{height:32px}.h-5{height:40px}.h-6{height:48px}.h-7{height:1.75rem}.h-8{height:64px}.h-\[16px\]{height:16px}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-\[var\(--widget-popover-max-height\,580px\)\]{max-height:var(--widget-popover-max-height,580px)}.min-h-\[20px\]{min-height:20px}.w-10{width:80px}.w-12{width:96px}.w-16{width:128px}.w-2{width:16px}.w-3\/4{width:75%}.w-4{width:32px}.w-5{width:40px}.w-5\/6{width:83.333333%}.w-6{width:48px}.w-7{width:1.75rem}.w-8{width:64px}.w-9{width:2.25rem}.w-\[16px\]{width:16px}.w-\[88px\]{width:88px}.w-\[var\(--widget-popover-width\,400px\)\]{width:var(--widget-popover-width,400px)}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[20rem\]{min-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.origin-top-left{transform-origin:top left}.origin-top-right{transform-origin:top right}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-4{--tw-translate-x: 32px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.grid-cols-\[auto_1fr_auto_auto\]{grid-template-columns:auto 1fr auto auto}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:8px}.gap-2{gap:16px}.gap-3{gap:24px}.gap-x-4{-moz-column-gap:32px;column-gap:32px}.gap-y-3{row-gap:24px}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(16px * var(--tw-space-x-reverse));margin-left:calc(16px * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(8px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(8px * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(16px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(16px * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border-light>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(243 244 246 / var(--tw-divide-opacity, 1))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:var(--widget-radius-card, 8px)}.rounded-2xl{border-radius:16px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:8px}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-t{border-top-width:1px}.border-\[var\(--widget-border\)\]{border-color:var(--widget-border)}.border-\[var\(--widget-primary\)\]{border-color:var(--widget-primary)}.border-blue-300{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity, 1))}.border-border{border-color:var(--widget-border, #e5e7eb)}.border-border-light{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-white{--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.border-t-blue-500{--tw-border-opacity: 1;border-top-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-t-transparent{border-top-color:transparent}.bg-\[var\(--widget-bg-secondary\)\]{background-color:var(--widget-bg-secondary)}.bg-\[var\(--widget-primary\)\]{background-color:var(--widget-primary)}.bg-\[var\(--widget-text\)\]{background-color:var(--widget-text)}.bg-\[var\(--widget-warning\)\]{background-color:var(--widget-warning)}.bg-black\/20{background-color:#0003}.bg-gray-300{--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-unread-indicator{background-color:var(--widget-unread-indicator, #2563eb)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-widget-background{background-color:var(--widget-background, #ffffff)}.bg-widget-hover{background-color:var(--widget-hover, #f9fafb)}.bg-widget-primary{background-color:var(--widget-primary, #2563eb)}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.from-widget-primary{--tw-gradient-from: var(--widget-primary, #2563eb) var(--tw-gradient-from-position);--tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:8px}.p-2{padding:16px}.p-3{padding:24px}.p-4{padding:32px}.px-1{padding-left:8px;padding-right:8px}.px-2{padding-left:16px;padding-right:16px}.px-3{padding-left:24px;padding-right:24px}.px-4{padding-left:32px;padding-right:32px}.py-1{padding-top:8px;padding-bottom:8px}.py-1\.5{padding-top:12px;padding-bottom:12px}.py-12{padding-top:96px;padding-bottom:96px}.py-2{padding-top:16px;padding-bottom:16px}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:24px;padding-bottom:24px}.py-8{padding-top:64px;padding-bottom:64px}.pb-1\.5{padding-bottom:12px}.pl-1{padding-left:8px}.pl-10{padding-left:80px}.pl-3{padding-left:24px}.pr-3{padding-right:24px}.pt-0\.5{padding-top:4px}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[10px\]{font-size:10px}.text-base{font-size:var(--widget-font-size-subject, 14px);line-height:20px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:var(--widget-font-size-body, 13px);line-height:18px}.text-xs{font-size:var(--widget-font-size-timestamp, 12px);line-height:16px}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.text-\[var\(--widget-error\)\]{color:var(--widget-error)}.text-\[var\(--widget-primary\)\]{color:var(--widget-primary)}.text-\[var\(--widget-success\)\]{color:var(--widget-success)}.text-\[var\(--widget-text\)\]{color:var(--widget-text)}.text-\[var\(--widget-text-secondary\)\]{color:var(--widget-text-secondary)}.text-\[var\(--widget-text-tertiary\)\]{color:var(--widget-text-tertiary)}.text-\[var\(--widget-warning\)\]{color:var(--widget-warning)}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-text-primary{color:var(--widget-text, #1f2937)}.text-text-secondary{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-text-tertiary{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-widget-primary{color:var(--widget-primary, #2563eb)}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-80{opacity:.8}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[var\(--widget-shadow-xl\)\]{--tw-shadow-color: var(--widget-shadow-xl);--tw-shadow: var(--tw-shadow-colored)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:ease-in-out;transition-duration:.2s}.transition-all{transition-property:all;transition-timing-function:ease-in-out;transition-duration:.2s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:ease-in-out;transition-duration:.2s}.transition-opacity{transition-property:opacity;transition-timing-function:ease-in-out;transition-duration:.2s}.transition-transform{transition-property:transform;transition-timing-function:ease-in-out;transition-duration:.2s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.widget-scrollbar{scrollbar-width:thin;scrollbar-color:var(--widget-border) transparent}.widget-scrollbar::-webkit-scrollbar{width:6px}.widget-scrollbar::-webkit-scrollbar-track{background:transparent}.widget-scrollbar::-webkit-scrollbar-thumb{background-color:var(--widget-border);border-radius:20px}.widget-scrollbar::-webkit-scrollbar-thumb:hover{background-color:var(--widget-text-tertiary)}.tab-inactive:hover{background-color:var(--widget-bg-hover);color:var(--widget-text)}.placeholder\:text-\[var\(--widget-text-tertiary\)\]::-moz-placeholder{color:var(--widget-text-tertiary)}.placeholder\:text-\[var\(--widget-text-tertiary\)\]::placeholder{color:var(--widget-text-tertiary)}.hover\:bg-\[var\(--widget-bg-hover\)\]:hover{background-color:var(--widget-bg-hover)}.hover\:bg-\[var\(--widget-primary-hover\)\]:hover{background-color:var(--widget-primary-hover)}.hover\:bg-\[var\(--widget-primary-light\)\]:hover{background-color:var(--widget-primary-light)}.hover\:bg-blue-50:hover{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-widget-hover:hover{background-color:var(--widget-hover, #f9fafb)}.hover\:text-\[var\(--widget-primary-hover\)\]:hover{color:var(--widget-primary-hover)}.hover\:text-\[var\(--widget-text\)\]:hover{color:var(--widget-text)}.hover\:text-text-primary:hover{color:var(--widget-text, #1f2937)}.focus\:border-transparent:focus{border-color:transparent}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-\[var\(--widget-error\)\]:focus{--tw-ring-color: var(--widget-error)}.focus\:ring-\[var\(--widget-primary\)\]:focus{--tw-ring-color: var(--widget-primary)}.focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1))}.focus\:ring-text-secondary:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(107 114 128 / var(--tw-ring-opacity, 1))}.focus\:ring-widget-primary:focus{--tw-ring-color: var(--widget-primary, #2563eb)}.focus\:ring-offset-0:focus{--tw-ring-offset-width: 0px}.focus\:ring-offset-1:focus{--tw-ring-offset-width: 1px}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-widget-hover:disabled{background-color:var(--widget-hover, #f9fafb)}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-70:disabled{opacity:.7}.dark\:border-gray-600:is([data-theme=dark] *){--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.dark\:border-gray-900:is([data-theme=dark] *){--tw-border-opacity: 1;border-color:rgb(17 24 39 / var(--tw-border-opacity, 1))}.dark\:border-t-blue-400:is([data-theme=dark] *){--tw-border-opacity: 1;border-top-color:rgb(96 165 250 / var(--tw-border-opacity, 1))}.dark\:bg-gray-600:is([data-theme=dark] *){--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}.dark\:text-gray-400:is([data-theme=dark] *){--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.dark\:hover\:bg-gray-800:hover:is([data-theme=dark] *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}@media not all and (min-width:640px){.max-sm\:fixed{position:fixed}.max-sm\:inset-x-4{left:32px;right:32px}.max-sm\:bottom-4{bottom:32px}.max-sm\:top-16{top:128px}.max-sm\:max-h-\[calc\(100vh-120px\)\]{max-height:calc(100vh - 120px)}.max-sm\:w-auto{width:auto}.max-sm\:max-w-none{max-width:none}}@media(min-width:768px){.md\:hidden{display:none}}
|
package/dist/index.esm.js
CHANGED
|
@@ -2,9 +2,9 @@ import { jsx as d, jsxs as k } from "react/jsx-runtime";
|
|
|
2
2
|
import M, { Component as V, useState as C, useCallback as y, useEffect as b, createContext as z, useReducer as q, useRef as $, useContext as H } from "react";
|
|
3
3
|
import { io as J } from "socket.io-client";
|
|
4
4
|
import { NotificationClient as j } from "@edusight/notification-sdk";
|
|
5
|
-
import { M as G, a as Q, C as O, B as D, S as X, I as Y, L as Z } from "./components-
|
|
6
|
-
import { N as Te, P as _e } from "./components-
|
|
7
|
-
import { u as ee, c as x } from "./hooks-
|
|
5
|
+
import { M as G, a as Q, C as O, B as D, S as X, I as Y, L as Z } from "./components-D8XxiFEB.js";
|
|
6
|
+
import { N as Te, P as _e } from "./components-D8XxiFEB.js";
|
|
7
|
+
import { u as ee, c as x } from "./hooks-BTG0z6yd.js";
|
|
8
8
|
const te = ({ error: t, onRetry: r }) => /* @__PURE__ */ k(
|
|
9
9
|
"div",
|
|
10
10
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edusight/notification-widget",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.32",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "React notification center widget for EduSight Notification Service, aligned with Novu's React UI and functionalities",
|
|
6
6
|
"main": "./dist/index.cjs.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"author": "EduSight",
|
|
59
59
|
"license": "MIT",
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@edusight/notification-sdk": "^1.0.
|
|
61
|
+
"@edusight/notification-sdk": "^1.0.30",
|
|
62
62
|
"@types/react-window": "^1.8.8",
|
|
63
63
|
"date-fns": "^2.30.0",
|
|
64
64
|
"react-icons": "^5.0.1",
|
package/dist/hooks-CggRWw6Q.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const f=require("react"),y=()=>window.__notificationSDK?.client,N=({preferences:t,onPreferencesChange:o,onError:e})=>{const n=y(),[c,i]=f.useState(!1),[u,l]=f.useState(null),p=f.useRef(),g=f.useRef({}),S=f.useCallback((v,E)=>{try{l(null);const r={...t},s=v.split(".");let h=r;for(let a=0;a<s.length-1;a++)h[s[a]]===void 0&&(h[s[a]]={}),h=h[s[a]];h[s[s.length-1]]=E,o(r),g.current[v]=E,p.current&&clearTimeout(p.current),i(!0),p.current=setTimeout(async()=>{try{if(!n)throw new Error("Notification client not available");const a=window.__notificationSDK?.config;if(!a)throw new Error("SDK configuration not available");const{subscriberId:b,tenantId:A,environmentId:D}=a;if(!b||!A||!D)throw new Error("SubscriberId, TenantId or EnvironmentId not available in SDK configuration.");const d={emailEnabled:r.channels.email,pushEnabled:r.channels.push,inAppEnabled:r.channels.inApp,smsEnabled:r.channels.sms};r.subscriptions.length>0&&(d.categories={},r.subscriptions.forEach(m=>{d.categories[m.workflowId]={emailEnabled:m.channels.email,pushEnabled:m.channels.push,inAppEnabled:m.channels.inApp,smsEnabled:m.channels.sms}})),await n.preferences.update(A,b,d),g.current={},l(null)}catch(a){const b=a instanceof Error?a:new Error("Failed to save preferences");process.env.NODE_ENV,l(b),e?.(b)}finally{i(!1)}},500)}catch(r){const s=r instanceof Error?r:new Error("Failed to update preference");l(s),e?.(s),i(!1)}},[t,o,n,e]);return f.useEffect(()=>()=>{p.current&&clearTimeout(p.current)},[]),{updatePreference:S,isSaving:c,error:u}},j=t=>!(!t||typeof t!="object"||["notificationId","channel","renderedContent","read","archived"].filter(n=>!(n in t)).length>0||typeof t.channel!="string"||typeof t.read!="boolean"||typeof t.archived!="boolean"||typeof t.renderedContent!="object"||t.renderedContent===null),_=(t,o,e)=>({type:"custom",label:t.label,icon:void 0,handler:async()=>{try{if(t.url){const n=t.target||"_self";window.open(t.url,n)}t.markAsReadOnClick}catch(n){throw n}}}),R=()=>{const t=(e,n)=>{if(!e||typeof e!="object")return{subject:"",body:""};let c="",i="";return e.push?(c=e.push.title||"",i=e.push.body||""):e.email?(c=e.email.subject||"",i=e.email.html||e.email.text||""):e.in_app?(c=e.in_app.title||"",i=e.in_app.message||""):e.sms?(c="SMS",i=e.sms.message||""):n==="in_app"?(c=e.title||"",i=e.message||""):(c=e.title||e.subject||"",i=e.message||e.body||e.text||""),{subject:c,body:i}},o=(e,n,c)=>{if(!e)return[];const i=[];return Array.isArray(e)?(e.forEach(u=>{i.push(_(u,n||"",c))}),i):(e.primary&&i.push({type:"custom",label:e.primary.label||"Primary Action",icon:void 0,handler:async()=>{}}),e.secondary&&i.push({type:"custom",label:e.secondary.label||"Secondary Action",icon:void 0,handler:async()=>{}}),i)};return{toWidgetNotification(e){const{subject:n,body:c}=t(e.renderedContent,e.channel);return{id:e.notificationId,subject:n||"Notification",body:c||"",isRead:e.read,isArchived:e.archived,timestamp:e.createdAt?new Date(e.createdAt):new Date,tags:[],actions:o(e.actions),metadata:{channel:e.channel,renderedContent:e.renderedContent}}},toWidgetNotificationFromWebSocket(e){if(!j(e)){const i=e?.renderedContent&&typeof e.renderedContent=="object"?e.renderedContent:{},{subject:u,body:l}=t(i,e?.channel);return{id:e?.notificationId||`notification-${Date.now()}`,subject:u||"Notification",body:l||"",isRead:e?.read||!1,isArchived:e?.archived||!1,timestamp:e?.createdAt?new Date(e.createdAt):new Date,tags:[],actions:[],metadata:{channel:e?.channel||"in_app",renderedContent:i}}}const{subject:n,body:c}=t(e.renderedContent,e.channel);return{id:e.notificationId,subject:n||"Notification",body:c||"",isRead:e.read||!1,isArchived:e.archived||!1,timestamp:e.createdAt?new Date(e.createdAt):new Date,tags:[],actions:o(e.actions,e.notificationId),metadata:{channel:e.channel,renderedContent:e.renderedContent}}},validateWebSocketPayload:j}};exports.createNotificationMapper=R;exports.useLivePreferences=N;
|
|
2
|
-
//# sourceMappingURL=hooks-CggRWw6Q.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-CggRWw6Q.cjs","sources":["../src/hooks/useLivePreferences.ts","../src/utils/notification-mapper.ts"],"sourcesContent":["import { useCallback, useRef, useState, useEffect } from 'react';\r\nimport { NotificationPreferences } from '../types/core';\r\n\r\nconst useNotificationsClient = () => {\r\n return (window as any).__notificationSDK?.client;\r\n};\r\n\r\nexport interface UseLivePreferencesProps {\r\n preferences: NotificationPreferences;\r\n onPreferencesChange: (preferences: NotificationPreferences) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport interface UseLivePreferencesResult {\r\n updatePreference: (path: string, value: any) => void;\r\n isSaving: boolean;\r\n error: Error | null;\r\n}\r\n\r\nexport const useLivePreferences = ({\r\n preferences,\r\n onPreferencesChange,\r\n onError,\r\n}: UseLivePreferencesProps): UseLivePreferencesResult => {\r\n const notificationClient = useNotificationsClient();\r\n const [isSaving, setIsSaving] = useState(false);\r\n const [error, setError] = useState<Error | null>(null);\r\n const saveTimeoutRef = useRef<NodeJS.Timeout>();\r\n const pendingUpdatesRef = useRef<{ [key: string]: any }>({});\r\n\r\n const updatePreference = useCallback(\r\n (path: string, value: any) => {\r\n try {\r\n setError(null);\r\n\r\n const updatedPreferences = { ...preferences };\r\n const pathParts = path.split('.');\r\n\r\n let current: any = updatedPreferences;\r\n for (let i = 0; i < pathParts.length - 1; i++) {\r\n if (current[pathParts[i]] === undefined) {\r\n current[pathParts[i]] = {};\r\n }\r\n current = current[pathParts[i]];\r\n }\r\n current[pathParts[pathParts.length - 1]] = value;\r\n\r\n onPreferencesChange(updatedPreferences);\r\n\r\n pendingUpdatesRef.current[path] = value;\r\n\r\n if (saveTimeoutRef.current) {\r\n clearTimeout(saveTimeoutRef.current);\r\n }\r\n\r\n setIsSaving(true);\r\n\r\n saveTimeoutRef.current = setTimeout(async () => {\r\n try {\r\n if (!notificationClient) {\r\n throw new Error('Notification client not available');\r\n }\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n\r\n if (!sdkConfig) {\r\n throw new Error('SDK configuration not available');\r\n }\r\n\r\n const { subscriberId, tenantId, environmentId } = sdkConfig;\r\n\r\n if (!subscriberId || !tenantId || !environmentId) {\r\n throw new Error('SubscriberId, TenantId or EnvironmentId not available in SDK configuration.');\r\n }\r\n\r\n const savePayload: any = {\r\n emailEnabled: updatedPreferences.channels.email,\r\n pushEnabled: updatedPreferences.channels.push,\r\n inAppEnabled: updatedPreferences.channels.inApp,\r\n smsEnabled: updatedPreferences.channels.sms,\r\n };\r\n\r\n if (updatedPreferences.subscriptions.length > 0) {\r\n savePayload.categories = {};\r\n updatedPreferences.subscriptions.forEach(sub => {\r\n savePayload.categories[sub.workflowId] = {\r\n emailEnabled: sub.channels.email,\r\n pushEnabled: sub.channels.push,\r\n inAppEnabled: sub.channels.inApp,\r\n smsEnabled: sub.channels.sms,\r\n };\r\n });\r\n }\r\n\r\n // NOTE: deliverySchedule removed as backend doesn't accept it (returns 400)\r\n // Quiet hours and weekdays management will be added when backend supports it\r\n\r\n await notificationClient.preferences.update(tenantId, subscriberId, savePayload);\r\n\r\n pendingUpdatesRef.current = {};\r\n setError(null);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to save preferences');\r\n\r\n if (process.env.NODE_ENV === 'development') {\r\n console.error('Failed to save preferences:', error);\r\n }\r\n\r\n setError(error);\r\n onError?.(error);\r\n\r\n } finally {\r\n setIsSaving(false);\r\n }\r\n }, 500);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to update preference');\r\n setError(error);\r\n onError?.(error);\r\n setIsSaving(false);\r\n }\r\n },\r\n [preferences, onPreferencesChange, notificationClient, onError]\r\n );\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (saveTimeoutRef.current) {\r\n clearTimeout(saveTimeoutRef.current);\r\n }\r\n };\r\n }, []);\r\n\r\n return {\r\n updatePreference,\r\n isSaving,\r\n error,\r\n };\r\n};","import type { RenderedNotificationItem, RenderedNotificationActionMap, NotificationAction as SDKNotificationAction } from '@edusight/notification-sdk';\r\nimport type { Notification, NotificationAction } from '../types/core';\r\n\r\nexport interface WebSocketNotificationReceivedPayload extends RenderedNotificationItem {}\r\n\r\nexport interface NotificationMapper {\r\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification;\r\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification;\r\n validateWebSocketPayload(payload: any): payload is WebSocketNotificationReceivedPayload;\r\n}\r\n\r\nconst validateWebSocketPayload = (payload: any): payload is WebSocketNotificationReceivedPayload => {\r\n if (!payload || typeof payload !== 'object') {\r\n console.warn('Invalid WebSocket payload: not an object', payload);\r\n return false;\r\n }\r\n\r\n const requiredFields = ['notificationId', 'channel', 'renderedContent', 'read', 'archived'];\r\n const missingFields = requiredFields.filter(field => !(field in payload));\r\n\r\n if (missingFields.length > 0) {\r\n console.warn('WebSocket payload missing required fields:', missingFields, payload);\r\n return false;\r\n }\r\n\r\n if (typeof payload.channel !== 'string') {\r\n console.warn('WebSocket payload channel is invalid', payload);\r\n return false;\r\n }\r\n\r\n if (typeof payload.read !== 'boolean' || typeof payload.archived !== 'boolean') {\r\n console.warn('WebSocket payload read/archived flags are invalid', payload);\r\n return false;\r\n }\r\n\r\n if (typeof payload.renderedContent !== 'object' || payload.renderedContent === null) {\r\n console.warn('WebSocket payload renderedContent is not an object', payload);\r\n return false;\r\n }\r\n\r\n return true;\r\n};\r\n\r\n\r\nconst mapSDKActionToWidgetAction = (\r\n sdkAction: SDKNotificationAction,\r\n notificationId: string,\r\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>\r\n): NotificationAction => {\r\n return {\r\n type: 'custom',\r\n label: sdkAction.label,\r\n icon: undefined,\r\n handler: async () => {\r\n try {\r\n if (onActionExecute) {\r\n await onActionExecute(sdkAction.id, notificationId);\r\n }\r\n\r\n if (sdkAction.url) {\r\n const target = sdkAction.target || '_self';\r\n window.open(sdkAction.url, target);\r\n }\r\n\r\n if (sdkAction.markAsReadOnClick) {\r\n // This will be handled by the widget's action handler\r\n }\r\n } catch (error) {\r\n console.error('Error executing action:', error);\r\n throw error;\r\n }\r\n },\r\n };\r\n};\r\n\r\nexport const createNotificationMapper = (): NotificationMapper => {\r\n const extractSubjectAndBody = (\r\n renderedContent: Record<string, any>,\r\n channel?: string\r\n ): { subject: string; body: string } => {\r\n if (!renderedContent || typeof renderedContent !== 'object') {\r\n return { subject: '', body: '' };\r\n }\r\n\r\n let subject = '';\r\n let body = '';\r\n\r\n if (renderedContent.push) {\r\n subject = renderedContent.push.title || '';\r\n body = renderedContent.push.body || '';\r\n } else if (renderedContent.email) {\r\n subject = renderedContent.email.subject || '';\r\n body = renderedContent.email.html || renderedContent.email.text || '';\r\n } else if (renderedContent.in_app) {\r\n subject = renderedContent.in_app.title || '';\r\n body = renderedContent.in_app.message || '';\r\n } else if (renderedContent.sms) {\r\n subject = 'SMS';\r\n body = renderedContent.sms.message || '';\r\n } else if (channel === 'in_app') {\r\n subject = renderedContent.title || '';\r\n body = renderedContent.message || '';\r\n } else {\r\n subject = renderedContent.title || renderedContent.subject || '';\r\n body = renderedContent.message || renderedContent.body || renderedContent.text || '';\r\n }\r\n\r\n return { subject, body };\r\n };\r\n\r\n const mapActionsToNotificationActions = (\r\n actions?: RenderedNotificationActionMap | SDKNotificationAction[],\r\n notificationId?: string,\r\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>\r\n ): NotificationAction[] => {\r\n if (!actions) return [];\r\n\r\n const result: NotificationAction[] = [];\r\n\r\n if (Array.isArray(actions)) {\r\n actions.forEach((sdkAction) => {\r\n result.push(mapSDKActionToWidgetAction(sdkAction, notificationId || '', onActionExecute));\r\n });\r\n return result;\r\n }\r\n\r\n if (actions.primary) {\r\n result.push({\r\n type: 'custom',\r\n label: actions.primary.label || 'Primary Action',\r\n icon: undefined,\r\n handler: async () => {\r\n },\r\n });\r\n }\r\n\r\n if (actions.secondary) {\r\n result.push({\r\n type: 'custom',\r\n label: actions.secondary.label || 'Secondary Action',\r\n icon: undefined,\r\n handler: async () => {\r\n },\r\n });\r\n }\r\n\r\n return result;\r\n };\r\n\r\n return {\r\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification {\r\n const { subject, body } = extractSubjectAndBody(renderedItem.renderedContent, renderedItem.channel);\r\n\r\n return {\r\n id: renderedItem.notificationId,\r\n subject: subject || 'Notification',\r\n body: body || '',\r\n isRead: renderedItem.read,\r\n isArchived: renderedItem.archived,\r\n timestamp: renderedItem.createdAt ? new Date(renderedItem.createdAt) : new Date(),\r\n tags: [],\r\n actions: mapActionsToNotificationActions(renderedItem.actions),\r\n metadata: {\r\n channel: renderedItem.channel,\r\n renderedContent: renderedItem.renderedContent,\r\n },\r\n };\r\n },\r\n\r\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification {\r\n if (!validateWebSocketPayload(wsPayload)) {\r\n console.error('Invalid WebSocket payload structure, using fallback', wsPayload);\r\n const fallbackRenderedContent =\r\n wsPayload?.renderedContent && typeof wsPayload.renderedContent === 'object'\r\n ? wsPayload.renderedContent\r\n : {};\r\n const { subject, body } = extractSubjectAndBody(fallbackRenderedContent, wsPayload?.channel);\r\n return {\r\n id: wsPayload?.notificationId || `notification-${Date.now()}`,\r\n subject: subject || 'Notification',\r\n body: body || '',\r\n isRead: wsPayload?.read || false,\r\n isArchived: wsPayload?.archived || false,\r\n timestamp: wsPayload?.createdAt ? new Date(wsPayload.createdAt) : new Date(),\r\n tags: [],\r\n actions: [],\r\n metadata: {\r\n channel: wsPayload?.channel || 'in_app',\r\n renderedContent: fallbackRenderedContent,\r\n },\r\n };\r\n }\r\n\r\n const { subject, body } = extractSubjectAndBody(wsPayload.renderedContent, wsPayload.channel);\r\n\r\n return {\r\n id: wsPayload.notificationId,\r\n subject: subject || 'Notification',\r\n body: body || '',\r\n isRead: wsPayload.read || false,\r\n isArchived: wsPayload.archived || false,\r\n timestamp: wsPayload.createdAt ? new Date(wsPayload.createdAt) : new Date(),\r\n tags: [],\r\n actions: mapActionsToNotificationActions(wsPayload.actions, wsPayload.notificationId),\r\n metadata: {\r\n channel: wsPayload.channel,\r\n renderedContent: wsPayload.renderedContent,\r\n },\r\n };\r\n },\r\n\r\n validateWebSocketPayload,\r\n };\r\n};\r\n"],"names":["useNotificationsClient","useLivePreferences","preferences","onPreferencesChange","onError","notificationClient","isSaving","setIsSaving","useState","error","setError","saveTimeoutRef","useRef","pendingUpdatesRef","updatePreference","useCallback","path","value","updatedPreferences","pathParts","current","i","sdkConfig","subscriberId","tenantId","environmentId","savePayload","sub","err","useEffect","validateWebSocketPayload","payload","field","mapSDKActionToWidgetAction","sdkAction","notificationId","onActionExecute","target","createNotificationMapper","extractSubjectAndBody","renderedContent","channel","subject","body","mapActionsToNotificationActions","actions","result","renderedItem","wsPayload","fallbackRenderedContent"],"mappings":"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"}
|