@edusight/notification-widget 1.0.28 → 1.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
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
@@ -0,0 +1 @@
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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"}
@@ -0,0 +1,159 @@
1
+ import { useState as A, useRef as j, useCallback as N, useEffect as _ } from "react";
2
+ const R = () => window.__notificationSDK?.client, I = ({
3
+ preferences: t,
4
+ onPreferencesChange: o,
5
+ onError: e
6
+ }) => {
7
+ const n = R(), [c, i] = A(!1), [f, l] = A(null), u = j(), d = j({}), D = N(
8
+ (g, v) => {
9
+ try {
10
+ l(null);
11
+ const r = { ...t }, s = g.split(".");
12
+ let p = r;
13
+ for (let a = 0; a < s.length - 1; a++)
14
+ p[s[a]] === void 0 && (p[s[a]] = {}), p = p[s[a]];
15
+ p[s[s.length - 1]] = v, o(r), d.current[g] = v, u.current && clearTimeout(u.current), i(!0), u.current = setTimeout(async () => {
16
+ try {
17
+ if (!n)
18
+ throw new Error("Notification client not available");
19
+ const a = window.__notificationSDK?.config;
20
+ if (!a)
21
+ throw new Error("SDK configuration not available");
22
+ const { subscriberId: h, tenantId: E, environmentId: y } = a;
23
+ if (!h || !E || !y)
24
+ throw new Error("SubscriberId, TenantId or EnvironmentId not available in SDK configuration.");
25
+ const m = {
26
+ emailEnabled: r.channels.email,
27
+ pushEnabled: r.channels.push,
28
+ inAppEnabled: r.channels.inApp,
29
+ smsEnabled: r.channels.sms
30
+ };
31
+ r.subscriptions.length > 0 && (m.categories = {}, r.subscriptions.forEach((b) => {
32
+ m.categories[b.workflowId] = {
33
+ emailEnabled: b.channels.email,
34
+ pushEnabled: b.channels.push,
35
+ inAppEnabled: b.channels.inApp,
36
+ smsEnabled: b.channels.sms
37
+ };
38
+ })), await n.preferences.update(E, h, m), d.current = {}, l(null);
39
+ } catch (a) {
40
+ const h = a instanceof Error ? a : new Error("Failed to save preferences");
41
+ process.env.NODE_ENV, l(h), e?.(h);
42
+ } finally {
43
+ i(!1);
44
+ }
45
+ }, 500);
46
+ } catch (r) {
47
+ const s = r instanceof Error ? r : new Error("Failed to update preference");
48
+ l(s), e?.(s), i(!1);
49
+ }
50
+ },
51
+ [t, o, n, e]
52
+ );
53
+ return _(() => () => {
54
+ u.current && clearTimeout(u.current);
55
+ }, []), {
56
+ updatePreference: D,
57
+ isSaving: c,
58
+ error: f
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), F = (t, o, e) => ({
61
+ type: "custom",
62
+ label: t.label,
63
+ icon: void 0,
64
+ handler: async () => {
65
+ try {
66
+ if (t.url) {
67
+ const n = t.target || "_self";
68
+ window.open(t.url, n);
69
+ }
70
+ t.markAsReadOnClick;
71
+ } catch (n) {
72
+ throw n;
73
+ }
74
+ }
75
+ }), K = () => {
76
+ const t = (e, n) => {
77
+ if (!e || typeof e != "object")
78
+ return { subject: "", body: "" };
79
+ let c = "", i = "";
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
+ }, o = (e, n, c) => {
82
+ if (!e) return [];
83
+ const i = [];
84
+ return Array.isArray(e) ? (e.forEach((f) => {
85
+ i.push(F(f, n || "", c));
86
+ }), i) : (e.primary && i.push({
87
+ type: "custom",
88
+ label: e.primary.label || "Primary Action",
89
+ icon: void 0,
90
+ handler: async () => {
91
+ }
92
+ }), e.secondary && i.push({
93
+ type: "custom",
94
+ label: e.secondary.label || "Secondary Action",
95
+ icon: void 0,
96
+ handler: async () => {
97
+ }
98
+ }), i);
99
+ };
100
+ return {
101
+ toWidgetNotification(e) {
102
+ const { subject: n, body: c } = t(e.renderedContent, e.channel);
103
+ return {
104
+ id: e.notificationId,
105
+ subject: n || "Notification",
106
+ body: c || "",
107
+ isRead: e.read,
108
+ isArchived: e.archived,
109
+ timestamp: e.createdAt ? new Date(e.createdAt) : /* @__PURE__ */ new Date(),
110
+ tags: [],
111
+ actions: o(e.actions),
112
+ metadata: {
113
+ channel: e.channel,
114
+ renderedContent: e.renderedContent
115
+ }
116
+ };
117
+ },
118
+ toWidgetNotificationFromWebSocket(e) {
119
+ if (!S(e)) {
120
+ const i = e?.renderedContent && typeof e.renderedContent == "object" ? e.renderedContent : {}, { subject: f, body: l } = t(i, e?.channel);
121
+ return {
122
+ id: e?.notificationId || `notification-${Date.now()}`,
123
+ subject: f || "Notification",
124
+ body: l || "",
125
+ isRead: e?.read || !1,
126
+ isArchived: e?.archived || !1,
127
+ timestamp: e?.createdAt ? new Date(e.createdAt) : /* @__PURE__ */ new Date(),
128
+ tags: [],
129
+ actions: [],
130
+ metadata: {
131
+ channel: e?.channel || "in_app",
132
+ renderedContent: i
133
+ }
134
+ };
135
+ }
136
+ const { subject: n, body: c } = t(e.renderedContent, e.channel);
137
+ return {
138
+ id: e.notificationId,
139
+ subject: n || "Notification",
140
+ body: c || "",
141
+ isRead: e.read || !1,
142
+ isArchived: e.archived || !1,
143
+ timestamp: e.createdAt ? new Date(e.createdAt) : /* @__PURE__ */ new Date(),
144
+ tags: [],
145
+ actions: o(e.actions, e.notificationId),
146
+ metadata: {
147
+ channel: e.channel,
148
+ renderedContent: e.renderedContent
149
+ }
150
+ };
151
+ },
152
+ validateWebSocketPayload: S
153
+ };
154
+ };
155
+ export {
156
+ K as c,
157
+ I as u
158
+ };
159
+ //# sourceMappingURL=hooks-Cv5k48VE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-Cv5k48VE.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';\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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"}
package/dist/index.cjs.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),s=require("react"),R=require("socket.io-client"),W=require("@edusight/notification-sdk"),f=require("./components-ytSNU0U3.cjs"),k=require("./hooks-CACL0Qzv.cjs"),F=({error:t,onRetry:r})=>o.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:[o.jsxs("div",{className:"flex items-center mb-2",children:[o.jsx(f.MdError,{className:"w-6 h-6 text-[var(--widget-error)] mr-2","aria-hidden":"true"}),o.jsx("h3",{className:"text-sm font-medium text-[var(--widget-error)]",children:"Something went wrong"})]}),o.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&&o.jsxs("details",{className:"mb-3",children:[o.jsx("summary",{className:"text-xs cursor-pointer text-[var(--widget-error)] hover:text-[var(--widget-error)]/80 transition-colors",children:"Error details (development only)"}),o.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&&`
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-B9Z6HsnI.cjs"),v=require("./hooks-CggRWw6Q.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
- ${t.stack}`]})]}),o.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:[o.jsx(f.MdRefresh,{className:"mr-1 w-4 h-4","aria-hidden":"true"}),"Try again"]})]});class v extends s.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?o.jsx(F,{error:this.state.error,onRetry:this.handleRetry}):this.props.children}}const U=()=>window.__notificationSDK?.client,B=({onPreferencesLoaded:t,onError:r})=>{const u=U(),[E,c]=s.useState(!0),[i,n]=s.useState(null),[d,m]=s.useState(null),S=s.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:g,tenantId:N,environmentId:I}=p;if(!g||!N||!I)throw new Error("SubscriberId, TenantId or EnvironmentId not available in config");const y=await u.preferences.get(N,g,I),w={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(([_,h])=>{w.subscriptions.push({workflowId:_,name:_,enabled:!0,channels:{email:h.emailEnabled??!0,push:h.pushEnabled??!0,sms:h.smsEnabled??!1,inApp:h.inAppEnabled??!0}})}),m(w),t(w)}catch(p){const g=p instanceof Error?p:new Error("Failed to load preferences");p?.response?.status===404||p?.status===404||(n(g),r?.(g));const I={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]}};m(I),t(I)}finally{c(!1)}},[u,t,r]);return s.useEffect(()=>{u&&S()},[u,S]),{isLoading:E,error:i,preferences:d}},x=s.createContext(null),L=()=>{const t=s.useContext(x);if(!t)throw new Error("useSDK must be used within a NotificationWidget");return t},M={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}},V=({config:t,children:r})=>{const[u,E]=s.useState({client:null,isInitialized:!1,error:null});return s.useEffect(()=>{let c=!0;return(async()=>{try{const n=window.__notificationSDK;if(n?.client&&JSON.stringify(n.config)===JSON.stringify(t)){c&&E({client:n.client,isInitialized:!0,error:null});return}const d=new W.NotificationClient({apiUrl:t.baseUrl,apiKey:t.apiKey,tenantId:t.tenantId,environmentId:t.environmentId});window.__notificationSDK={client:d,config:t},c&&E({client:d,isInitialized:!0,error:null})}catch(n){c&&E({client:null,isInitialized:!1,error:n})}})(),()=>{c=!1}},[t]),o.jsx(x.Provider,{value:u,children:r})},q=(t,r)=>{switch(r.type){case"SET_NOTIFICATIONS":return{...t,notifications:r.payload,unreadCount:r.payload.filter(i=>!i.isRead).length};case"ADD_NOTIFICATION":const u=[r.payload,...t.notifications];return{...t,notifications:u,unreadCount:u.filter(i=>!i.isRead).length};case"UPDATE_NOTIFICATION":const E=t.notifications.map(i=>i.id===r.payload.id?{...i,...r.payload.updates}:i);return{...t,notifications:E,unreadCount:E.filter(i=>!i.isRead).length};case"DELETE_NOTIFICATION":const c=t.notifications.filter(i=>i.id!==r.payload);return{...t,notifications:c,unreadCount:c.filter(i=>!i.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}},z=({position:t="right",size:r="medium",theme:u="light",className:E="",onError:c})=>{const[i,n]=s.useReducer(q,M),{client:d,isInitialized:m,error:S}=L(),p=s.useRef(null),g=s.useCallback(e=>{n({type:"SET_PREFERENCES",payload:e})},[]),N=s.useCallback(e=>{c&&c(e)},[c]),{error:I}=B({onPreferencesLoaded:g,onError:N}),{updatePreference:y,isSaving:w,error:_}=k.useLivePreferences({preferences:i.preferences,onPreferencesChange:g,onError:N}),h=s.useCallback(e=>{try{const a=k.createNotificationMapper();switch(e.type){case"notification_received":{const l=e.data;if(!a.validateWebSocketPayload(l))break;const C=a.toWidgetNotificationFromWebSocket(l);n({type:"ADD_NOTIFICATION",payload:C});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{}},[]),A=s.useCallback(async()=>{if(!(!d||!m||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 C=`${d.getApiHost()}/v1/notifications`,b=R.io(C,{query:{tenantId:e.tenantId,subscriberId:e.subscriberId,environmentId:e.environmentId},transports:["websocket"],autoConnect:!1,reconnection:!0,reconnectionAttempts:10,reconnectionDelay:1e3,reconnectionDelayMax:5e3});p.current=b,b.on("notification",T=>{h({type:"notification_received",data:T})}),b.on("connect",()=>{n({type:"SET_WEBSOCKET_STATE",payload:{connected:!0,reconnecting:!1}})}),b.on("disconnect",T=>{n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}})}),b.on("reconnect_attempt",T=>{n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!0}})}),b.on("connect_error",T=>{n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}}),c&&c(T)}),b.connect()}catch(e){n({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}}),c&&c(e)}},[d,m,h,c]),O=s.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{}},[]),D=s.useCallback(()=>{n({type:"SET_UI_STATE",payload:{isOpen:!i.ui.isOpen}})},[i.ui.isOpen]),j=s.useCallback(()=>{n({type:"SET_UI_STATE",payload:{isOpen:!1}})},[]),K=s.useCallback(e=>{n({type:"SET_UI_STATE",payload:{currentView:e}})},[]),P=s.useCallback(async(e,a)=>{if(!d||!m)return;const l=window.__notificationSDK?.config;if(l)try{switch(a.type){case"mark_read":await d.inbox.markAsRead(e,l.tenantId,l.environmentId,l.subscriberId);break;case"mark_unread":await d.inbox.markAsUnread(e,l.tenantId,l.environmentId,l.subscriberId);break;case"archive":await d.inbox.archive(e,l.tenantId,l.environmentId,l.subscriberId);break;case"delete":await d.inbox.delete(e,l.tenantId,l.environmentId,l.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(C){c&&c(C)}},[d]);return s.useEffect(()=>{if(!d||!m)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 l=k.createNotificationMapper(),b=((await d.inbox.getRenderedNotifications({channel:"in_app",limit:50,offset:0},a.tenantId,a.environmentId,a.subscriberId))?.items||[]).map(T=>l.toWidgetNotification(T));n({type:"SET_NOTIFICATIONS",payload:b}),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)}})()},[d,m,c]),s.useEffect(()=>(d&&m&&A(),()=>{O()}),[d]),s.useEffect(()=>{if(!d||!m||i.websocket.connected)return;const e=setInterval(async()=>{try{const a=window.__notificationSDK?.config;if(!a)return;const l=k.createNotificationMapper(),b=((await d.inbox.getRenderedNotifications({channel:"in_app",limit:50,offset:0},a.tenantId,a.environmentId,a.subscriberId))?.items||[]).map(T=>l.toWidgetNotification(T));n({type:"SET_NOTIFICATIONS",payload:b})}catch{}},3e4);return()=>clearInterval(e)},[d,i.websocket.connected]),s.useEffect(()=>{const e=a=>{if(a.key==="notification_widget_sync"&&a.newValue)try{const l=JSON.parse(a.newValue);h(l)}catch{}};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)},[h]),s.useEffect(()=>{n({type:"SET_UI_STATE",payload:{isLoading:w}})},[w]),s.useEffect(()=>{const e=S||_||I;e&&n({type:"SET_UI_STATE",payload:{error:e}})},[S,_,I]),!m&&!S?o.jsx("div",{className:`relative inline-block ${E}`,"data-widget-size":r||"small","data-theme":u,"data-testid":"notification-widget",children:o.jsx(f.ComponentErrorBoundary,{componentName:"BellComponent",children:o.jsx(f.BellComponent,{unreadCount:0,onClick:()=>{},size:r,disabled:!0})})}):S?o.jsx("div",{className:`relative inline-block ${E}`,"data-widget-size":r||"small","data-theme":u,"data-testid":"notification-widget",children:o.jsx(f.ComponentErrorBoundary,{componentName:"BellComponent",fallback:o.jsx(f.SDKConnectionFallback,{error:S.message,onRetry:()=>window.location.reload()}),children:o.jsx(f.BellComponent,{unreadCount:0,onClick:()=>{},size:r,disabled:!0})})}):o.jsxs("div",{className:`relative inline-block ${E}`,"data-widget-size":r||"small","data-theme":u,"data-testid":"notification-widget",children:[o.jsx(f.ComponentErrorBoundary,{componentName:"BellComponent",children:o.jsx(f.BellComponent,{unreadCount:i.unreadCount,onClick:D,size:r,disabled:i.ui.isLoading})}),o.jsx(f.ComponentErrorBoundary,{componentName:"InboxPopover",fallback:o.jsx(f.LoadingFallback,{message:"Unable to load notifications"}),children:o.jsx(f.InboxPopover,{isOpen:i.ui.isOpen,onClose:j,position:t,currentView:i.ui.currentView,onViewChange:K,notifications:i.notifications,onNotificationAction:P,preferences:i.preferences,onPreferenceChange:y,isPreferencesLoading:w})})]})},H=({sdkConfig:t,...r})=>o.jsx(v,{onError:r.onError,children:o.jsx(V,{config:t,children:o.jsx(z,{...r})})}),$="3.0.0",J="@edusight/notification-widget";exports.BellComponent=f.BellComponent;exports.InboxPopover=f.InboxPopover;exports.NotificationItem=f.NotificationItem;exports.PreferencesView=f.PreferencesView;exports.NotificationWidget=H;exports.NotificationWidgetErrorBoundary=v;exports.VERSION=$;exports.WIDGET_NAME=J;
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/components/ErrorBoundary.tsx","../src/hooks/usePreferencesSync.ts","../src/components/NotificationWidget.tsx","../src/index.ts"],"sourcesContent":["import React, { Component, ErrorInfo, ReactNode } from 'react';\r\nimport { MdError, MdRefresh } from 'react-icons/md';\r\nimport { ErrorBoundaryState } from '../types/core';\r\n\r\ninterface ErrorBoundaryProps {\r\n children: ReactNode;\r\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\r\n}\r\n\r\nconst ErrorFallback: React.FC<{\r\n error: Error | null;\r\n onRetry: () => void;\r\n}> = ({ error, onRetry }) => (\r\n <div\r\n className=\"p-4 bg-[var(--widget-error)]/10 border border-[var(--widget-error)]/20 rounded-lg\"\r\n role=\"alert\"\r\n data-testid=\"error-boundary-fallback\"\r\n >\r\n <div className=\"flex items-center mb-2\">\r\n <MdError\r\n className=\"w-6 h-6 text-[var(--widget-error)] mr-2\"\r\n aria-hidden=\"true\"\r\n />\r\n <h3\r\n className=\"text-sm font-medium text-[var(--widget-error)]\"\r\n >\r\n Something went wrong\r\n </h3>\r\n </div>\r\n\r\n <p\r\n className=\"text-sm mb-3 text-[var(--widget-error)]/80\"\r\n >\r\n The notification widget encountered an error and couldn't load properly.\r\n </p>\r\n\r\n {process.env.NODE_ENV === 'development' && error && (\r\n <details className=\"mb-3\">\r\n <summary\r\n className=\"text-xs cursor-pointer text-[var(--widget-error)] hover:text-[var(--widget-error)]/80 transition-colors\"\r\n >\r\n Error details (development only)\r\n </summary>\r\n <pre\r\n className=\"mt-2 text-xs bg-[var(--widget-error)]/5 p-2 rounded overflow-auto max-h-32 text-[var(--widget-error)]\"\r\n >\r\n {error.message}\r\n {error.stack && `\\n\\n${error.stack}`}\r\n </pre>\r\n </details>\r\n )}\r\n\r\n <button\r\n type=\"button\"\r\n 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\"\r\n onClick={onRetry}\r\n data-testid=\"error-retry-button\"\r\n >\r\n <MdRefresh\r\n className=\"mr-1 w-4 h-4\"\r\n aria-hidden=\"true\"\r\n />\r\n Try again\r\n </button>\r\n </div>\r\n);\r\n\r\nexport class NotificationWidgetErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\r\n constructor(props: ErrorBoundaryProps) {\r\n super(props);\r\n this.state = {\r\n hasError: false,\r\n error: null,\r\n errorInfo: null,\r\n };\r\n }\r\n\r\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\r\n return {\r\n hasError: true,\r\n error,\r\n };\r\n }\r\n\r\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\r\n this.setState({\r\n errorInfo,\r\n });\r\n\r\n console.error('NotificationWidget Error Boundary caught an error:', {\r\n message: error.message,\r\n stack: error.stack,\r\n componentStack: errorInfo.componentStack,\r\n timestamp: new Date().toISOString(),\r\n });\r\n\r\n if (this.props.onError) {\r\n this.props.onError(error, errorInfo);\r\n }\r\n }\r\n\r\n handleRetry = () => {\r\n this.setState({\r\n hasError: false,\r\n error: null,\r\n errorInfo: null,\r\n });\r\n };\r\n\r\n render() {\r\n if (this.state.hasError) {\r\n return (\r\n <ErrorFallback\r\n error={this.state.error}\r\n onRetry={this.handleRetry}\r\n />\r\n );\r\n }\r\n\r\n return this.props.children;\r\n }\r\n}\r\n\r\nexport const useErrorHandler = () => {\r\n return (error: Error, errorInfo?: ErrorInfo) => {\r\n console.error('Widget error:', {\r\n message: error.message,\r\n stack: error.stack,\r\n errorInfo,\r\n timestamp: new Date().toISOString(),\r\n });\r\n };\r\n};","import { useEffect, useState, useCallback } 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 UsePreferencesSyncProps {\r\n onPreferencesLoaded: (preferences: NotificationPreferences) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport interface UsePreferencesSyncResult {\r\n isLoading: boolean;\r\n error: Error | null;\r\n preferences: NotificationPreferences | null;\r\n}\r\n\r\nexport const usePreferencesSync = ({\r\n onPreferencesLoaded,\r\n onError,\r\n}: UsePreferencesSyncProps): UsePreferencesSyncResult => {\r\n const notificationClient = useNotificationsClient();\r\n const [isLoading, setIsLoading] = useState(true);\r\n const [error, setError] = useState<Error | null>(null);\r\n const [preferences, setPreferences] = useState<NotificationPreferences | null>(null);\r\n\r\n const loadPreferences = useCallback(async () => {\r\n try {\r\n setIsLoading(true);\r\n setError(null);\r\n\r\n if (!notificationClient) {\r\n throw new Error('Notification client not available');\r\n }\r\n\r\n const config = (window as any).__notificationSDK?.config;\r\n\r\n if (!config) {\r\n throw new Error('SDK configuration not available');\r\n }\r\n\r\n const { subscriberId, tenantId, environmentId } = config;\r\n\r\n if (!subscriberId || !tenantId || !environmentId) {\r\n throw new Error('SubscriberId, TenantId or EnvironmentId not available in config');\r\n }\r\n\r\n const servicePreferences = await notificationClient.preferences.get(\r\n tenantId,\r\n subscriberId,\r\n environmentId,\r\n );\r\n\r\n const mappedPreferences: NotificationPreferences = {\r\n channels: {\r\n email: servicePreferences.emailEnabled ?? true,\r\n push: servicePreferences.pushEnabled ?? true,\r\n sms: servicePreferences.smsEnabled ?? false,\r\n inApp: servicePreferences.inAppEnabled ?? true,\r\n },\r\n subscriptions: [],\r\n deliverySchedule: {\r\n timezone: 'UTC',\r\n quietHours: {\r\n start: servicePreferences.quietHoursStart ?? '22:00',\r\n end: servicePreferences.quietHoursEnd ?? '08:00',\r\n },\r\n weekdays: [true, true, true, true, true, false, false],\r\n },\r\n };\r\n\r\n if (servicePreferences.categories) {\r\n Object.entries(servicePreferences.categories).forEach(([workflowId, categoryPrefs]) => {\r\n mappedPreferences.subscriptions.push({\r\n workflowId,\r\n name: workflowId,\r\n enabled: true,\r\n channels: {\r\n email: (categoryPrefs as any).emailEnabled ?? true,\r\n push: (categoryPrefs as any).pushEnabled ?? true,\r\n sms: (categoryPrefs as any).smsEnabled ?? false,\r\n inApp: (categoryPrefs as any).inAppEnabled ?? true,\r\n },\r\n });\r\n });\r\n }\r\n\r\n setPreferences(mappedPreferences);\r\n onPreferencesLoaded(mappedPreferences);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to load preferences');\r\n\r\n // If 404, it means preferences don't exist yet for this user. \r\n // We'll use defaults and suppress the error callback.\r\n const isNotFound = (err as any)?.response?.status === 404 || (err as any)?.status === 404;\r\n\r\n if (!isNotFound) {\r\n setError(error);\r\n onError?.(error);\r\n } else {\r\n console.warn('Preferences not found for user (404), using defaults.');\r\n }\r\n\r\n const defaultPreferences: NotificationPreferences = {\r\n channels: {\r\n email: true,\r\n push: true,\r\n sms: false,\r\n inApp: true,\r\n },\r\n subscriptions: [],\r\n deliverySchedule: {\r\n timezone: 'UTC',\r\n quietHours: {\r\n start: '22:00',\r\n end: '08:00',\r\n },\r\n weekdays: [true, true, true, true, true, false, false],\r\n },\r\n };\r\n setPreferences(defaultPreferences);\r\n onPreferencesLoaded(defaultPreferences);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n }, [notificationClient, onPreferencesLoaded, onError]);\r\n\r\n useEffect(() => {\r\n if (notificationClient) {\r\n loadPreferences();\r\n }\r\n }, [notificationClient, loadPreferences]);\r\n\r\n return {\r\n isLoading,\r\n error,\r\n preferences,\r\n };\r\n};\r\n","\r\nimport React, { useReducer, useEffect, useCallback, createContext, useContext, useRef } from 'react';\r\nimport { io as ioClient } from 'socket.io-client';\r\nimport { NotificationClient } from '@edusight/notification-sdk';\r\nimport { NotificationWidgetProps, WidgetState, WidgetAction, SDKConfiguration } from '../types/core';\r\nimport { BellComponent } from './BellComponent';\r\nimport { InboxPopover } from './InboxPopover';\r\nimport { NotificationWidgetErrorBoundary } from './ErrorBoundary';\r\nimport { ComponentErrorBoundary } from './ComponentErrorBoundary';\r\nimport { SDKConnectionFallback, LoadingFallback } from './FallbackComponents';\r\nimport { useLivePreferences } from '../hooks/useLivePreferences';\r\nimport { usePreferencesSync } from '../hooks/usePreferencesSync';\r\nimport { createNotificationMapper } from '../utils/notification-mapper';\r\n\r\ninterface SDKContextType {\r\n client: any;\r\n isInitialized: boolean;\r\n error: Error | null;\r\n}\r\n\r\nconst SDKContext = createContext<SDKContextType | null>(null);\r\n\r\nexport const useSDK = () => {\r\n const context = useContext(SDKContext);\r\n if (!context) {\r\n throw new Error('useSDK must be used within a NotificationWidget');\r\n }\r\n return context;\r\n};\r\n\r\nconst initialState: WidgetState = {\r\n notifications: [],\r\n unreadCount: 0,\r\n preferences: {\r\n channels: {\r\n email: true,\r\n push: true,\r\n sms: false,\r\n inApp: true,\r\n },\r\n subscriptions: [],\r\n deliverySchedule: {\r\n timezone: 'UTC',\r\n quietHours: {\r\n start: '22:00',\r\n end: '08:00',\r\n },\r\n weekdays: [true, true, true, true, true, false, false],\r\n },\r\n },\r\n ui: {\r\n isOpen: false,\r\n currentView: 'notifications',\r\n selectedNotifications: [],\r\n isLoading: false,\r\n error: null,\r\n },\r\n websocket: {\r\n connected: false,\r\n reconnecting: false,\r\n },\r\n};\r\n\r\nconst SDKProvider: React.FC<{ config: SDKConfiguration; children: React.ReactNode }> = ({\r\n config,\r\n children,\r\n}) => {\r\n const [sdkState, setSdkState] = React.useState<SDKContextType>({\r\n client: null,\r\n isInitialized: false,\r\n error: null,\r\n });\r\n\r\n useEffect(() => {\r\n let isMounted = true;\r\n\r\n const initializeSDK = async () => {\r\n try {\r\n const existingSDK = (window as any).__notificationSDK;\r\n\r\n // Check if we can reuse the existing SDK instance\r\n if (existingSDK?.client) {\r\n // Compare new config with existing config to determine if we need to re-initialize\r\n // We use simple JSON stringify as configs are simple objects with strings/numbers\r\n const isConfigMatch = JSON.stringify(existingSDK.config) === JSON.stringify(config);\r\n\r\n if (isConfigMatch) {\r\n if (isMounted) {\r\n setSdkState({\r\n client: existingSDK.client,\r\n isInitialized: true,\r\n error: null,\r\n });\r\n }\r\n return;\r\n } else {\r\n console.log('[NotificationWidget] Config changed, re-initializing SDK', { old: existingSDK.config, new: config });\r\n }\r\n }\r\n\r\n const client = new NotificationClient({\r\n apiUrl: config.baseUrl,\r\n apiKey: config.apiKey,\r\n tenantId: config.tenantId,\r\n environmentId: config.environmentId,\r\n });\r\n\r\n (window as any).__notificationSDK = { client, config };\r\n\r\n if (isMounted) {\r\n setSdkState({\r\n client,\r\n isInitialized: true,\r\n error: null,\r\n });\r\n }\r\n } catch (error) {\r\n console.error('Failed to initialize SDK:', error);\r\n if (isMounted) {\r\n setSdkState({\r\n client: null,\r\n isInitialized: false,\r\n error: error as Error,\r\n });\r\n }\r\n }\r\n };\r\n\r\n initializeSDK();\r\n\r\n return () => {\r\n isMounted = false;\r\n };\r\n }, [config]);\r\n\r\n return (\r\n <SDKContext.Provider value={sdkState}>\r\n {children}\r\n </SDKContext.Provider>\r\n );\r\n};\r\n\r\nconst widgetReducer = (state: WidgetState, action: WidgetAction): WidgetState => {\r\n switch (action.type) {\r\n case 'SET_NOTIFICATIONS':\r\n return {\r\n ...state,\r\n notifications: action.payload,\r\n unreadCount: action.payload.filter(n => !n.isRead).length,\r\n };\r\n\r\n case 'ADD_NOTIFICATION':\r\n const newNotifications = [action.payload, ...state.notifications];\r\n return {\r\n ...state,\r\n notifications: newNotifications,\r\n unreadCount: newNotifications.filter(n => !n.isRead).length,\r\n };\r\n\r\n case 'UPDATE_NOTIFICATION':\r\n const updatedNotifications = state.notifications.map(n =>\r\n n.id === action.payload.id ? { ...n, ...action.payload.updates } : n\r\n );\r\n return {\r\n ...state,\r\n notifications: updatedNotifications,\r\n unreadCount: updatedNotifications.filter(n => !n.isRead).length,\r\n };\r\n\r\n case 'DELETE_NOTIFICATION':\r\n const filteredNotifications = state.notifications.filter(n => n.id !== action.payload);\r\n return {\r\n ...state,\r\n notifications: filteredNotifications,\r\n unreadCount: filteredNotifications.filter(n => !n.isRead).length,\r\n };\r\n\r\n case 'SET_PREFERENCES':\r\n return {\r\n ...state,\r\n preferences: action.payload,\r\n };\r\n\r\n case 'SET_UI_STATE':\r\n return {\r\n ...state,\r\n ui: { ...state.ui, ...action.payload },\r\n };\r\n\r\n case 'SET_WEBSOCKET_STATE':\r\n return {\r\n ...state,\r\n websocket: { ...state.websocket, ...action.payload },\r\n };\r\n\r\n default:\r\n return state;\r\n }\r\n};\r\n\r\nconst NotificationWidgetInternal: React.FC<Omit<NotificationWidgetProps, 'sdkConfig'>> = ({\r\n position = 'right',\r\n size = 'medium',\r\n theme = 'light',\r\n className = '',\r\n onError,\r\n}) => {\r\n const [state, dispatch] = useReducer(widgetReducer, initialState);\r\n const { client, isInitialized, error: sdkError } = useSDK();\r\n const websocketRef = useRef<any>(null);\r\n\r\n const handlePreferencesChange = useCallback((preferences: any) => {\r\n dispatch({\r\n type: 'SET_PREFERENCES',\r\n payload: preferences,\r\n });\r\n }, []);\r\n\r\n const handleWidgetError = useCallback((error: Error) => {\r\n console.error('Widget error:', error);\r\n if (onError) {\r\n onError(error);\r\n }\r\n }, [onError]);\r\n\r\n const { isLoading: isPreferencesLoading, error: preferencesLoadError } = usePreferencesSync({\r\n onPreferencesLoaded: handlePreferencesChange,\r\n onError: handleWidgetError,\r\n });\r\n\r\n const { updatePreference, isSaving, error: preferencesError } = useLivePreferences({\r\n preferences: state.preferences,\r\n onPreferencesChange: handlePreferencesChange,\r\n onError: handleWidgetError,\r\n });\r\n\r\n const handleWebSocketEvent = useCallback((event: any) => {\r\n try {\r\n const notificationMapper = createNotificationMapper();\r\n\r\n switch (event.type) {\r\n case 'notification_received': {\r\n const wsPayload = event.data;\r\n\r\n if (!notificationMapper.validateWebSocketPayload(wsPayload)) {\r\n console.error('Invalid WebSocket notification payload, skipping', wsPayload);\r\n break;\r\n }\r\n\r\n const mappedNotification = notificationMapper.toWidgetNotificationFromWebSocket(wsPayload);\r\n dispatch({\r\n type: 'ADD_NOTIFICATION',\r\n payload: mappedNotification,\r\n });\r\n break;\r\n }\r\n\r\n case 'notification_updated':\r\n dispatch({\r\n type: 'UPDATE_NOTIFICATION',\r\n payload: {\r\n id: event.data.id || event.data.notificationId,\r\n updates: event.data,\r\n },\r\n });\r\n break;\r\n\r\n case 'notification_deleted':\r\n dispatch({\r\n type: 'DELETE_NOTIFICATION',\r\n payload: event.data.id || event.data.notificationId,\r\n });\r\n break;\r\n\r\n case 'preferences_updated':\r\n dispatch({\r\n type: 'SET_PREFERENCES',\r\n payload: event.data,\r\n });\r\n break;\r\n\r\n default:\r\n console.log('Unknown WebSocket event type:', event.type);\r\n }\r\n } catch (error) {\r\n console.error('Error handling WebSocket event:', error);\r\n }\r\n }, []);\r\n\r\n const connectWebSocket = useCallback(async () => {\r\n if (!client || !isInitialized || websocketRef.current) return;\r\n\r\n try {\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { reconnecting: true },\r\n });\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n if (!sdkConfig) {\r\n throw new Error('SDK configuration not available for WebSocket connection');\r\n }\r\n\r\n const baseUrl = client.getApiHost();\r\n const namespace = '/v1/notifications';\r\n const fullUrl = `${baseUrl}${namespace}`;\r\n\r\n console.log('Connecting to Socket.IO at:', fullUrl);\r\n\r\n const socket = ioClient(fullUrl, {\r\n query: {\r\n tenantId: sdkConfig.tenantId,\r\n subscriberId: sdkConfig.subscriberId,\r\n environmentId: sdkConfig.environmentId,\r\n },\r\n transports: ['websocket'],\r\n autoConnect: false,\r\n reconnection: true,\r\n reconnectionAttempts: 10,\r\n reconnectionDelay: 1000,\r\n reconnectionDelayMax: 5000,\r\n });\r\n\r\n websocketRef.current = socket;\r\n\r\n socket.on('notification', (payload: any) => {\r\n console.log('Received notification:', payload);\r\n handleWebSocketEvent({\r\n type: 'notification_received',\r\n data: payload,\r\n });\r\n });\r\n\r\n socket.on('connect', () => {\r\n console.log('Socket.IO connected successfully');\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: true, reconnecting: false },\r\n });\r\n });\r\n\r\n socket.on('disconnect', (reason: any) => {\r\n console.log('Socket.IO disconnected:', reason);\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: false },\r\n });\r\n });\r\n\r\n socket.on('reconnect_attempt', (attempt: any) => {\r\n console.log('Socket.IO reconnection attempt:', attempt);\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: true },\r\n });\r\n });\r\n\r\n socket.on('connect_error', (error: any) => {\r\n console.error('Socket.IO connection error:', error);\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: false },\r\n });\r\n if (onError) {\r\n onError(error);\r\n }\r\n });\r\n\r\n socket.connect();\r\n\r\n } catch (error) {\r\n console.error('Failed to connect WebSocket:', error);\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: false },\r\n });\r\n if (onError) {\r\n onError(error as Error);\r\n }\r\n }\r\n }, [client, isInitialized, handleWebSocketEvent, onError]);\r\n\r\n const disconnectWebSocket = useCallback(() => {\r\n if (websocketRef.current) {\r\n try {\r\n if (websocketRef.current.disconnect) {\r\n websocketRef.current.disconnect();\r\n }\r\n websocketRef.current = null;\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: false },\r\n });\r\n } catch (error) {\r\n console.error('Error disconnecting WebSocket:', error);\r\n }\r\n }\r\n }, []);\r\n\r\n const handleBellClick = useCallback(() => {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isOpen: !state.ui.isOpen },\r\n });\r\n }, [state.ui.isOpen]);\r\n\r\n const handlePopoverClose = useCallback(() => {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isOpen: false },\r\n });\r\n }, []);\r\n\r\n const handleViewChange = useCallback((view: 'notifications' | 'preferences') => {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { currentView: view },\r\n });\r\n }, []);\r\n\r\n const handleNotificationAction = useCallback(async (id: string, action: any) => {\r\n if (!client || !isInitialized) {\r\n console.error('SDK not initialized');\r\n return;\r\n }\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n if (!sdkConfig) {\r\n console.error('SDK configuration not available');\r\n return;\r\n }\r\n\r\n try {\r\n switch (action.type) {\r\n case 'mark_read':\r\n await client.inbox.markAsRead(id, sdkConfig.tenantId, sdkConfig.environmentId, sdkConfig.subscriberId);\r\n break;\r\n case 'mark_unread':\r\n await client.inbox.markAsUnread(id, sdkConfig.tenantId, sdkConfig.environmentId, sdkConfig.subscriberId);\r\n break;\r\n case 'archive':\r\n await client.inbox.archive(id, sdkConfig.tenantId, sdkConfig.environmentId, sdkConfig.subscriberId);\r\n break;\r\n case 'delete':\r\n await client.inbox.delete(id, sdkConfig.tenantId, sdkConfig.environmentId, sdkConfig.subscriberId);\r\n break;\r\n default:\r\n if (action.handler) {\r\n await action.handler(id);\r\n }\r\n break;\r\n }\r\n\r\n switch (action.type) {\r\n case 'mark_read':\r\n dispatch({\r\n type: 'UPDATE_NOTIFICATION',\r\n payload: { id, updates: { isRead: true } },\r\n });\r\n break;\r\n case 'mark_unread':\r\n dispatch({\r\n type: 'UPDATE_NOTIFICATION',\r\n payload: { id, updates: { isRead: false } },\r\n });\r\n break;\r\n case 'archive':\r\n dispatch({\r\n type: 'UPDATE_NOTIFICATION',\r\n payload: { id, updates: { isArchived: true } },\r\n });\r\n break;\r\n case 'delete':\r\n dispatch({\r\n type: 'DELETE_NOTIFICATION',\r\n payload: id,\r\n });\r\n break;\r\n }\r\n } catch (error) {\r\n console.error('Error performing notification action:', error);\r\n if (onError) {\r\n onError(error as Error);\r\n }\r\n }\r\n }, [client]);\r\n\r\n useEffect(() => {\r\n if (!client || !isInitialized) return;\r\n\r\n const loadNotifications = async () => {\r\n try {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isLoading: true },\r\n });\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n if (!sdkConfig) {\r\n throw new Error('SDK configuration not available');\r\n }\r\n\r\n const notificationMapper = createNotificationMapper();\r\n const response = await client.inbox.getRenderedNotifications(\r\n {\r\n channel: 'in_app',\r\n limit: 50,\r\n offset: 0,\r\n },\r\n sdkConfig.tenantId,\r\n sdkConfig.environmentId,\r\n sdkConfig.subscriberId,\r\n );\r\n\r\n const coreNotifications = (response?.items || []).map((item: any) =>\r\n notificationMapper.toWidgetNotification(item)\r\n );\r\n\r\n dispatch({\r\n type: 'SET_NOTIFICATIONS',\r\n payload: coreNotifications,\r\n });\r\n\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isLoading: false, error: null },\r\n });\r\n } catch (error) {\r\n console.error('Failed to load notifications:', error);\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: {\r\n isLoading: false,\r\n error: (error as Error)\r\n },\r\n });\r\n if (onError) {\r\n onError(error as Error);\r\n }\r\n }\r\n };\r\n\r\n loadNotifications();\r\n }, [client, isInitialized, onError]);\r\n\r\n useEffect(() => {\r\n if (client && isInitialized) {\r\n connectWebSocket();\r\n }\r\n\r\n return () => {\r\n disconnectWebSocket();\r\n };\r\n }, [client]);\r\n\r\n useEffect(() => {\r\n if (!client || !isInitialized) return;\r\n\r\n if (state.websocket.connected) return;\r\n\r\n const pollInterval = setInterval(async () => {\r\n try {\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n if (!sdkConfig) {\r\n return;\r\n }\r\n\r\n const notificationMapper = createNotificationMapper();\r\n const response = await client.inbox.getRenderedNotifications(\r\n {\r\n channel: 'in_app',\r\n limit: 50,\r\n offset: 0,\r\n },\r\n sdkConfig.tenantId,\r\n sdkConfig.environmentId,\r\n sdkConfig.subscriberId,\r\n );\r\n\r\n const coreNotifications = (response?.items || []).map((item: any) =>\r\n notificationMapper.toWidgetNotification(item)\r\n );\r\n\r\n dispatch({\r\n type: 'SET_NOTIFICATIONS',\r\n payload: coreNotifications,\r\n });\r\n } catch (error) {\r\n console.error('Polling failed:', error);\r\n }\r\n }, 30000);\r\n\r\n return () => clearInterval(pollInterval);\r\n }, [client, state.websocket.connected]);\r\n\r\n useEffect(() => {\r\n const handleStorageChange = (event: StorageEvent) => {\r\n if (event.key === 'notification_widget_sync' && event.newValue) {\r\n try {\r\n const syncData = JSON.parse(event.newValue);\r\n handleWebSocketEvent(syncData);\r\n } catch (error) {\r\n console.error('Error parsing sync data:', error);\r\n }\r\n }\r\n };\r\n\r\n window.addEventListener('storage', handleStorageChange);\r\n return () => window.removeEventListener('storage', handleStorageChange);\r\n }, [handleWebSocketEvent]);\r\n\r\n useEffect(() => {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isLoading: isSaving },\r\n });\r\n }, [isSaving]);\r\n\r\n useEffect(() => {\r\n const error = sdkError || preferencesError || preferencesLoadError;\r\n if (error) {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { error: error },\r\n });\r\n }\r\n }, [sdkError, preferencesError, preferencesLoadError]);\r\n\r\n if (!isInitialized && !sdkError) {\r\n return (\r\n <div\r\n className={`relative inline-block ${className}`}\r\n data-widget-size={size || 'small'}\r\n data-theme={theme}\r\n data-testid=\"notification-widget\"\r\n >\r\n <ComponentErrorBoundary componentName=\"BellComponent\">\r\n <BellComponent\r\n unreadCount={0}\r\n onClick={() => { }}\r\n size={size}\r\n disabled={true}\r\n />\r\n </ComponentErrorBoundary>\r\n </div>\r\n );\r\n }\r\n\r\n if (sdkError) {\r\n return (\r\n <div\r\n className={`relative inline-block ${className}`}\r\n data-widget-size={size || 'small'}\r\n data-theme={theme}\r\n data-testid=\"notification-widget\"\r\n >\r\n <ComponentErrorBoundary\r\n componentName=\"BellComponent\"\r\n fallback={\r\n <SDKConnectionFallback\r\n error={sdkError.message}\r\n onRetry={() => window.location.reload()}\r\n />\r\n }\r\n >\r\n <BellComponent\r\n unreadCount={0}\r\n onClick={() => { }}\r\n size={size}\r\n disabled={true}\r\n />\r\n </ComponentErrorBoundary>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={`relative inline-block ${className}`}\r\n data-widget-size={size || 'small'}\r\n data-theme={theme}\r\n data-testid=\"notification-widget\"\r\n >\r\n <ComponentErrorBoundary componentName=\"BellComponent\">\r\n <BellComponent\r\n unreadCount={state.unreadCount}\r\n onClick={handleBellClick}\r\n size={size}\r\n disabled={state.ui.isLoading}\r\n />\r\n </ComponentErrorBoundary>\r\n\r\n <ComponentErrorBoundary\r\n componentName=\"InboxPopover\"\r\n fallback={<LoadingFallback message=\"Unable to load notifications\" />}\r\n >\r\n <InboxPopover\r\n isOpen={state.ui.isOpen}\r\n onClose={handlePopoverClose}\r\n position={position}\r\n currentView={state.ui.currentView}\r\n onViewChange={handleViewChange}\r\n notifications={state.notifications}\r\n onNotificationAction={handleNotificationAction}\r\n preferences={state.preferences}\r\n onPreferenceChange={updatePreference}\r\n isPreferencesLoading={isSaving}\r\n />\r\n </ComponentErrorBoundary>\r\n </div>\r\n );\r\n};\r\n\r\nexport const NotificationWidget: React.FC<NotificationWidgetProps> = ({\r\n sdkConfig,\r\n ...props\r\n}) => {\r\n return (\r\n <NotificationWidgetErrorBoundary onError={props.onError}>\r\n <SDKProvider config={sdkConfig}>\r\n <NotificationWidgetInternal {...props} />\r\n </SDKProvider>\r\n </NotificationWidgetErrorBoundary>\r\n );\r\n};","export { NotificationWidget } from './components/NotificationWidget';\r\n\r\nexport { BellComponent } from './components/BellComponent';\r\nexport { InboxPopover } from './components/InboxPopover';\r\nexport { NotificationItem } from './components/NotificationItem';\r\nexport { PreferencesView } from './components/PreferencesView';\r\n\r\nexport { NotificationWidgetErrorBoundary } from './components/ErrorBoundary';\r\n\r\nexport type * from './types/core';\r\n\r\nexport type { Notification as SDKNotification, NotificationFilters } from '@edusight/notification-sdk';\r\n\r\nimport './styles/index.css';\r\n\r\nexport const VERSION = '3.0.0';\r\nexport const WIDGET_NAME = '@edusight/notification-widget';"],"names":["ErrorFallback","error","onRetry","jsxs","jsx","MdError","MdRefresh","NotificationWidgetErrorBoundary","Component","props","errorInfo","useNotificationsClient","usePreferencesSync","onPreferencesLoaded","onError","notificationClient","isLoading","setIsLoading","useState","setError","preferences","setPreferences","loadPreferences","useCallback","config","subscriberId","tenantId","environmentId","servicePreferences","mappedPreferences","workflowId","categoryPrefs","err","defaultPreferences","useEffect","SDKContext","createContext","useSDK","context","useContext","initialState","SDKProvider","children","sdkState","setSdkState","React","isMounted","existingSDK","client","NotificationClient","widgetReducer","state","action","n","newNotifications","updatedNotifications","filteredNotifications","NotificationWidgetInternal","position","size","theme","className","dispatch","useReducer","isInitialized","sdkError","websocketRef","useRef","handlePreferencesChange","handleWidgetError","preferencesLoadError","updatePreference","isSaving","preferencesError","useLivePreferences","handleWebSocketEvent","event","notificationMapper","createNotificationMapper","wsPayload","mappedNotification","connectWebSocket","sdkConfig","fullUrl","socket","ioClient","payload","reason","attempt","disconnectWebSocket","handleBellClick","handlePopoverClose","handleViewChange","view","handleNotificationAction","id","coreNotifications","item","pollInterval","handleStorageChange","syncData","ComponentErrorBoundary","BellComponent","SDKConnectionFallback","LoadingFallback","InboxPopover","NotificationWidget","VERSION","WIDGET_NAME"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/components/ErrorBoundary.tsx","../src/hooks/usePreferencesSync.ts","../src/hooks/useWorkflows.ts","../src/components/NotificationWidget.tsx","../src/index.ts"],"sourcesContent":["import React, { Component, ErrorInfo, ReactNode } from 'react';\r\nimport { MdError, MdRefresh } from 'react-icons/md';\r\nimport { ErrorBoundaryState } from '../types/core';\r\n\r\ninterface ErrorBoundaryProps {\r\n children: ReactNode;\r\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\r\n}\r\n\r\nconst ErrorFallback: React.FC<{\r\n error: Error | null;\r\n onRetry: () => void;\r\n}> = ({ error, onRetry }) => (\r\n <div\r\n className=\"p-4 bg-[var(--widget-error)]/10 border border-[var(--widget-error)]/20 rounded-lg\"\r\n role=\"alert\"\r\n data-testid=\"error-boundary-fallback\"\r\n >\r\n <div className=\"flex items-center mb-2\">\r\n <MdError\r\n className=\"w-6 h-6 text-[var(--widget-error)] mr-2\"\r\n aria-hidden=\"true\"\r\n />\r\n <h3\r\n className=\"text-sm font-medium text-[var(--widget-error)]\"\r\n >\r\n Something went wrong\r\n </h3>\r\n </div>\r\n\r\n <p\r\n className=\"text-sm mb-3 text-[var(--widget-error)]/80\"\r\n >\r\n The notification widget encountered an error and couldn't load properly.\r\n </p>\r\n\r\n {process.env.NODE_ENV === 'development' && error && (\r\n <details className=\"mb-3\">\r\n <summary\r\n className=\"text-xs cursor-pointer text-[var(--widget-error)] hover:text-[var(--widget-error)]/80 transition-colors\"\r\n >\r\n Error details (development only)\r\n </summary>\r\n <pre\r\n className=\"mt-2 text-xs bg-[var(--widget-error)]/5 p-2 rounded overflow-auto max-h-32 text-[var(--widget-error)]\"\r\n >\r\n {error.message}\r\n {error.stack && `\\n\\n${error.stack}`}\r\n </pre>\r\n </details>\r\n )}\r\n\r\n <button\r\n type=\"button\"\r\n 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\"\r\n onClick={onRetry}\r\n data-testid=\"error-retry-button\"\r\n >\r\n <MdRefresh\r\n className=\"mr-1 w-4 h-4\"\r\n aria-hidden=\"true\"\r\n />\r\n Try again\r\n </button>\r\n </div>\r\n);\r\n\r\nexport class NotificationWidgetErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\r\n constructor(props: ErrorBoundaryProps) {\r\n super(props);\r\n this.state = {\r\n hasError: false,\r\n error: null,\r\n errorInfo: null,\r\n };\r\n }\r\n\r\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\r\n return {\r\n hasError: true,\r\n error,\r\n };\r\n }\r\n\r\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\r\n this.setState({\r\n errorInfo,\r\n });\r\n\r\n console.error('NotificationWidget Error Boundary caught an error:', {\r\n message: error.message,\r\n stack: error.stack,\r\n componentStack: errorInfo.componentStack,\r\n timestamp: new Date().toISOString(),\r\n });\r\n\r\n if (this.props.onError) {\r\n this.props.onError(error, errorInfo);\r\n }\r\n }\r\n\r\n handleRetry = () => {\r\n this.setState({\r\n hasError: false,\r\n error: null,\r\n errorInfo: null,\r\n });\r\n };\r\n\r\n render() {\r\n if (this.state.hasError) {\r\n return (\r\n <ErrorFallback\r\n error={this.state.error}\r\n onRetry={this.handleRetry}\r\n />\r\n );\r\n }\r\n\r\n return this.props.children;\r\n }\r\n}\r\n\r\nexport const useErrorHandler = () => {\r\n return (error: Error, errorInfo?: ErrorInfo) => {\r\n console.error('Widget error:', {\r\n message: error.message,\r\n stack: error.stack,\r\n errorInfo,\r\n timestamp: new Date().toISOString(),\r\n });\r\n };\r\n};","import { useEffect, useState, useCallback } 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 UsePreferencesSyncProps {\r\n onPreferencesLoaded: (preferences: NotificationPreferences) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport interface UsePreferencesSyncResult {\r\n isLoading: boolean;\r\n error: Error | null;\r\n preferences: NotificationPreferences | null;\r\n}\r\n\r\nexport const usePreferencesSync = ({\r\n onPreferencesLoaded,\r\n onError,\r\n}: UsePreferencesSyncProps): UsePreferencesSyncResult => {\r\n const notificationClient = useNotificationsClient();\r\n const [isLoading, setIsLoading] = useState(true);\r\n const [error, setError] = useState<Error | null>(null);\r\n const [preferences, setPreferences] = useState<NotificationPreferences | null>(null);\r\n\r\n const loadPreferences = useCallback(async () => {\r\n try {\r\n setIsLoading(true);\r\n setError(null);\r\n\r\n if (!notificationClient) {\r\n throw new Error('Notification client not available');\r\n }\r\n\r\n const config = (window as any).__notificationSDK?.config;\r\n\r\n if (!config) {\r\n throw new Error('SDK configuration not available');\r\n }\r\n\r\n const { subscriberId, tenantId, environmentId } = config;\r\n\r\n if (!subscriberId || !tenantId || !environmentId) {\r\n throw new Error('SubscriberId, TenantId or EnvironmentId not available in config');\r\n }\r\n\r\n const servicePreferences = await notificationClient.preferences.get(\r\n tenantId,\r\n subscriberId,\r\n environmentId,\r\n );\r\n\r\n const mappedPreferences: NotificationPreferences = {\r\n channels: {\r\n email: servicePreferences.emailEnabled ?? true,\r\n push: servicePreferences.pushEnabled ?? true,\r\n sms: servicePreferences.smsEnabled ?? false,\r\n inApp: servicePreferences.inAppEnabled ?? true,\r\n },\r\n subscriptions: [],\r\n deliverySchedule: {\r\n timezone: 'UTC',\r\n quietHours: {\r\n start: servicePreferences.quietHoursStart ?? '22:00',\r\n end: servicePreferences.quietHoursEnd ?? '08:00',\r\n },\r\n weekdays: [true, true, true, true, true, false, false],\r\n },\r\n };\r\n\r\n if (servicePreferences.categories) {\r\n Object.entries(servicePreferences.categories).forEach(([workflowId, categoryPrefs]) => {\r\n mappedPreferences.subscriptions.push({\r\n workflowId,\r\n name: workflowId,\r\n enabled: true,\r\n channels: {\r\n email: (categoryPrefs as any).emailEnabled ?? true,\r\n push: (categoryPrefs as any).pushEnabled ?? true,\r\n sms: (categoryPrefs as any).smsEnabled ?? false,\r\n inApp: (categoryPrefs as any).inAppEnabled ?? true,\r\n },\r\n });\r\n });\r\n }\r\n\r\n setPreferences(mappedPreferences);\r\n onPreferencesLoaded(mappedPreferences);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to load preferences');\r\n\r\n // If 404, it means preferences don't exist yet for this user. \r\n // We'll use defaults and suppress the error callback.\r\n const isNotFound = (err as any)?.response?.status === 404 || (err as any)?.status === 404;\r\n\r\n if (!isNotFound) {\r\n setError(error);\r\n onError?.(error);\r\n } else {\r\n console.warn('Preferences not found for user (404), using defaults.');\r\n }\r\n\r\n const defaultPreferences: NotificationPreferences = {\r\n channels: {\r\n email: true,\r\n push: true,\r\n sms: false,\r\n inApp: true,\r\n },\r\n subscriptions: [],\r\n deliverySchedule: {\r\n timezone: 'UTC',\r\n quietHours: {\r\n start: '22:00',\r\n end: '08:00',\r\n },\r\n weekdays: [true, true, true, true, true, false, false],\r\n },\r\n };\r\n setPreferences(defaultPreferences);\r\n onPreferencesLoaded(defaultPreferences);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n }, [notificationClient, onPreferencesLoaded, onError]);\r\n\r\n useEffect(() => {\r\n if (notificationClient) {\r\n loadPreferences();\r\n }\r\n }, [notificationClient, loadPreferences]);\r\n\r\n return {\r\n isLoading,\r\n error,\r\n preferences,\r\n };\r\n};\r\n","import { useEffect, useState, useCallback } from 'react';\r\n\r\nconst useNotificationsClient = () => {\r\n return (window as any).__notificationSDK?.client;\r\n};\r\n\r\nexport interface Workflow {\r\n workflowId: string;\r\n name: string;\r\n description?: string;\r\n}\r\n\r\nexport interface UseWorkflowsResult {\r\n workflows: Workflow[];\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport const useWorkflows = (): UseWorkflowsResult => {\r\n const notificationClient = useNotificationsClient();\r\n const [workflows, setWorkflows] = useState<Workflow[]>([]);\r\n const [isLoading, setIsLoading] = useState(true);\r\n const [error, setError] = useState<Error | null>(null);\r\n\r\n const loadWorkflows = useCallback(async () => {\r\n try {\r\n setIsLoading(true);\r\n setError(null);\r\n\r\n if (!notificationClient) {\r\n throw new Error('Notification client not available');\r\n }\r\n\r\n const config = (window as any).__notificationSDK?.config;\r\n\r\n if (!config) {\r\n throw new Error('SDK configuration not available');\r\n }\r\n\r\n const { tenantId, environmentId } = config;\r\n\r\n if (!tenantId || !environmentId) {\r\n throw new Error('TenantId or EnvironmentId not available in config');\r\n }\r\n\r\n // List all active workflows for this tenant/environment\r\n const response = await notificationClient.workflows.list(\r\n { status: 'active' }, // Only load active workflows\r\n tenantId,\r\n environmentId\r\n );\r\n\r\n const mappedWorkflows: Workflow[] = (response?.workflows || []).map((wf: any) => ({\r\n workflowId: wf.workflowId,\r\n name: wf.name || wf.workflowId,\r\n description: wf.description,\r\n }));\r\n\r\n setWorkflows(mappedWorkflows);\r\n } catch (err: any) {\r\n const error = err instanceof Error ? err : new Error('Failed to load workflows');\r\n\r\n // Silently handle 404 or other errors - workflows are optional\r\n console.warn('Failed to load workflows:', error);\r\n setError(error);\r\n setWorkflows([]);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n }, [notificationClient]);\r\n\r\n useEffect(() => {\r\n if (notificationClient) {\r\n loadWorkflows();\r\n }\r\n }, [notificationClient, loadWorkflows]);\r\n\r\n return {\r\n workflows,\r\n isLoading,\r\n error,\r\n refetch: loadWorkflows,\r\n };\r\n};\r\n","\r\nimport React, { useReducer, useEffect, useCallback, createContext, useContext, useRef } from 'react';\r\nimport { io as ioClient } from 'socket.io-client';\r\nimport { NotificationClient } from '@edusight/notification-sdk';\r\nimport { NotificationWidgetProps, WidgetState, WidgetAction, SDKConfiguration } from '../types/core';\r\nimport { BellComponent } from './BellComponent';\r\nimport { InboxPopover } from './InboxPopover';\r\nimport { NotificationWidgetErrorBoundary } from './ErrorBoundary';\r\nimport { ComponentErrorBoundary } from './ComponentErrorBoundary';\r\nimport { SDKConnectionFallback, LoadingFallback } from './FallbackComponents';\r\nimport { useLivePreferences } from '../hooks/useLivePreferences';\r\nimport { usePreferencesSync } from '../hooks/usePreferencesSync';\r\nimport { useWorkflows } from '../hooks/useWorkflows';\r\nimport { createNotificationMapper } from '../utils/notification-mapper';\r\n\r\ninterface SDKContextType {\r\n client: any;\r\n isInitialized: boolean;\r\n error: Error | null;\r\n}\r\n\r\nconst SDKContext = createContext<SDKContextType | null>(null);\r\n\r\nexport const useSDK = () => {\r\n const context = useContext(SDKContext);\r\n if (!context) {\r\n throw new Error('useSDK must be used within a NotificationWidget');\r\n }\r\n return context;\r\n};\r\n\r\nconst initialState: WidgetState = {\r\n notifications: [],\r\n unreadCount: 0,\r\n preferences: {\r\n channels: {\r\n email: true,\r\n push: true,\r\n sms: false,\r\n inApp: true,\r\n },\r\n subscriptions: [],\r\n deliverySchedule: {\r\n timezone: 'UTC',\r\n quietHours: {\r\n start: '22:00',\r\n end: '08:00',\r\n },\r\n weekdays: [true, true, true, true, true, false, false],\r\n },\r\n },\r\n ui: {\r\n isOpen: false,\r\n currentView: 'notifications',\r\n selectedNotifications: [],\r\n isLoading: false,\r\n error: null,\r\n },\r\n websocket: {\r\n connected: false,\r\n reconnecting: false,\r\n },\r\n};\r\n\r\nconst SDKProvider: React.FC<{ config: SDKConfiguration; children: React.ReactNode }> = ({\r\n config,\r\n children,\r\n}) => {\r\n const [sdkState, setSdkState] = React.useState<SDKContextType>({\r\n client: null,\r\n isInitialized: false,\r\n error: null,\r\n });\r\n\r\n useEffect(() => {\r\n let isMounted = true;\r\n\r\n const initializeSDK = async () => {\r\n try {\r\n const existingSDK = (window as any).__notificationSDK;\r\n\r\n // Check if we can reuse the existing SDK instance\r\n if (existingSDK?.client) {\r\n // Compare new config with existing config to determine if we need to re-initialize\r\n // We use simple JSON stringify as configs are simple objects with strings/numbers\r\n const isConfigMatch = JSON.stringify(existingSDK.config) === JSON.stringify(config);\r\n\r\n if (isConfigMatch) {\r\n if (isMounted) {\r\n setSdkState({\r\n client: existingSDK.client,\r\n isInitialized: true,\r\n error: null,\r\n });\r\n }\r\n return;\r\n } else {\r\n console.log('[NotificationWidget] Config changed, re-initializing SDK', { old: existingSDK.config, new: config });\r\n }\r\n }\r\n\r\n const client = new NotificationClient({\r\n apiUrl: config.baseUrl,\r\n apiKey: config.apiKey,\r\n tenantId: config.tenantId,\r\n environmentId: config.environmentId,\r\n });\r\n\r\n (window as any).__notificationSDK = { client, config };\r\n\r\n if (isMounted) {\r\n setSdkState({\r\n client,\r\n isInitialized: true,\r\n error: null,\r\n });\r\n }\r\n } catch (error) {\r\n console.error('Failed to initialize SDK:', error);\r\n if (isMounted) {\r\n setSdkState({\r\n client: null,\r\n isInitialized: false,\r\n error: error as Error,\r\n });\r\n }\r\n }\r\n };\r\n\r\n initializeSDK();\r\n\r\n return () => {\r\n isMounted = false;\r\n };\r\n }, [config]);\r\n\r\n return (\r\n <SDKContext.Provider value={sdkState}>\r\n {children}\r\n </SDKContext.Provider>\r\n );\r\n};\r\n\r\nconst widgetReducer = (state: WidgetState, action: WidgetAction): WidgetState => {\r\n switch (action.type) {\r\n case 'SET_NOTIFICATIONS':\r\n return {\r\n ...state,\r\n notifications: action.payload,\r\n unreadCount: action.payload.filter(n => !n.isRead).length,\r\n };\r\n\r\n case 'ADD_NOTIFICATION':\r\n const newNotifications = [action.payload, ...state.notifications];\r\n return {\r\n ...state,\r\n notifications: newNotifications,\r\n unreadCount: newNotifications.filter(n => !n.isRead).length,\r\n };\r\n\r\n case 'UPDATE_NOTIFICATION':\r\n const updatedNotifications = state.notifications.map(n =>\r\n n.id === action.payload.id ? { ...n, ...action.payload.updates } : n\r\n );\r\n return {\r\n ...state,\r\n notifications: updatedNotifications,\r\n unreadCount: updatedNotifications.filter(n => !n.isRead).length,\r\n };\r\n\r\n case 'DELETE_NOTIFICATION':\r\n const filteredNotifications = state.notifications.filter(n => n.id !== action.payload);\r\n return {\r\n ...state,\r\n notifications: filteredNotifications,\r\n unreadCount: filteredNotifications.filter(n => !n.isRead).length,\r\n };\r\n\r\n case 'SET_PREFERENCES':\r\n return {\r\n ...state,\r\n preferences: action.payload,\r\n };\r\n\r\n case 'SET_UI_STATE':\r\n return {\r\n ...state,\r\n ui: { ...state.ui, ...action.payload },\r\n };\r\n\r\n case 'SET_WEBSOCKET_STATE':\r\n return {\r\n ...state,\r\n websocket: { ...state.websocket, ...action.payload },\r\n };\r\n\r\n default:\r\n return state;\r\n }\r\n};\r\n\r\nconst NotificationWidgetInternal: React.FC<Omit<NotificationWidgetProps, 'sdkConfig'>> = ({\r\n position = 'right',\r\n size = 'medium',\r\n theme = 'light',\r\n className = '',\r\n onError,\r\n}) => {\r\n const [state, dispatch] = useReducer(widgetReducer, initialState);\r\n const { client, isInitialized, error: sdkError } = useSDK();\r\n const websocketRef = useRef<any>(null);\r\n\r\n const handlePreferencesChange = useCallback((preferences: any) => {\r\n dispatch({\r\n type: 'SET_PREFERENCES',\r\n payload: preferences,\r\n });\r\n }, []);\r\n\r\n const handleWidgetError = useCallback((error: Error) => {\r\n console.error('Widget error:', error);\r\n if (onError) {\r\n onError(error);\r\n }\r\n }, [onError]);\r\n\r\n const { isLoading: isPreferencesLoading, error: preferencesLoadError } = usePreferencesSync({\r\n onPreferencesLoaded: handlePreferencesChange,\r\n onError: handleWidgetError,\r\n });\r\n\r\n // Load available workflows to populate subscription preferences\r\n const { workflows, isLoading: isWorkflowsLoading } = useWorkflows();\r\n\r\n const { updatePreference, isSaving, error: preferencesError } = useLivePreferences({\r\n preferences: state.preferences,\r\n onPreferencesChange: handlePreferencesChange,\r\n onError: handleWidgetError,\r\n });\r\n\r\n // Merge workflows into preferences subscriptions when they load\r\n useEffect(() => {\r\n if (!isWorkflowsLoading && workflows.length > 0) {\r\n const updatedSubscriptions = workflows.map(wf => {\r\n // Find existing preference for this workflow\r\n const existing = state.preferences.subscriptions.find(s => s.workflowId === wf.workflowId);\r\n\r\n return existing || {\r\n workflowId: wf.workflowId,\r\n name: wf.name,\r\n enabled: true, // Default to enabled\r\n channels: {\r\n email: true,\r\n push: true,\r\n sms: false,\r\n inApp: true,\r\n },\r\n };\r\n });\r\n\r\n // Only update if different to avoid infinite loops\r\n if (JSON.stringify(updatedSubscriptions) !== JSON.stringify(state.preferences.subscriptions)) {\r\n dispatch({\r\n type: 'SET_PREFERENCES',\r\n payload: {\r\n ...state.preferences,\r\n subscriptions: updatedSubscriptions,\r\n },\r\n });\r\n }\r\n }\r\n }, [workflows, isWorkflowsLoading, state.preferences]);\r\n\r\n const handleWebSocketEvent = useCallback((event: any) => {\r\n try {\r\n const notificationMapper = createNotificationMapper();\r\n\r\n switch (event.type) {\r\n case 'notification_received': {\r\n const wsPayload = event.data;\r\n\r\n if (!notificationMapper.validateWebSocketPayload(wsPayload)) {\r\n console.error('Invalid WebSocket notification payload, skipping', wsPayload);\r\n break;\r\n }\r\n\r\n const mappedNotification = notificationMapper.toWidgetNotificationFromWebSocket(wsPayload);\r\n dispatch({\r\n type: 'ADD_NOTIFICATION',\r\n payload: mappedNotification,\r\n });\r\n break;\r\n }\r\n\r\n case 'notification_updated':\r\n dispatch({\r\n type: 'UPDATE_NOTIFICATION',\r\n payload: {\r\n id: event.data.id || event.data.notificationId,\r\n updates: event.data,\r\n },\r\n });\r\n break;\r\n\r\n case 'notification_deleted':\r\n dispatch({\r\n type: 'DELETE_NOTIFICATION',\r\n payload: event.data.id || event.data.notificationId,\r\n });\r\n break;\r\n\r\n case 'preferences_updated':\r\n dispatch({\r\n type: 'SET_PREFERENCES',\r\n payload: event.data,\r\n });\r\n break;\r\n\r\n default:\r\n console.log('Unknown WebSocket event type:', event.type);\r\n }\r\n } catch (error) {\r\n console.error('Error handling WebSocket event:', error);\r\n }\r\n }, []);\r\n\r\n const connectWebSocket = useCallback(async () => {\r\n if (!client || !isInitialized || websocketRef.current) return;\r\n\r\n try {\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { reconnecting: true },\r\n });\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n if (!sdkConfig) {\r\n throw new Error('SDK configuration not available for WebSocket connection');\r\n }\r\n\r\n const baseUrl = client.getApiHost();\r\n const namespace = '/v1/notifications';\r\n const fullUrl = `${baseUrl}${namespace}`;\r\n\r\n console.log('Connecting to Socket.IO at:', fullUrl);\r\n\r\n const socket = ioClient(fullUrl, {\r\n query: {\r\n tenantId: sdkConfig.tenantId,\r\n subscriberId: sdkConfig.subscriberId,\r\n environmentId: sdkConfig.environmentId,\r\n },\r\n transports: ['websocket'],\r\n autoConnect: false,\r\n reconnection: true,\r\n reconnectionAttempts: 10,\r\n reconnectionDelay: 1000,\r\n reconnectionDelayMax: 5000,\r\n });\r\n\r\n websocketRef.current = socket;\r\n\r\n socket.on('notification', (payload: any) => {\r\n console.log('Received notification:', payload);\r\n handleWebSocketEvent({\r\n type: 'notification_received',\r\n data: payload,\r\n });\r\n });\r\n\r\n socket.on('connect', () => {\r\n console.log('Socket.IO connected successfully');\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: true, reconnecting: false },\r\n });\r\n });\r\n\r\n socket.on('disconnect', (reason: any) => {\r\n console.log('Socket.IO disconnected:', reason);\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: false },\r\n });\r\n });\r\n\r\n socket.on('reconnect_attempt', (attempt: any) => {\r\n console.log('Socket.IO reconnection attempt:', attempt);\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: true },\r\n });\r\n });\r\n\r\n socket.on('connect_error', (error: any) => {\r\n console.error('Socket.IO connection error:', error);\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: false },\r\n });\r\n if (onError) {\r\n onError(error);\r\n }\r\n });\r\n\r\n socket.connect();\r\n\r\n } catch (error) {\r\n console.error('Failed to connect WebSocket:', error);\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: false },\r\n });\r\n if (onError) {\r\n onError(error as Error);\r\n }\r\n }\r\n }, [client, isInitialized, handleWebSocketEvent, onError]);\r\n\r\n const disconnectWebSocket = useCallback(() => {\r\n if (websocketRef.current) {\r\n try {\r\n if (websocketRef.current.disconnect) {\r\n websocketRef.current.disconnect();\r\n }\r\n websocketRef.current = null;\r\n dispatch({\r\n type: 'SET_WEBSOCKET_STATE',\r\n payload: { connected: false, reconnecting: false },\r\n });\r\n } catch (error) {\r\n console.error('Error disconnecting WebSocket:', error);\r\n }\r\n }\r\n }, []);\r\n\r\n const handleBellClick = useCallback(() => {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isOpen: !state.ui.isOpen },\r\n });\r\n }, [state.ui.isOpen]);\r\n\r\n const handlePopoverClose = useCallback(() => {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isOpen: false },\r\n });\r\n }, []);\r\n\r\n const handleViewChange = useCallback((view: 'notifications' | 'preferences') => {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { currentView: view },\r\n });\r\n }, []);\r\n\r\n const handleNotificationAction = useCallback(async (id: string, action: any) => {\r\n if (!client || !isInitialized) {\r\n console.error('SDK not initialized');\r\n return;\r\n }\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n if (!sdkConfig) {\r\n console.error('SDK configuration not available');\r\n return;\r\n }\r\n\r\n if (!id) {\r\n console.error('notificationId is required');\r\n throw new Error('notificationId is required');\r\n }\r\n\r\n try {\r\n switch (action.type) {\r\n case 'mark_read':\r\n await client.inbox.markAsRead(id, sdkConfig.tenantId, sdkConfig.environmentId, sdkConfig.subscriberId);\r\n break;\r\n case 'mark_unread':\r\n await client.inbox.markAsUnread(id, sdkConfig.tenantId, sdkConfig.environmentId, sdkConfig.subscriberId);\r\n break;\r\n case 'archive':\r\n await client.inbox.archive(id, sdkConfig.tenantId, sdkConfig.environmentId, sdkConfig.subscriberId);\r\n break;\r\n case 'delete':\r\n await client.inbox.delete(id, sdkConfig.tenantId, sdkConfig.environmentId, sdkConfig.subscriberId);\r\n break;\r\n default:\r\n if (action.handler) {\r\n await action.handler(id);\r\n }\r\n break;\r\n }\r\n\r\n switch (action.type) {\r\n case 'mark_read':\r\n dispatch({\r\n type: 'UPDATE_NOTIFICATION',\r\n payload: { id, updates: { isRead: true } },\r\n });\r\n break;\r\n case 'mark_unread':\r\n dispatch({\r\n type: 'UPDATE_NOTIFICATION',\r\n payload: { id, updates: { isRead: false } },\r\n });\r\n break;\r\n case 'archive':\r\n dispatch({\r\n type: 'UPDATE_NOTIFICATION',\r\n payload: { id, updates: { isArchived: true } },\r\n });\r\n break;\r\n case 'delete':\r\n dispatch({\r\n type: 'DELETE_NOTIFICATION',\r\n payload: id,\r\n });\r\n break;\r\n }\r\n } catch (error) {\r\n console.error('Error performing notification action:', error);\r\n if (onError) {\r\n onError(error as Error);\r\n }\r\n }\r\n }, [client]);\r\n\r\n useEffect(() => {\r\n if (!client || !isInitialized) return;\r\n\r\n const loadNotifications = async () => {\r\n try {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isLoading: true },\r\n });\r\n\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n if (!sdkConfig) {\r\n throw new Error('SDK configuration not available');\r\n }\r\n\r\n const notificationMapper = createNotificationMapper();\r\n const response = await client.inbox.getRenderedNotifications(\r\n {\r\n channel: 'in_app',\r\n limit: 50,\r\n offset: 0,\r\n },\r\n sdkConfig.tenantId,\r\n sdkConfig.environmentId,\r\n sdkConfig.subscriberId,\r\n );\r\n\r\n const coreNotifications = (response?.items || []).map((item: any) =>\r\n notificationMapper.toWidgetNotification(item)\r\n );\r\n\r\n dispatch({\r\n type: 'SET_NOTIFICATIONS',\r\n payload: coreNotifications,\r\n });\r\n\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isLoading: false, error: null },\r\n });\r\n } catch (error) {\r\n console.error('Failed to load notifications:', error);\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: {\r\n isLoading: false,\r\n error: (error as Error)\r\n },\r\n });\r\n if (onError) {\r\n onError(error as Error);\r\n }\r\n }\r\n };\r\n\r\n loadNotifications();\r\n }, [client, isInitialized, onError]);\r\n\r\n useEffect(() => {\r\n if (client && isInitialized) {\r\n connectWebSocket();\r\n }\r\n\r\n return () => {\r\n disconnectWebSocket();\r\n };\r\n }, [client]);\r\n\r\n useEffect(() => {\r\n if (!client || !isInitialized) return;\r\n\r\n if (state.websocket.connected) return;\r\n\r\n const pollInterval = setInterval(async () => {\r\n try {\r\n const sdkConfig = (window as any).__notificationSDK?.config;\r\n if (!sdkConfig) {\r\n return;\r\n }\r\n\r\n const notificationMapper = createNotificationMapper();\r\n const response = await client.inbox.getRenderedNotifications(\r\n {\r\n channel: 'in_app',\r\n limit: 50,\r\n offset: 0,\r\n },\r\n sdkConfig.tenantId,\r\n sdkConfig.environmentId,\r\n sdkConfig.subscriberId,\r\n );\r\n\r\n const coreNotifications = (response?.items || []).map((item: any) =>\r\n notificationMapper.toWidgetNotification(item)\r\n );\r\n\r\n dispatch({\r\n type: 'SET_NOTIFICATIONS',\r\n payload: coreNotifications,\r\n });\r\n } catch (error) {\r\n console.error('Polling failed:', error);\r\n }\r\n }, 30000);\r\n\r\n return () => clearInterval(pollInterval);\r\n }, [client, state.websocket.connected]);\r\n\r\n useEffect(() => {\r\n const handleStorageChange = (event: StorageEvent) => {\r\n if (event.key === 'notification_widget_sync' && event.newValue) {\r\n try {\r\n const syncData = JSON.parse(event.newValue);\r\n handleWebSocketEvent(syncData);\r\n } catch (error) {\r\n console.error('Error parsing sync data:', error);\r\n }\r\n }\r\n };\r\n\r\n window.addEventListener('storage', handleStorageChange);\r\n return () => window.removeEventListener('storage', handleStorageChange);\r\n }, [handleWebSocketEvent]);\r\n\r\n useEffect(() => {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { isLoading: isSaving },\r\n });\r\n }, [isSaving]);\r\n\r\n useEffect(() => {\r\n const error = sdkError || preferencesError || preferencesLoadError;\r\n if (error) {\r\n dispatch({\r\n type: 'SET_UI_STATE',\r\n payload: { error: error },\r\n });\r\n }\r\n }, [sdkError, preferencesError, preferencesLoadError]);\r\n\r\n if (!isInitialized && !sdkError) {\r\n return (\r\n <div\r\n className={`relative inline-block ${className}`}\r\n data-widget-size={size || 'small'}\r\n data-theme={theme}\r\n data-testid=\"notification-widget\"\r\n >\r\n <ComponentErrorBoundary componentName=\"BellComponent\">\r\n <BellComponent\r\n unreadCount={0}\r\n onClick={() => { }}\r\n size={size}\r\n disabled={true}\r\n />\r\n </ComponentErrorBoundary>\r\n </div>\r\n );\r\n }\r\n\r\n if (sdkError) {\r\n return (\r\n <div\r\n className={`relative inline-block ${className}`}\r\n data-widget-size={size || 'small'}\r\n data-theme={theme}\r\n data-testid=\"notification-widget\"\r\n >\r\n <ComponentErrorBoundary\r\n componentName=\"BellComponent\"\r\n fallback={\r\n <SDKConnectionFallback\r\n error={sdkError.message}\r\n onRetry={() => window.location.reload()}\r\n />\r\n }\r\n >\r\n <BellComponent\r\n unreadCount={0}\r\n onClick={() => { }}\r\n size={size}\r\n disabled={true}\r\n />\r\n </ComponentErrorBoundary>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={`relative inline-block ${className}`}\r\n data-widget-size={size || 'small'}\r\n data-theme={theme}\r\n data-testid=\"notification-widget\"\r\n >\r\n <ComponentErrorBoundary componentName=\"BellComponent\">\r\n <BellComponent\r\n unreadCount={state.unreadCount}\r\n onClick={handleBellClick}\r\n size={size}\r\n disabled={state.ui.isLoading}\r\n />\r\n </ComponentErrorBoundary>\r\n\r\n <ComponentErrorBoundary\r\n componentName=\"InboxPopover\"\r\n fallback={<LoadingFallback message=\"Unable to load notifications\" />}\r\n >\r\n <InboxPopover\r\n isOpen={state.ui.isOpen}\r\n onClose={handlePopoverClose}\r\n position={position}\r\n currentView={state.ui.currentView}\r\n onViewChange={handleViewChange}\r\n notifications={state.notifications}\r\n onNotificationAction={handleNotificationAction}\r\n preferences={state.preferences}\r\n onPreferenceChange={updatePreference}\r\n isPreferencesLoading={isSaving}\r\n />\r\n </ComponentErrorBoundary>\r\n </div>\r\n );\r\n};\r\n\r\nexport const NotificationWidget: React.FC<NotificationWidgetProps> = ({\r\n sdkConfig,\r\n ...props\r\n}) => {\r\n return (\r\n <NotificationWidgetErrorBoundary onError={props.onError}>\r\n <SDKProvider config={sdkConfig}>\r\n <NotificationWidgetInternal {...props} />\r\n </SDKProvider>\r\n </NotificationWidgetErrorBoundary>\r\n );\r\n};","export { NotificationWidget } from './components/NotificationWidget';\r\n\r\nexport { BellComponent } from './components/BellComponent';\r\nexport { InboxPopover } from './components/InboxPopover';\r\nexport { NotificationItem } from './components/NotificationItem';\r\nexport { PreferencesView } from './components/PreferencesView';\r\n\r\nexport { NotificationWidgetErrorBoundary } from './components/ErrorBoundary';\r\n\r\nexport type * from './types/core';\r\n\r\nexport type { Notification as SDKNotification, NotificationFilters } from '@edusight/notification-sdk';\r\n\r\nimport './styles/index.css';\r\n\r\nexport const VERSION = '3.0.0';\r\nexport const WIDGET_NAME = '@edusight/notification-widget';"],"names":["ErrorFallback","error","onRetry","jsxs","jsx","MdError","MdRefresh","NotificationWidgetErrorBoundary","Component","props","errorInfo","useNotificationsClient","usePreferencesSync","onPreferencesLoaded","onError","notificationClient","isLoading","setIsLoading","useState","setError","preferences","setPreferences","loadPreferences","useCallback","config","subscriberId","tenantId","environmentId","servicePreferences","mappedPreferences","workflowId","categoryPrefs","err","defaultPreferences","useEffect","useWorkflows","workflows","setWorkflows","loadWorkflows","mappedWorkflows","wf","SDKContext","createContext","useSDK","context","useContext","initialState","SDKProvider","children","sdkState","setSdkState","React","isMounted","existingSDK","client","NotificationClient","widgetReducer","state","action","n","newNotifications","updatedNotifications","filteredNotifications","NotificationWidgetInternal","position","size","theme","className","dispatch","useReducer","isInitialized","sdkError","websocketRef","useRef","handlePreferencesChange","handleWidgetError","preferencesLoadError","isWorkflowsLoading","updatePreference","isSaving","preferencesError","useLivePreferences","updatedSubscriptions","s","handleWebSocketEvent","event","notificationMapper","createNotificationMapper","wsPayload","mappedNotification","connectWebSocket","sdkConfig","fullUrl","socket","ioClient","payload","reason","attempt","disconnectWebSocket","handleBellClick","handlePopoverClose","handleViewChange","view","handleNotificationAction","id","coreNotifications","item","pollInterval","handleStorageChange","syncData","ComponentErrorBoundary","BellComponent","SDKConnectionFallback","LoadingFallback","InboxPopover","NotificationWidget","VERSION","WIDGET_NAME"],"mappings":"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"}