@edusight/notification-widget 1.0.36 → 1.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{components-DqQ0ehzG.js → components-CWbjrQKA.js} +129 -137
- package/dist/{components-DqQ0ehzG.js.map → components-CWbjrQKA.js.map} +1 -1
- package/dist/{components-D9Q1H53S.cjs → components-Cr9Sf7Cz.cjs} +9 -9
- package/dist/{components-D9Q1H53S.cjs.map → components-Cr9Sf7Cz.cjs.map} +1 -1
- package/dist/hooks-C6Z38jT_.cjs +2 -0
- package/dist/hooks-C6Z38jT_.cjs.map +1 -0
- package/dist/{hooks-C7dzVxIU.js → hooks-S0z2_-4B.js} +63 -50
- package/dist/hooks-S0z2_-4B.js.map +1 -0
- package/dist/index.cjs.js +2 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.esm.js +177 -156
- package/dist/index.esm.js.map +1 -1
- package/package.json +2 -2
- package/dist/hooks-C7dzVxIU.js.map +0 -1
- package/dist/hooks-kLhwdW29.cjs +0 -2
- package/dist/hooks-kLhwdW29.cjs.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const h=require("react"),D=()=>window.__notificationSDK?.client,_=({preferences:t,onPreferencesChange:f,onError:e})=>{const n=D(),[c,i]=h.useState(!1),[s,l]=h.useState(null),p=h.useRef(),S=h.useRef({}),j=h.useCallback((v,y)=>{try{l(null);const r={...t},o=v.split(".");let b=r;for(let a=0;a<o.length-1;a++)b[o[a]]===void 0&&(b[o[a]]={}),b=b[o[a]];b[o[o.length-1]]=y,f(r),S.current[v]=y,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:u,tenantId:g,environmentId:A}=a;if(!u||!g||!A)throw new Error("SubscriberId, TenantId or EnvironmentId not available in SDK configuration.");if(v.startsWith("deliverySchedule.")){const d={isEnabled:r.deliverySchedule.enabled||!1};r.deliverySchedule.weeklySchedule&&(d.weeklySchedule=r.deliverySchedule.weeklySchedule),await n.preferences.updateSchedule(g,u,d,A)}else{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(g,u,d)}S.current={},l(null)}catch(a){const u=a instanceof Error?a:new Error("Failed to save preferences");process.env.NODE_ENV,l(u),e?.(u)}finally{i(!1)}},500)}catch(r){const o=r instanceof Error?r:new Error("Failed to update preference");l(o),e?.(o),i(!1)}},[t,f,n,e]);return h.useEffect(()=>()=>{p.current&&clearTimeout(p.current)},[]),{updatePreference:j,isSaving:c,error:s}},E=t=>!(!t||typeof t!="object"||["notificationId","channel","renderedContent","read","archived"].filter(n=>!(n in t)).length>0||typeof t.channel!="string"||typeof t.read!="boolean"||typeof t.archived!="boolean"||typeof t.renderedContent!="object"||t.renderedContent===null),N=(t,f,e)=>({type:"custom",label:t.label,icon:void 0,handler:async()=>{try{if(t.url){const n=t.target||"_self";window.open(t.url,n)}t.markAsReadOnClick}catch(n){throw n}}}),w=()=>{const t=(e,n)=>{if(!e||typeof e!="object")return{subject:"",body:""};let c="",i="";return e.push?(c=e.push.title||"",i=e.push.body||""):e.email?(c=e.email.subject||"",i=e.email.html||e.email.text||""):e.in_app?(c=e.in_app.title||"",i=e.in_app.message||""):e.sms?(c="SMS",i=e.sms.message||""):n==="in_app"?(c=e.title||"",i=e.message||""):(c=e.title||e.subject||"",i=e.message||e.body||e.text||""),{subject:c,body:i}},f=(e,n,c)=>{if(!e)return[];const i=[];if(Array.isArray(e))return e.forEach(s=>{i.push(N(s,n||"",c))}),i;if(e.primary){const s=e.primary;i.push({type:"custom",label:s.label||"Primary Action",icon:void 0,handler:async l=>{s.url&&window.open(s.url,"_self")}})}if(e.secondary){const s=e.secondary;i.push({type:"custom",label:s.label||"Secondary Action",icon:void 0,handler:async l=>{s.url&&window.open(s.url,"_self")}})}return i};return{toWidgetNotification(e){const{subject:n,body:c}=t(e.renderedContent,e.channel);return{id:e.notificationId,subject:n||"Notification",body:c||"",isRead:e.read,isArchived:e.archived,timestamp:e.createdAt?new Date(e.createdAt):new Date,tags:[],actions:f(e.renderedContent?.actions||e.actions),metadata:{channel:e.channel,renderedContent:e.renderedContent}}},toWidgetNotificationFromWebSocket(e){if(!E(e)){const i=e?.renderedContent&&typeof e.renderedContent=="object"?e.renderedContent:{},{subject:s,body:l}=t(i,e?.channel);return{id:e?.notificationId||`notification-${Date.now()}`,subject:s||"Notification",body:l||"",isRead:e?.read||!1,isArchived:e?.archived||!1,timestamp:e?.createdAt?new Date(e.createdAt):new Date,tags:[],actions:[],metadata:{channel:e?.channel||"in_app",renderedContent:i}}}const{subject:n,body:c}=t(e.renderedContent,e.channel);return{id:e.notificationId,subject:n||"Notification",body:c||"",isRead:e.read||!1,isArchived:e.archived||!1,timestamp:e.createdAt?new Date(e.createdAt):new Date,tags:[],actions:f(e.renderedContent?.actions||e.actions,e.notificationId),metadata:{channel:e.channel,renderedContent:e.renderedContent}}},validateWebSocketPayload:E}};exports.createNotificationMapper=w;exports.useLivePreferences=_;
|
|
2
|
+
//# sourceMappingURL=hooks-C6Z38jT_.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-C6Z38jT_.cjs","sources":["../src/hooks/useLivePreferences.ts","../src/utils/notification-mapper.ts"],"sourcesContent":["import { useCallback, useRef, useState, useEffect } from 'react';\n\nimport { NotificationPreferences } from '../types/core';\n\nconst useNotificationsClient = () => {\n return (window as any).__notificationSDK?.client;\n};\n\nexport interface UseLivePreferencesProps {\n preferences: NotificationPreferences;\n onPreferencesChange: (preferences: NotificationPreferences) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface UseLivePreferencesResult {\n updatePreference: (path: string, value: any) => void;\n isSaving: boolean;\n error: Error | null;\n}\n\nexport const useLivePreferences = ({\n preferences,\n onPreferencesChange,\n onError,\n}: UseLivePreferencesProps): UseLivePreferencesResult => {\n const notificationClient = useNotificationsClient();\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const saveTimeoutRef = useRef<NodeJS.Timeout>();\n const pendingUpdatesRef = useRef<{ [key: string]: any }>({});\n\n const updatePreference = useCallback(\n (path: string, value: any) => {\n try {\n setError(null);\n\n const updatedPreferences = { ...preferences };\n const pathParts = path.split('.');\n\n let current: any = updatedPreferences;\n for (let i = 0; i < pathParts.length - 1; i++) {\n if (current[pathParts[i]] === undefined) {\n current[pathParts[i]] = {};\n }\n current = current[pathParts[i]];\n }\n current[pathParts[pathParts.length - 1]] = value;\n\n onPreferencesChange(updatedPreferences);\n\n pendingUpdatesRef.current[path] = value;\n\n if (saveTimeoutRef.current) {\n clearTimeout(saveTimeoutRef.current);\n }\n\n setIsSaving(true);\n\n saveTimeoutRef.current = setTimeout(async () => {\n try {\n if (!notificationClient) {\n throw new Error('Notification client not available');\n }\n\n const sdkConfig = (window as any).__notificationSDK?.config;\n\n if (!sdkConfig) {\n throw new Error('SDK configuration not available');\n }\n\n const { subscriberId, tenantId, environmentId } = sdkConfig;\n\n if (!subscriberId || !tenantId || !environmentId) {\n throw new Error(\n 'SubscriberId, TenantId or EnvironmentId not available in SDK configuration.',\n );\n }\n\n // Check if this is a schedule-related update\n const isScheduleUpdate = path.startsWith('deliverySchedule.');\n\n if (isScheduleUpdate) {\n // Handle schedule updates separately\n const schedulePayload: any = {\n isEnabled: updatedPreferences.deliverySchedule.enabled || false,\n };\n\n // Build weekly schedule\n if (updatedPreferences.deliverySchedule.weeklySchedule) {\n schedulePayload.weeklySchedule = updatedPreferences.deliverySchedule.weeklySchedule;\n }\n\n await notificationClient.preferences.updateSchedule(\n tenantId,\n subscriberId,\n schedulePayload,\n environmentId,\n );\n } else {\n // Handle global and subscription preferences\n const savePayload: any = {\n emailEnabled: updatedPreferences.channels.email,\n pushEnabled: updatedPreferences.channels.push,\n inAppEnabled: updatedPreferences.channels.inApp,\n smsEnabled: updatedPreferences.channels.sms,\n };\n\n if (updatedPreferences.subscriptions.length > 0) {\n savePayload.categories = {};\n updatedPreferences.subscriptions.forEach((sub) => {\n savePayload.categories[sub.workflowId] = {\n emailEnabled: sub.channels.email,\n pushEnabled: sub.channels.push,\n inAppEnabled: sub.channels.inApp,\n smsEnabled: sub.channels.sms,\n };\n });\n }\n\n await notificationClient.preferences.update(tenantId, subscriberId, savePayload);\n }\n\n pendingUpdatesRef.current = {};\n setError(null);\n } catch (err: any) {\n const error = err instanceof Error ? err : new Error('Failed to save preferences');\n\n if (process.env.NODE_ENV === 'development') {\n console.error('Failed to save preferences:', error);\n }\n\n setError(error);\n onError?.(error);\n } finally {\n setIsSaving(false);\n }\n }, 500);\n } catch (err: any) {\n const error = err instanceof Error ? err : new Error('Failed to update preference');\n setError(error);\n onError?.(error);\n setIsSaving(false);\n }\n },\n [preferences, onPreferencesChange, notificationClient, onError],\n );\n\n useEffect(() => {\n return () => {\n if (saveTimeoutRef.current) {\n clearTimeout(saveTimeoutRef.current);\n }\n };\n }, []);\n\n return {\n updatePreference,\n isSaving,\n error,\n };\n};\n","import type {\n RenderedNotificationItem,\n RenderedNotificationActionMap,\n NotificationAction as SDKNotificationAction,\n} from '@edusight/notification-sdk';\n\nimport type { Notification, NotificationAction } from '../types/core';\n\nexport type WebSocketNotificationReceivedPayload = RenderedNotificationItem;\n\nexport interface NotificationMapper {\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification;\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification;\n validateWebSocketPayload(payload: any): payload is WebSocketNotificationReceivedPayload;\n}\n\nconst validateWebSocketPayload = (\n payload: any,\n): payload is WebSocketNotificationReceivedPayload => {\n if (!payload || typeof payload !== 'object') {\n console.warn('Invalid WebSocket payload: not an object', payload);\n return false;\n }\n\n const requiredFields = ['notificationId', 'channel', 'renderedContent', 'read', 'archived'];\n const missingFields = requiredFields.filter((field) => !(field in payload));\n\n if (missingFields.length > 0) {\n console.warn('WebSocket payload missing required fields:', missingFields, payload);\n return false;\n }\n\n if (typeof payload.channel !== 'string') {\n console.warn('WebSocket payload channel is invalid', payload);\n return false;\n }\n\n if (typeof payload.read !== 'boolean' || typeof payload.archived !== 'boolean') {\n console.warn('WebSocket payload read/archived flags are invalid', payload);\n return false;\n }\n\n if (typeof payload.renderedContent !== 'object' || payload.renderedContent === null) {\n console.warn('WebSocket payload renderedContent is not an object', payload);\n return false;\n }\n\n return true;\n};\n\nconst mapSDKActionToWidgetAction = (\n sdkAction: SDKNotificationAction,\n notificationId: string,\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>,\n): NotificationAction => {\n return {\n type: 'custom',\n label: sdkAction.label,\n icon: undefined,\n handler: async () => {\n try {\n if (onActionExecute) {\n await onActionExecute(sdkAction.id, notificationId);\n }\n\n if (sdkAction.url) {\n const target = sdkAction.target || '_self';\n window.open(sdkAction.url, target);\n }\n\n if (sdkAction.markAsReadOnClick) {\n // This will be handled by the widget's action handler\n }\n } catch (error) {\n console.error('Error executing action:', error);\n throw error;\n }\n },\n };\n};\n\nexport const createNotificationMapper = (): NotificationMapper => {\n const extractSubjectAndBody = (\n renderedContent: Record<string, any>,\n channel?: string,\n ): { subject: string; body: string } => {\n if (!renderedContent || typeof renderedContent !== 'object') {\n return { subject: '', body: '' };\n }\n\n let subject = '';\n let body = '';\n\n if (renderedContent.push) {\n subject = renderedContent.push.title || '';\n body = renderedContent.push.body || '';\n } else if (renderedContent.email) {\n subject = renderedContent.email.subject || '';\n body = renderedContent.email.html || renderedContent.email.text || '';\n } else if (renderedContent.in_app) {\n subject = renderedContent.in_app.title || '';\n body = renderedContent.in_app.message || '';\n } else if (renderedContent.sms) {\n subject = 'SMS';\n body = renderedContent.sms.message || '';\n } else if (channel === 'in_app') {\n subject = renderedContent.title || '';\n body = renderedContent.message || '';\n } else {\n subject = renderedContent.title || renderedContent.subject || '';\n body = renderedContent.message || renderedContent.body || renderedContent.text || '';\n }\n\n return { subject, body };\n };\n\n const mapActionsToNotificationActions = (\n actions?: RenderedNotificationActionMap | SDKNotificationAction[],\n notificationId?: string,\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>,\n ): NotificationAction[] => {\n if (!actions) return [];\n\n const result: NotificationAction[] = [];\n\n if (Array.isArray(actions)) {\n actions.forEach((sdkAction) => {\n result.push(mapSDKActionToWidgetAction(sdkAction, notificationId || '', onActionExecute));\n });\n return result;\n }\n\n if (actions.primary) {\n const primaryAction = actions.primary;\n result.push({\n type: 'custom',\n label: primaryAction.label || 'Primary Action',\n icon: undefined,\n handler: async (notificationId: string) => {\n if (primaryAction.url) {\n window.open(primaryAction.url, '_self');\n }\n if (onActionExecute) {\n await onActionExecute('primary', notificationId);\n }\n },\n });\n }\n\n if (actions.secondary) {\n const secondaryAction = actions.secondary;\n result.push({\n type: 'custom',\n label: secondaryAction.label || 'Secondary Action',\n icon: undefined,\n handler: async (notificationId: string) => {\n if (secondaryAction.url) {\n window.open(secondaryAction.url, '_self');\n }\n if (onActionExecute) {\n await onActionExecute('secondary', notificationId);\n }\n },\n });\n }\n\n return result;\n };\n\n return {\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification {\n const { subject, body } = extractSubjectAndBody(\n renderedItem.renderedContent,\n renderedItem.channel,\n );\n\n return {\n id: renderedItem.notificationId,\n subject: subject || 'Notification',\n body: body || '',\n isRead: renderedItem.read,\n isArchived: renderedItem.archived,\n timestamp: renderedItem.createdAt ? new Date(renderedItem.createdAt) : new Date(),\n tags: [],\n actions: mapActionsToNotificationActions(\n renderedItem.renderedContent?.actions || renderedItem.actions,\n ),\n metadata: {\n channel: renderedItem.channel,\n renderedContent: renderedItem.renderedContent,\n },\n };\n },\n\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification {\n if (!validateWebSocketPayload(wsPayload)) {\n console.error('Invalid WebSocket payload structure, using fallback', wsPayload);\n const fallbackRenderedContent =\n wsPayload?.renderedContent && typeof wsPayload.renderedContent === 'object'\n ? wsPayload.renderedContent\n : {};\n const { subject, body } = extractSubjectAndBody(\n fallbackRenderedContent,\n wsPayload?.channel,\n );\n return {\n id: wsPayload?.notificationId || `notification-${Date.now()}`,\n subject: subject || 'Notification',\n body: body || '',\n isRead: wsPayload?.read || false,\n isArchived: wsPayload?.archived || false,\n timestamp: wsPayload?.createdAt ? new Date(wsPayload.createdAt) : new Date(),\n tags: [],\n actions: [],\n metadata: {\n channel: wsPayload?.channel || 'in_app',\n renderedContent: fallbackRenderedContent,\n },\n };\n }\n\n const { subject, body } = extractSubjectAndBody(wsPayload.renderedContent, wsPayload.channel);\n\n return {\n id: wsPayload.notificationId,\n subject: subject || 'Notification',\n body: body || '',\n isRead: wsPayload.read || false,\n isArchived: wsPayload.archived || false,\n timestamp: wsPayload.createdAt ? new Date(wsPayload.createdAt) : new Date(),\n tags: [],\n actions: mapActionsToNotificationActions(\n wsPayload.renderedContent?.actions || wsPayload.actions,\n wsPayload.notificationId,\n ),\n metadata: {\n channel: wsPayload.channel,\n renderedContent: (wsPayload as any).renderedContent,\n },\n };\n },\n\n validateWebSocketPayload,\n };\n};\n"],"names":["useNotificationsClient","useLivePreferences","preferences","onPreferencesChange","onError","notificationClient","isSaving","setIsSaving","useState","error","setError","saveTimeoutRef","useRef","pendingUpdatesRef","updatePreference","useCallback","path","value","updatedPreferences","pathParts","current","i","sdkConfig","subscriberId","tenantId","environmentId","schedulePayload","savePayload","sub","err","useEffect","validateWebSocketPayload","payload","field","mapSDKActionToWidgetAction","sdkAction","notificationId","onActionExecute","target","createNotificationMapper","extractSubjectAndBody","renderedContent","channel","subject","body","mapActionsToNotificationActions","actions","result","primaryAction","secondaryAction","renderedItem","wsPayload","fallbackRenderedContent"],"mappings":"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"}
|
|
@@ -1,65 +1,78 @@
|
|
|
1
|
-
import { useState as
|
|
2
|
-
const
|
|
1
|
+
import { useState as A, useRef as E, useCallback as _, useEffect as w } from "react";
|
|
2
|
+
const N = () => window.__notificationSDK?.client, T = ({
|
|
3
3
|
preferences: t,
|
|
4
4
|
onPreferencesChange: f,
|
|
5
5
|
onError: e
|
|
6
6
|
}) => {
|
|
7
|
-
const n =
|
|
8
|
-
(
|
|
7
|
+
const n = N(), [c, i] = A(!1), [a, l] = A(null), h = E(), g = E({}), D = _(
|
|
8
|
+
(m, S) => {
|
|
9
9
|
try {
|
|
10
10
|
l(null);
|
|
11
|
-
const
|
|
12
|
-
let p =
|
|
13
|
-
for (let
|
|
14
|
-
p[s
|
|
15
|
-
p[
|
|
11
|
+
const r = { ...t }, o = m.split(".");
|
|
12
|
+
let p = r;
|
|
13
|
+
for (let s = 0; s < o.length - 1; s++)
|
|
14
|
+
p[o[s]] === void 0 && (p[o[s]] = {}), p = p[o[s]];
|
|
15
|
+
p[o[o.length - 1]] = S, f(r), g.current[m] = S, h.current && clearTimeout(h.current), i(!0), h.current = setTimeout(async () => {
|
|
16
16
|
try {
|
|
17
17
|
if (!n)
|
|
18
18
|
throw new Error("Notification client not available");
|
|
19
|
-
const
|
|
20
|
-
if (!
|
|
19
|
+
const s = window.__notificationSDK?.config;
|
|
20
|
+
if (!s)
|
|
21
21
|
throw new Error("SDK configuration not available");
|
|
22
|
-
const { subscriberId:
|
|
23
|
-
if (!
|
|
22
|
+
const { subscriberId: u, tenantId: v, environmentId: y } = s;
|
|
23
|
+
if (!u || !v || !y)
|
|
24
24
|
throw new Error(
|
|
25
25
|
"SubscriberId, TenantId or EnvironmentId not available in SDK configuration."
|
|
26
26
|
);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
inAppEnabled: o.channels.inApp,
|
|
31
|
-
smsEnabled: o.channels.sms
|
|
32
|
-
};
|
|
33
|
-
o.subscriptions.length > 0 && (d.categories = {}, o.subscriptions.forEach((b) => {
|
|
34
|
-
d.categories[b.workflowId] = {
|
|
35
|
-
emailEnabled: b.channels.email,
|
|
36
|
-
pushEnabled: b.channels.push,
|
|
37
|
-
inAppEnabled: b.channels.inApp,
|
|
38
|
-
smsEnabled: b.channels.sms
|
|
27
|
+
if (m.startsWith("deliverySchedule.")) {
|
|
28
|
+
const d = {
|
|
29
|
+
isEnabled: r.deliverySchedule.enabled || !1
|
|
39
30
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
r.deliverySchedule.weeklySchedule && (d.weeklySchedule = r.deliverySchedule.weeklySchedule), await n.preferences.updateSchedule(
|
|
32
|
+
v,
|
|
33
|
+
u,
|
|
34
|
+
d,
|
|
35
|
+
y
|
|
36
|
+
);
|
|
37
|
+
} else {
|
|
38
|
+
const d = {
|
|
39
|
+
emailEnabled: r.channels.email,
|
|
40
|
+
pushEnabled: r.channels.push,
|
|
41
|
+
inAppEnabled: r.channels.inApp,
|
|
42
|
+
smsEnabled: r.channels.sms
|
|
43
|
+
};
|
|
44
|
+
r.subscriptions.length > 0 && (d.categories = {}, r.subscriptions.forEach((b) => {
|
|
45
|
+
d.categories[b.workflowId] = {
|
|
46
|
+
emailEnabled: b.channels.email,
|
|
47
|
+
pushEnabled: b.channels.push,
|
|
48
|
+
inAppEnabled: b.channels.inApp,
|
|
49
|
+
smsEnabled: b.channels.sms
|
|
50
|
+
};
|
|
51
|
+
})), await n.preferences.update(v, u, d);
|
|
52
|
+
}
|
|
53
|
+
g.current = {}, l(null);
|
|
54
|
+
} catch (s) {
|
|
55
|
+
const u = s instanceof Error ? s : new Error("Failed to save preferences");
|
|
56
|
+
process.env.NODE_ENV, l(u), e?.(u);
|
|
44
57
|
} finally {
|
|
45
58
|
i(!1);
|
|
46
59
|
}
|
|
47
60
|
}, 500);
|
|
48
|
-
} catch (
|
|
49
|
-
const
|
|
50
|
-
l(
|
|
61
|
+
} catch (r) {
|
|
62
|
+
const o = r instanceof Error ? r : new Error("Failed to update preference");
|
|
63
|
+
l(o), e?.(o), i(!1);
|
|
51
64
|
}
|
|
52
65
|
},
|
|
53
66
|
[t, f, n, e]
|
|
54
67
|
);
|
|
55
|
-
return
|
|
56
|
-
|
|
68
|
+
return w(() => () => {
|
|
69
|
+
h.current && clearTimeout(h.current);
|
|
57
70
|
}, []), {
|
|
58
|
-
updatePreference:
|
|
71
|
+
updatePreference: D,
|
|
59
72
|
isSaving: c,
|
|
60
|
-
error:
|
|
73
|
+
error: a
|
|
61
74
|
};
|
|
62
|
-
},
|
|
75
|
+
}, 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), R = (t, f, e) => ({
|
|
63
76
|
type: "custom",
|
|
64
77
|
label: t.label,
|
|
65
78
|
icon: void 0,
|
|
@@ -84,28 +97,28 @@ const R = () => window.__notificationSDK?.client, T = ({
|
|
|
84
97
|
if (!e) return [];
|
|
85
98
|
const i = [];
|
|
86
99
|
if (Array.isArray(e))
|
|
87
|
-
return e.forEach((
|
|
88
|
-
i.push(
|
|
100
|
+
return e.forEach((a) => {
|
|
101
|
+
i.push(R(a, n || "", c));
|
|
89
102
|
}), i;
|
|
90
103
|
if (e.primary) {
|
|
91
|
-
const
|
|
104
|
+
const a = e.primary;
|
|
92
105
|
i.push({
|
|
93
106
|
type: "custom",
|
|
94
|
-
label:
|
|
107
|
+
label: a.label || "Primary Action",
|
|
95
108
|
icon: void 0,
|
|
96
109
|
handler: async (l) => {
|
|
97
|
-
|
|
110
|
+
a.url && window.open(a.url, "_self");
|
|
98
111
|
}
|
|
99
112
|
});
|
|
100
113
|
}
|
|
101
114
|
if (e.secondary) {
|
|
102
|
-
const
|
|
115
|
+
const a = e.secondary;
|
|
103
116
|
i.push({
|
|
104
117
|
type: "custom",
|
|
105
|
-
label:
|
|
118
|
+
label: a.label || "Secondary Action",
|
|
106
119
|
icon: void 0,
|
|
107
120
|
handler: async (l) => {
|
|
108
|
-
|
|
121
|
+
a.url && window.open(a.url, "_self");
|
|
109
122
|
}
|
|
110
123
|
});
|
|
111
124
|
}
|
|
@@ -135,14 +148,14 @@ const R = () => window.__notificationSDK?.client, T = ({
|
|
|
135
148
|
};
|
|
136
149
|
},
|
|
137
150
|
toWidgetNotificationFromWebSocket(e) {
|
|
138
|
-
if (!
|
|
139
|
-
const i = e?.renderedContent && typeof e.renderedContent == "object" ? e.renderedContent : {}, { subject:
|
|
151
|
+
if (!j(e)) {
|
|
152
|
+
const i = e?.renderedContent && typeof e.renderedContent == "object" ? e.renderedContent : {}, { subject: a, body: l } = t(
|
|
140
153
|
i,
|
|
141
154
|
e?.channel
|
|
142
155
|
);
|
|
143
156
|
return {
|
|
144
157
|
id: e?.notificationId || `notification-${Date.now()}`,
|
|
145
|
-
subject:
|
|
158
|
+
subject: a || "Notification",
|
|
146
159
|
body: l || "",
|
|
147
160
|
isRead: e?.read || !1,
|
|
148
161
|
isArchived: e?.archived || !1,
|
|
@@ -174,11 +187,11 @@ const R = () => window.__notificationSDK?.client, T = ({
|
|
|
174
187
|
}
|
|
175
188
|
};
|
|
176
189
|
},
|
|
177
|
-
validateWebSocketPayload:
|
|
190
|
+
validateWebSocketPayload: j
|
|
178
191
|
};
|
|
179
192
|
};
|
|
180
193
|
export {
|
|
181
194
|
I as c,
|
|
182
195
|
T as u
|
|
183
196
|
};
|
|
184
|
-
//# sourceMappingURL=hooks-
|
|
197
|
+
//# sourceMappingURL=hooks-S0z2_-4B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-S0z2_-4B.js","sources":["../src/hooks/useLivePreferences.ts","../src/utils/notification-mapper.ts"],"sourcesContent":["import { useCallback, useRef, useState, useEffect } from 'react';\n\nimport { NotificationPreferences } from '../types/core';\n\nconst useNotificationsClient = () => {\n return (window as any).__notificationSDK?.client;\n};\n\nexport interface UseLivePreferencesProps {\n preferences: NotificationPreferences;\n onPreferencesChange: (preferences: NotificationPreferences) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface UseLivePreferencesResult {\n updatePreference: (path: string, value: any) => void;\n isSaving: boolean;\n error: Error | null;\n}\n\nexport const useLivePreferences = ({\n preferences,\n onPreferencesChange,\n onError,\n}: UseLivePreferencesProps): UseLivePreferencesResult => {\n const notificationClient = useNotificationsClient();\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const saveTimeoutRef = useRef<NodeJS.Timeout>();\n const pendingUpdatesRef = useRef<{ [key: string]: any }>({});\n\n const updatePreference = useCallback(\n (path: string, value: any) => {\n try {\n setError(null);\n\n const updatedPreferences = { ...preferences };\n const pathParts = path.split('.');\n\n let current: any = updatedPreferences;\n for (let i = 0; i < pathParts.length - 1; i++) {\n if (current[pathParts[i]] === undefined) {\n current[pathParts[i]] = {};\n }\n current = current[pathParts[i]];\n }\n current[pathParts[pathParts.length - 1]] = value;\n\n onPreferencesChange(updatedPreferences);\n\n pendingUpdatesRef.current[path] = value;\n\n if (saveTimeoutRef.current) {\n clearTimeout(saveTimeoutRef.current);\n }\n\n setIsSaving(true);\n\n saveTimeoutRef.current = setTimeout(async () => {\n try {\n if (!notificationClient) {\n throw new Error('Notification client not available');\n }\n\n const sdkConfig = (window as any).__notificationSDK?.config;\n\n if (!sdkConfig) {\n throw new Error('SDK configuration not available');\n }\n\n const { subscriberId, tenantId, environmentId } = sdkConfig;\n\n if (!subscriberId || !tenantId || !environmentId) {\n throw new Error(\n 'SubscriberId, TenantId or EnvironmentId not available in SDK configuration.',\n );\n }\n\n // Check if this is a schedule-related update\n const isScheduleUpdate = path.startsWith('deliverySchedule.');\n\n if (isScheduleUpdate) {\n // Handle schedule updates separately\n const schedulePayload: any = {\n isEnabled: updatedPreferences.deliverySchedule.enabled || false,\n };\n\n // Build weekly schedule\n if (updatedPreferences.deliverySchedule.weeklySchedule) {\n schedulePayload.weeklySchedule = updatedPreferences.deliverySchedule.weeklySchedule;\n }\n\n await notificationClient.preferences.updateSchedule(\n tenantId,\n subscriberId,\n schedulePayload,\n environmentId,\n );\n } else {\n // Handle global and subscription preferences\n const savePayload: any = {\n emailEnabled: updatedPreferences.channels.email,\n pushEnabled: updatedPreferences.channels.push,\n inAppEnabled: updatedPreferences.channels.inApp,\n smsEnabled: updatedPreferences.channels.sms,\n };\n\n if (updatedPreferences.subscriptions.length > 0) {\n savePayload.categories = {};\n updatedPreferences.subscriptions.forEach((sub) => {\n savePayload.categories[sub.workflowId] = {\n emailEnabled: sub.channels.email,\n pushEnabled: sub.channels.push,\n inAppEnabled: sub.channels.inApp,\n smsEnabled: sub.channels.sms,\n };\n });\n }\n\n await notificationClient.preferences.update(tenantId, subscriberId, savePayload);\n }\n\n pendingUpdatesRef.current = {};\n setError(null);\n } catch (err: any) {\n const error = err instanceof Error ? err : new Error('Failed to save preferences');\n\n if (process.env.NODE_ENV === 'development') {\n console.error('Failed to save preferences:', error);\n }\n\n setError(error);\n onError?.(error);\n } finally {\n setIsSaving(false);\n }\n }, 500);\n } catch (err: any) {\n const error = err instanceof Error ? err : new Error('Failed to update preference');\n setError(error);\n onError?.(error);\n setIsSaving(false);\n }\n },\n [preferences, onPreferencesChange, notificationClient, onError],\n );\n\n useEffect(() => {\n return () => {\n if (saveTimeoutRef.current) {\n clearTimeout(saveTimeoutRef.current);\n }\n };\n }, []);\n\n return {\n updatePreference,\n isSaving,\n error,\n };\n};\n","import type {\n RenderedNotificationItem,\n RenderedNotificationActionMap,\n NotificationAction as SDKNotificationAction,\n} from '@edusight/notification-sdk';\n\nimport type { Notification, NotificationAction } from '../types/core';\n\nexport type WebSocketNotificationReceivedPayload = RenderedNotificationItem;\n\nexport interface NotificationMapper {\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification;\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification;\n validateWebSocketPayload(payload: any): payload is WebSocketNotificationReceivedPayload;\n}\n\nconst validateWebSocketPayload = (\n payload: any,\n): payload is WebSocketNotificationReceivedPayload => {\n if (!payload || typeof payload !== 'object') {\n console.warn('Invalid WebSocket payload: not an object', payload);\n return false;\n }\n\n const requiredFields = ['notificationId', 'channel', 'renderedContent', 'read', 'archived'];\n const missingFields = requiredFields.filter((field) => !(field in payload));\n\n if (missingFields.length > 0) {\n console.warn('WebSocket payload missing required fields:', missingFields, payload);\n return false;\n }\n\n if (typeof payload.channel !== 'string') {\n console.warn('WebSocket payload channel is invalid', payload);\n return false;\n }\n\n if (typeof payload.read !== 'boolean' || typeof payload.archived !== 'boolean') {\n console.warn('WebSocket payload read/archived flags are invalid', payload);\n return false;\n }\n\n if (typeof payload.renderedContent !== 'object' || payload.renderedContent === null) {\n console.warn('WebSocket payload renderedContent is not an object', payload);\n return false;\n }\n\n return true;\n};\n\nconst mapSDKActionToWidgetAction = (\n sdkAction: SDKNotificationAction,\n notificationId: string,\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>,\n): NotificationAction => {\n return {\n type: 'custom',\n label: sdkAction.label,\n icon: undefined,\n handler: async () => {\n try {\n if (onActionExecute) {\n await onActionExecute(sdkAction.id, notificationId);\n }\n\n if (sdkAction.url) {\n const target = sdkAction.target || '_self';\n window.open(sdkAction.url, target);\n }\n\n if (sdkAction.markAsReadOnClick) {\n // This will be handled by the widget's action handler\n }\n } catch (error) {\n console.error('Error executing action:', error);\n throw error;\n }\n },\n };\n};\n\nexport const createNotificationMapper = (): NotificationMapper => {\n const extractSubjectAndBody = (\n renderedContent: Record<string, any>,\n channel?: string,\n ): { subject: string; body: string } => {\n if (!renderedContent || typeof renderedContent !== 'object') {\n return { subject: '', body: '' };\n }\n\n let subject = '';\n let body = '';\n\n if (renderedContent.push) {\n subject = renderedContent.push.title || '';\n body = renderedContent.push.body || '';\n } else if (renderedContent.email) {\n subject = renderedContent.email.subject || '';\n body = renderedContent.email.html || renderedContent.email.text || '';\n } else if (renderedContent.in_app) {\n subject = renderedContent.in_app.title || '';\n body = renderedContent.in_app.message || '';\n } else if (renderedContent.sms) {\n subject = 'SMS';\n body = renderedContent.sms.message || '';\n } else if (channel === 'in_app') {\n subject = renderedContent.title || '';\n body = renderedContent.message || '';\n } else {\n subject = renderedContent.title || renderedContent.subject || '';\n body = renderedContent.message || renderedContent.body || renderedContent.text || '';\n }\n\n return { subject, body };\n };\n\n const mapActionsToNotificationActions = (\n actions?: RenderedNotificationActionMap | SDKNotificationAction[],\n notificationId?: string,\n onActionExecute?: (actionId: string, notificationId: string) => Promise<void>,\n ): NotificationAction[] => {\n if (!actions) return [];\n\n const result: NotificationAction[] = [];\n\n if (Array.isArray(actions)) {\n actions.forEach((sdkAction) => {\n result.push(mapSDKActionToWidgetAction(sdkAction, notificationId || '', onActionExecute));\n });\n return result;\n }\n\n if (actions.primary) {\n const primaryAction = actions.primary;\n result.push({\n type: 'custom',\n label: primaryAction.label || 'Primary Action',\n icon: undefined,\n handler: async (notificationId: string) => {\n if (primaryAction.url) {\n window.open(primaryAction.url, '_self');\n }\n if (onActionExecute) {\n await onActionExecute('primary', notificationId);\n }\n },\n });\n }\n\n if (actions.secondary) {\n const secondaryAction = actions.secondary;\n result.push({\n type: 'custom',\n label: secondaryAction.label || 'Secondary Action',\n icon: undefined,\n handler: async (notificationId: string) => {\n if (secondaryAction.url) {\n window.open(secondaryAction.url, '_self');\n }\n if (onActionExecute) {\n await onActionExecute('secondary', notificationId);\n }\n },\n });\n }\n\n return result;\n };\n\n return {\n toWidgetNotification(renderedItem: RenderedNotificationItem): Notification {\n const { subject, body } = extractSubjectAndBody(\n renderedItem.renderedContent,\n renderedItem.channel,\n );\n\n return {\n id: renderedItem.notificationId,\n subject: subject || 'Notification',\n body: body || '',\n isRead: renderedItem.read,\n isArchived: renderedItem.archived,\n timestamp: renderedItem.createdAt ? new Date(renderedItem.createdAt) : new Date(),\n tags: [],\n actions: mapActionsToNotificationActions(\n renderedItem.renderedContent?.actions || renderedItem.actions,\n ),\n metadata: {\n channel: renderedItem.channel,\n renderedContent: renderedItem.renderedContent,\n },\n };\n },\n\n toWidgetNotificationFromWebSocket(wsPayload: any): Notification {\n if (!validateWebSocketPayload(wsPayload)) {\n console.error('Invalid WebSocket payload structure, using fallback', wsPayload);\n const fallbackRenderedContent =\n wsPayload?.renderedContent && typeof wsPayload.renderedContent === 'object'\n ? wsPayload.renderedContent\n : {};\n const { subject, body } = extractSubjectAndBody(\n fallbackRenderedContent,\n wsPayload?.channel,\n );\n return {\n id: wsPayload?.notificationId || `notification-${Date.now()}`,\n subject: subject || 'Notification',\n body: body || '',\n isRead: wsPayload?.read || false,\n isArchived: wsPayload?.archived || false,\n timestamp: wsPayload?.createdAt ? new Date(wsPayload.createdAt) : new Date(),\n tags: [],\n actions: [],\n metadata: {\n channel: wsPayload?.channel || 'in_app',\n renderedContent: fallbackRenderedContent,\n },\n };\n }\n\n const { subject, body } = extractSubjectAndBody(wsPayload.renderedContent, wsPayload.channel);\n\n return {\n id: wsPayload.notificationId,\n subject: subject || 'Notification',\n body: body || '',\n isRead: wsPayload.read || false,\n isArchived: wsPayload.archived || false,\n timestamp: wsPayload.createdAt ? new Date(wsPayload.createdAt) : new Date(),\n tags: [],\n actions: mapActionsToNotificationActions(\n wsPayload.renderedContent?.actions || wsPayload.actions,\n wsPayload.notificationId,\n ),\n metadata: {\n channel: wsPayload.channel,\n renderedContent: (wsPayload as any).renderedContent,\n },\n };\n },\n\n validateWebSocketPayload,\n };\n};\n"],"names":["useNotificationsClient","useLivePreferences","preferences","onPreferencesChange","onError","notificationClient","isSaving","setIsSaving","useState","error","setError","saveTimeoutRef","useRef","pendingUpdatesRef","updatePreference","useCallback","path","value","updatedPreferences","pathParts","current","i","sdkConfig","subscriberId","tenantId","environmentId","schedulePayload","savePayload","sub","err","useEffect","validateWebSocketPayload","payload","field","mapSDKActionToWidgetAction","sdkAction","notificationId","onActionExecute","target","createNotificationMapper","extractSubjectAndBody","renderedContent","channel","subject","body","mapActionsToNotificationActions","actions","result","primaryAction","secondaryAction","renderedItem","wsPayload","fallbackRenderedContent"],"mappings":";AAIA,MAAMA,IAAyB,MACrB,OAAe,mBAAmB,QAe/BC,IAAqB,CAAC;AAAA,EACjC,aAAAC;AAAA,EACA,qBAAAC;AAAA,EACA,SAAAC;AACF,MAAyD;AACvD,QAAMC,IAAqBL,EAAA,GACrB,CAACM,GAAUC,CAAW,IAAIC,EAAS,EAAK,GACxC,CAACC,GAAOC,CAAQ,IAAIF,EAAuB,IAAI,GAC/CG,IAAiBC,EAAA,GACjBC,IAAoBD,EAA+B,EAAE,GAErDE,IAAmBC;AAAA,IACvB,CAACC,GAAcC,MAAe;AAC5B,UAAI;AACF,QAAAP,EAAS,IAAI;AAEb,cAAMQ,IAAqB,EAAE,GAAGhB,EAAA,GAC1BiB,IAAYH,EAAK,MAAM,GAAG;AAEhC,YAAII,IAAeF;AACnB,iBAASG,IAAI,GAAGA,IAAIF,EAAU,SAAS,GAAGE;AACxC,UAAID,EAAQD,EAAUE,CAAC,CAAC,MAAM,WAC5BD,EAAQD,EAAUE,CAAC,CAAC,IAAI,CAAA,IAE1BD,IAAUA,EAAQD,EAAUE,CAAC,CAAC;AAEhC,QAAAD,EAAQD,EAAUA,EAAU,SAAS,CAAC,CAAC,IAAIF,GAE3Cd,EAAoBe,CAAkB,GAEtCL,EAAkB,QAAQG,CAAI,IAAIC,GAE9BN,EAAe,WACjB,aAAaA,EAAe,OAAO,GAGrCJ,EAAY,EAAI,GAEhBI,EAAe,UAAU,WAAW,YAAY;AAC9C,cAAI;AACF,gBAAI,CAACN;AACH,oBAAM,IAAI,MAAM,mCAAmC;AAGrD,kBAAMiB,IAAa,OAAe,mBAAmB;AAErD,gBAAI,CAACA;AACH,oBAAM,IAAI,MAAM,iCAAiC;AAGnD,kBAAM,EAAE,cAAAC,GAAc,UAAAC,GAAU,eAAAC,EAAA,IAAkBH;AAElD,gBAAI,CAACC,KAAgB,CAACC,KAAY,CAACC;AACjC,oBAAM,IAAI;AAAA,gBACR;AAAA,cAAA;AAOJ,gBAFyBT,EAAK,WAAW,mBAAmB,GAEtC;AAEpB,oBAAMU,IAAuB;AAAA,gBAC3B,WAAWR,EAAmB,iBAAiB,WAAW;AAAA,cAAA;AAI5D,cAAIA,EAAmB,iBAAiB,mBACtCQ,EAAgB,iBAAiBR,EAAmB,iBAAiB,iBAGvE,MAAMb,EAAmB,YAAY;AAAA,gBACnCmB;AAAA,gBACAD;AAAA,gBACAG;AAAA,gBACAD;AAAA,cAAA;AAAA,YAEJ,OAAO;AAEL,oBAAME,IAAmB;AAAA,gBACvB,cAAcT,EAAmB,SAAS;AAAA,gBAC1C,aAAaA,EAAmB,SAAS;AAAA,gBACzC,cAAcA,EAAmB,SAAS;AAAA,gBAC1C,YAAYA,EAAmB,SAAS;AAAA,cAAA;AAG1C,cAAIA,EAAmB,cAAc,SAAS,MAC5CS,EAAY,aAAa,CAAA,GACzBT,EAAmB,cAAc,QAAQ,CAACU,MAAQ;AAChD,gBAAAD,EAAY,WAAWC,EAAI,UAAU,IAAI;AAAA,kBACvC,cAAcA,EAAI,SAAS;AAAA,kBAC3B,aAAaA,EAAI,SAAS;AAAA,kBAC1B,cAAcA,EAAI,SAAS;AAAA,kBAC3B,YAAYA,EAAI,SAAS;AAAA,gBAAA;AAAA,cAE7B,CAAC,IAGH,MAAMvB,EAAmB,YAAY,OAAOmB,GAAUD,GAAcI,CAAW;AAAA,YACjF;AAEA,YAAAd,EAAkB,UAAU,CAAA,GAC5BH,EAAS,IAAI;AAAA,UACf,SAASmB,GAAU;AACjB,kBAAMpB,IAAQoB,aAAe,QAAQA,IAAM,IAAI,MAAM,4BAA4B;AAEjF,YAAI,QAAQ,IAAI,UAIhBnB,EAASD,CAAK,GACdL,IAAUK,CAAK;AAAA,UACjB,UAAA;AACE,YAAAF,EAAY,EAAK;AAAA,UACnB;AAAA,QACF,GAAG,GAAG;AAAA,MACR,SAASsB,GAAU;AACjB,cAAMpB,IAAQoB,aAAe,QAAQA,IAAM,IAAI,MAAM,6BAA6B;AAClF,QAAAnB,EAASD,CAAK,GACdL,IAAUK,CAAK,GACfF,EAAY,EAAK;AAAA,MACnB;AAAA,IACF;AAAA,IACA,CAACL,GAAaC,GAAqBE,GAAoBD,CAAO;AAAA,EAAA;AAGhE,SAAA0B,EAAU,MACD,MAAM;AACX,IAAInB,EAAe,WACjB,aAAaA,EAAe,OAAO;AAAA,EAEvC,GACC,CAAA,CAAE,GAEE;AAAA,IACL,kBAAAG;AAAA,IACA,UAAAR;AAAA,IACA,OAAAG;AAAA,EAAA;AAEJ,GChJMsB,IAA2B,CAC/BC,MAEI,GAACA,KAAW,OAAOA,KAAY,YAKZ,CAAC,kBAAkB,WAAW,mBAAmB,QAAQ,UAAU,EACrD,OAAO,CAACC,MAAU,EAAEA,KAASD,EAAQ,EAExD,SAAS,KAKvB,OAAOA,EAAQ,WAAY,YAK3B,OAAOA,EAAQ,QAAS,aAAa,OAAOA,EAAQ,YAAa,aAKjE,OAAOA,EAAQ,mBAAoB,YAAYA,EAAQ,oBAAoB,OAQ3EE,IAA6B,CACjCC,GACAC,GACAC,OAEO;AAAA,EACL,MAAM;AAAA,EACN,OAAOF,EAAU;AAAA,EACjB,MAAM;AAAA,EACN,SAAS,YAAY;AACnB,QAAI;AAKF,UAAIA,EAAU,KAAK;AACjB,cAAMG,IAASH,EAAU,UAAU;AACnC,eAAO,KAAKA,EAAU,KAAKG,CAAM;AAAA,MACnC;AAEA,MAAIH,EAAU;AAAA,IAGhB,SAAS1B,GAAO;AAEd,YAAMA;AAAA,IACR;AAAA,EACF;AAAA,IAIS8B,IAA2B,MAA0B;AAChE,QAAMC,IAAwB,CAC5BC,GACAC,MACsC;AACtC,QAAI,CAACD,KAAmB,OAAOA,KAAoB;AACjD,aAAO,EAAE,SAAS,IAAI,MAAM,GAAA;AAG9B,QAAIE,IAAU,IACVC,IAAO;AAEX,WAAIH,EAAgB,QAClBE,IAAUF,EAAgB,KAAK,SAAS,IACxCG,IAAOH,EAAgB,KAAK,QAAQ,MAC3BA,EAAgB,SACzBE,IAAUF,EAAgB,MAAM,WAAW,IAC3CG,IAAOH,EAAgB,MAAM,QAAQA,EAAgB,MAAM,QAAQ,MAC1DA,EAAgB,UACzBE,IAAUF,EAAgB,OAAO,SAAS,IAC1CG,IAAOH,EAAgB,OAAO,WAAW,MAChCA,EAAgB,OACzBE,IAAU,OACVC,IAAOH,EAAgB,IAAI,WAAW,MAC7BC,MAAY,YACrBC,IAAUF,EAAgB,SAAS,IACnCG,IAAOH,EAAgB,WAAW,OAElCE,IAAUF,EAAgB,SAASA,EAAgB,WAAW,IAC9DG,IAAOH,EAAgB,WAAWA,EAAgB,QAAQA,EAAgB,QAAQ,KAG7E,EAAE,SAAAE,GAAS,MAAAC,EAAA;AAAA,EACpB,GAEMC,IAAkC,CACtCC,GACAV,GACAC,MACyB;AACzB,QAAI,CAACS,EAAS,QAAO,CAAA;AAErB,UAAMC,IAA+B,CAAA;AAErC,QAAI,MAAM,QAAQD,CAAO;AACvB,aAAAA,EAAQ,QAAQ,CAACX,MAAc;AAC7B,QAAAY,EAAO,KAAKb,EAA2BC,GAAWC,KAAkB,IAAIC,CAAe,CAAC;AAAA,MAC1F,CAAC,GACMU;AAGT,QAAID,EAAQ,SAAS;AACnB,YAAME,IAAgBF,EAAQ;AAC9B,MAAAC,EAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,OAAOC,EAAc,SAAS;AAAA,QAC9B,MAAM;AAAA,QACN,SAAS,OAAOZ,MAA2B;AACzC,UAAIY,EAAc,OAChB,OAAO,KAAKA,EAAc,KAAK,OAAO;AAAA,QAK1C;AAAA,MAAA,CACD;AAAA,IACH;AAEA,QAAIF,EAAQ,WAAW;AACrB,YAAMG,IAAkBH,EAAQ;AAChC,MAAAC,EAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,OAAOE,EAAgB,SAAS;AAAA,QAChC,MAAM;AAAA,QACN,SAAS,OAAOb,MAA2B;AACzC,UAAIa,EAAgB,OAClB,OAAO,KAAKA,EAAgB,KAAK,OAAO;AAAA,QAK5C;AAAA,MAAA,CACD;AAAA,IACH;AAEA,WAAOF;AAAA,EACT;AAEA,SAAO;AAAA,IACL,qBAAqBG,GAAsD;AACzE,YAAM,EAAE,SAAAP,GAAS,MAAAC,EAAA,IAASJ;AAAA,QACxBU,EAAa;AAAA,QACbA,EAAa;AAAA,MAAA;AAGf,aAAO;AAAA,QACL,IAAIA,EAAa;AAAA,QACjB,SAASP,KAAW;AAAA,QACpB,MAAMC,KAAQ;AAAA,QACd,QAAQM,EAAa;AAAA,QACrB,YAAYA,EAAa;AAAA,QACzB,WAAWA,EAAa,YAAY,IAAI,KAAKA,EAAa,SAAS,IAAI,oBAAI,KAAA;AAAA,QAC3E,MAAM,CAAA;AAAA,QACN,SAASL;AAAA,UACPK,EAAa,iBAAiB,WAAWA,EAAa;AAAA,QAAA;AAAA,QAExD,UAAU;AAAA,UACR,SAASA,EAAa;AAAA,UACtB,iBAAiBA,EAAa;AAAA,QAAA;AAAA,MAChC;AAAA,IAEJ;AAAA,IAEA,kCAAkCC,GAA8B;AAC9D,UAAI,CAACpB,EAAyBoB,CAAS,GAAG;AAExC,cAAMC,IACJD,GAAW,mBAAmB,OAAOA,EAAU,mBAAoB,WAC/DA,EAAU,kBACV,CAAA,GACA,EAAE,SAAAR,GAAS,MAAAC,MAASJ;AAAA,UACxBY;AAAA,UACAD,GAAW;AAAA,QAAA;AAEb,eAAO;AAAA,UACL,IAAIA,GAAW,kBAAkB,gBAAgB,KAAK,KAAK;AAAA,UAC3D,SAASR,KAAW;AAAA,UACpB,MAAMC,KAAQ;AAAA,UACd,QAAQO,GAAW,QAAQ;AAAA,UAC3B,YAAYA,GAAW,YAAY;AAAA,UACnC,WAAWA,GAAW,YAAY,IAAI,KAAKA,EAAU,SAAS,IAAI,oBAAI,KAAA;AAAA,UACtE,MAAM,CAAA;AAAA,UACN,SAAS,CAAA;AAAA,UACT,UAAU;AAAA,YACR,SAASA,GAAW,WAAW;AAAA,YAC/B,iBAAiBC;AAAA,UAAA;AAAA,QACnB;AAAA,MAEJ;AAEA,YAAM,EAAE,SAAAT,GAAS,MAAAC,MAASJ,EAAsBW,EAAU,iBAAiBA,EAAU,OAAO;AAE5F,aAAO;AAAA,QACL,IAAIA,EAAU;AAAA,QACd,SAASR,KAAW;AAAA,QACpB,MAAMC,KAAQ;AAAA,QACd,QAAQO,EAAU,QAAQ;AAAA,QAC1B,YAAYA,EAAU,YAAY;AAAA,QAClC,WAAWA,EAAU,YAAY,IAAI,KAAKA,EAAU,SAAS,IAAI,oBAAI,KAAA;AAAA,QACrE,MAAM,CAAA;AAAA,QACN,SAASN;AAAA,UACPM,EAAU,iBAAiB,WAAWA,EAAU;AAAA,UAChDA,EAAU;AAAA,QAAA;AAAA,QAEZ,UAAU;AAAA,UACR,SAASA,EAAU;AAAA,UACnB,iBAAkBA,EAAkB;AAAA,QAAA;AAAA,MACtC;AAAA,IAEJ;AAAA,IAEA,0BAAApB;AAAA,EAAA;AAEJ;"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),B=require("@edusight/notification-sdk"),i=require("react"),q=require("socket.io-client"),v=require("./hooks-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),B=require("@edusight/notification-sdk"),i=require("react"),q=require("socket.io-client"),v=require("./hooks-C6Z38jT_.cjs"),y=require("./components-Cr9Sf7Cz.cjs"),V=()=>window.__notificationSDK?.client,z=({onPreferencesLoaded:t,onError:n})=>{const p=V(),[w,c]=i.useState(!0),[f,l]=i.useState(null),[r,u]=i.useState(null),m=i.useCallback(async()=>{try{if(c(!0),l(null),!p)throw new Error("Notification client not available");const h=window.__notificationSDK?.config;if(!h)throw new Error("SDK configuration not available");const{subscriberId:g,tenantId:k,environmentId:T}=h;if(!g||!k||!T)throw new Error("SubscriberId, TenantId or EnvironmentId not available in config");const E=await p.preferences.get(k,g,T);let d=null;try{d=await p.preferences.getSchedule(k,g,T)}catch{}const _={channels:{email:E.emailEnabled??!0,push:E.pushEnabled??!0,sms:E.smsEnabled??!1,inApp:E.inAppEnabled??!0},subscriptions:[],deliverySchedule:{enabled:d?.isEnabled||!1,timezone:"UTC",quietHours:{start:E.quietHoursStart??"22:00",end:E.quietHoursEnd??"08:00"},weekdays:d?.weeklySchedule?[!!d.weeklySchedule.monday,!!d.weeklySchedule.tuesday,!!d.weeklySchedule.wednesday,!!d.weeklySchedule.thursday,!!d.weeklySchedule.friday,!!d.weeklySchedule.saturday,!!d.weeklySchedule.sunday]:[!0,!0,!0,!0,!0,!1,!1],weeklySchedule:d?.weeklySchedule||void 0}};E.categories&&Object.entries(E.categories).forEach(([N,C])=>{_.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}})}),u(_),t(_)}catch(h){const g=h instanceof Error?h:new Error("Failed to load preferences");h?.response?.status===404||h?.status===404||(l(g),n?.(g));const T={channels:{email:!0,push:!0,sms:!1,inApp:!0},subscriptions:[],deliverySchedule:{enabled:!1,timezone:"UTC",quietHours:{start:"22:00",end:"08:00"},weekdays:[!0,!0,!0,!0,!0,!1,!1]}};u(T),t(T)}finally{c(!1)}},[p,t,n]);return i.useEffect(()=>{p&&m()},[p,m]),{isLoading:w,error:f,preferences:r}},H=()=>window.__notificationSDK?.client,$=()=>{const t=H(),[n,p]=i.useState([]),[w,c]=i.useState(!1),[f,l]=i.useState(!0),[r,u]=i.useState(0),m=5,h=i.useCallback(async()=>{if(!(!t||w||!f))try{c(!0);const k=window.__notificationSDK?.config;if(!k)return;const T=await t.preferences.listSpecific(k.tenantId,k.subscriberId,{includeWorkflows:!0,includeTemplates:!1,activeOnly:!0,limit:m,offset:r}),E=(T.items||[]).map(d=>({workflowId:d.identifier,name:d.name,enabled:d.preference.enabled,channels:d.preference.channels}));p(d=>{const _=new Set(d.map(C=>C.workflowId)),N=E.filter(C=>!_.has(C.workflowId));return[...d,...N]}),u(d=>d+m),(E.length<m||T.total!==void 0&&n.length+E.length>=T.total)&&l(!1)}catch{}finally{c(!1)}},[t,r,f,w,n.length]);return i.useEffect(()=>{t&&r===0&&n.length===0&&h()},[t,h,r,n.length]),{specificPreferences:n,isLoading:w,hasMore:f,loadMore:h,refetch:async()=>{p([]),u(0),l(!0)}}},J=({error:t,onRetry:n})=>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(y.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}`]})]}),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:n,"data-testid":"error-retry-button",children:[s.jsx(h.MdRefresh,{className:"mr-1 w-4 h-4","aria-hidden":"true"}),"Try again"]})]});class D extends i.Component{constructor(n){super(n),this.handleRetry=()=>{this.setState({hasError:!1,error:null,errorInfo:null})},this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(n){return{hasError:!0,error:n}}componentDidCatch(n,f){this.setState({errorInfo:f}),this.props.onError&&this.props.onError(n,f)}render(){return this.state.hasError?s.jsx(J,{error:this.state.error,onRetry:this.handleRetry}):this.props.children}}const P=i.createContext(null),G=()=>{const t=i.useContext(P);if(!t)throw new Error("useSDK must be used within a NotificationWidget");return t},Q={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}},X=({config:t,children:n})=>{const[f,E]=i.useState({client:null,isInitialized:!1,error:null});return i.useEffect(()=>{let c=!0;return(async()=>{try{const l=window.__notificationSDK;if(l?.client&&JSON.stringify(l.config)===JSON.stringify(t)){c&&E({client:l.client,isInitialized:!0,error:null});return}const r=new B.NotificationClient({apiUrl:t.baseUrl,apiKey:t.apiKey,tenantId:t.tenantId,environmentId:t.environmentId});window.__notificationSDK={client:r,config:t},c&&E({client:r,isInitialized:!0,error:null})}catch(l){c&&E({client:null,isInitialized:!1,error:l})}})(),()=>{c=!1}},[t]),s.jsx(P.Provider,{value:f,children:n})},Y=(t,n)=>{switch(n.type){case"SET_NOTIFICATIONS":return{...t,notifications:n.payload,unreadCount:n.payload.filter(u=>!u.isRead).length};case"ADD_NOTIFICATION":const f=[n.payload,...t.notifications];return{...t,notifications:f,unreadCount:f.filter(u=>!u.isRead).length};case"UPDATE_NOTIFICATION":const E=t.notifications.map(u=>u.id===n.payload.id?{...u,...n.payload.updates}:u);return{...t,notifications:E,unreadCount:E.filter(u=>!u.isRead).length};case"DELETE_NOTIFICATION":const c=t.notifications.filter(u=>u.id!==n.payload);return{...t,notifications:c,unreadCount:c.filter(u=>!u.isRead).length};case"SET_PREFERENCES":return{...t,preferences:n.payload};case"SET_UI_STATE":return{...t,ui:{...t.ui,...n.payload}};case"SET_WEBSOCKET_STATE":return{...t,websocket:{...t.websocket,...n.payload}};default:return t}},Z=({position:t="right",size:n="medium",theme:f="light",className:E="",onError:c,onMorePreferencesClick:u})=>{const[l,r]=i.useReducer(Y,Q),{client:d,isInitialized:w,error:m}=G(),I=i.useRef(null),C=i.useCallback(e=>{r({type:"SET_PREFERENCES",payload:e})},[]),T=i.useCallback(e=>{c&&c(e)},[c]),{error:b}=z({onPreferencesLoaded:C,onError:T}),{specificPreferences:p,isLoading:N,hasMore:_,loadMore:k}=$(),{updatePreference:j,isSaving:A,error:O}=v.useLivePreferences({preferences:l.preferences,onPreferencesChange:C,onError:T});i.useEffect(()=>{if(p.length>0){const o=[...l.preferences.subscriptions];let a=!1;p.forEach(S=>{const g=o.findIndex(y=>y.workflowId===S.workflowId);if(g===-1)o.push(S),a=!0;else{const y=o[g];y.name===y.workflowId&&S.name&&S.name!==S.workflowId&&(o[g]={...y,name:S.name},a=!0)}}),a&&r({type:"SET_PREFERENCES",payload:{...l.preferences,subscriptions:o}})}},[p]);const K=i.useMemo(()=>p.map(e=>l.preferences.subscriptions.find(a=>a.workflowId===e.workflowId)||e),[p,l.preferences.subscriptions]),x=i.useCallback(e=>{try{const o=v.createNotificationMapper();switch(e.type){case"notification_received":{const a=e.data;if(!o.validateWebSocketPayload(a))break;const S=o.toWidgetNotificationFromWebSocket(a);r({type:"ADD_NOTIFICATION",payload:S});break}case"notification_updated":r({type:"UPDATE_NOTIFICATION",payload:{id:e.data.id||e.data.notificationId,updates:e.data}});break;case"notification_deleted":r({type:"DELETE_NOTIFICATION",payload:e.data.id||e.data.notificationId});break;case"preferences_updated":r({type:"SET_PREFERENCES",payload:e.data});break;default:}}catch{}},[]),R=i.useCallback(async()=>{if(!(!d||!w||I.current))try{r({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 S=`${d.getApiHost()}/v1/notifications`,g=q.io(S,{query:{tenantId:e.tenantId,subscriberId:e.subscriberId,environmentId:e.environmentId},transports:["websocket"],autoConnect:!1,reconnection:!0,reconnectionAttempts:10,reconnectionDelay:1e3,reconnectionDelayMax:5e3});I.current=g,g.on("notification",y=>{x({type:"notification_received",data:y})}),g.on("connect",()=>{r({type:"SET_WEBSOCKET_STATE",payload:{connected:!0,reconnecting:!1}})}),g.on("disconnect",y=>{r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}})}),g.on("reconnect_attempt",y=>{r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!0}})}),g.on("connect_error",y=>{r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}}),c&&c(y)}),g.connect()}catch(e){r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}}),c&&c(e)}},[d,w,x,c]),W=i.useCallback(()=>{if(I.current)try{I.current.disconnect&&I.current.disconnect(),I.current=null,r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}})}catch{}},[]),F=i.useCallback(()=>{r({type:"SET_UI_STATE",payload:{isOpen:!l.ui.isOpen}})},[l.ui.isOpen]),M=i.useCallback(()=>{r({type:"SET_UI_STATE",payload:{isOpen:!1}})},[]),L=i.useCallback(e=>{r({type:"SET_UI_STATE",payload:{currentView:e}})},[]),U=i.useCallback(async(e,o)=>{if(!d||!w)return;const a=window.__notificationSDK?.config;if(a){if(!e)throw new Error("notificationId is required");try{switch(o.type){case"mark_read":await d.inbox.markAsRead(e,a.tenantId,a.environmentId,a.subscriberId);break;case"mark_unread":await d.inbox.markAsUnread(e,a.tenantId,a.environmentId,a.subscriberId);break;case"archive":await d.inbox.archive(e,a.tenantId,a.environmentId,a.subscriberId);break;case"delete":await d.inbox.delete(e,a.tenantId,a.environmentId,a.subscriberId);break;default:o.handler&&await o.handler(e);break}switch(o.type){case"mark_read":r({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isRead:!0}}});break;case"mark_unread":r({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isRead:!1}}});break;case"archive":r({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isArchived:!0}}});break;case"delete":r({type:"DELETE_NOTIFICATION",payload:e});break}}catch(S){c&&c(S)}}},[d]);return i.useEffect(()=>{if(!d||!w)return;(async()=>{try{r({type:"SET_UI_STATE",payload:{isLoading:!0}});const o=window.__notificationSDK?.config;if(!o)throw new Error("SDK configuration not available");const a=v.createNotificationMapper(),g=((await d.inbox.getRenderedNotifications({channel:"in_app",limit:50,offset:0},o.tenantId,o.environmentId,o.subscriberId))?.items||[]).map(y=>a.toWidgetNotification(y));r({type:"SET_NOTIFICATIONS",payload:g}),r({type:"SET_UI_STATE",payload:{isLoading:!1,error:null}})}catch(o){r({type:"SET_UI_STATE",payload:{isLoading:!1,error:o}}),c&&c(o)}})()},[d,w,c]),i.useEffect(()=>(d&&w&&R(),()=>{W()}),[d]),i.useEffect(()=>{if(!d||!w||l.websocket.connected)return;const e=setInterval(async()=>{try{const o=window.__notificationSDK?.config;if(!o)return;const a=v.createNotificationMapper(),g=((await d.inbox.getRenderedNotifications({channel:"in_app",limit:50,offset:0},o.tenantId,o.environmentId,o.subscriberId))?.items||[]).map(y=>a.toWidgetNotification(y));r({type:"SET_NOTIFICATIONS",payload:g})}catch{}},3e4);return()=>clearInterval(e)},[d,l.websocket.connected]),i.useEffect(()=>{const e=o=>{if(o.key==="notification_widget_sync"&&o.newValue)try{const a=JSON.parse(o.newValue);x(a)}catch{}};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)},[x]),i.useEffect(()=>{r({type:"SET_UI_STATE",payload:{isLoading:A}})},[A]),i.useEffect(()=>{const e=m||O||b;e&&r({type:"SET_UI_STATE",payload:{error:e}})},[m,O,b]),!w&&!m?s.jsx("div",{className:`mx-widget-root relative inline-block ${E}`,"data-mx-widget":"root","data-widget-size":n||"small","data-theme":f,"data-testid":"notification-widget",children:s.jsx(h.ComponentErrorBoundary,{componentName:"BellComponent",children:s.jsx(h.BellComponent,{unreadCount:0,onClick:()=>{},size:n,disabled:!0})})}):m?s.jsx("div",{className:`mx-widget-root relative inline-block ${E}`,"data-mx-widget":"root","data-widget-size":n||"small","data-theme":f,"data-testid":"notification-widget",children:s.jsx(h.ComponentErrorBoundary,{componentName:"BellComponent",fallback:s.jsx(h.SDKConnectionFallback,{error:m.message,onRetry:()=>window.location.reload()}),children:s.jsx(h.BellComponent,{unreadCount:0,onClick:()=>{},size:n,disabled:!0})})}):s.jsxs("div",{className:`mx-widget-root relative inline-block ${E}`,"data-mx-widget":"root","data-widget-size":n||"small","data-theme":f,"data-testid":"notification-widget",children:[s.jsx(h.ComponentErrorBoundary,{componentName:"BellComponent",children:s.jsx(h.BellComponent,{unreadCount:l.unreadCount,onClick:F,size:n,disabled:l.ui.isLoading})}),s.jsx(h.ComponentErrorBoundary,{componentName:"InboxPopover",fallback:s.jsx(h.LoadingFallback,{message:"Unable to load notifications"}),children:s.jsx(h.InboxPopover,{isOpen:l.ui.isOpen,onClose:M,position:t,currentView:l.ui.currentView,onViewChange:L,notifications:l.notifications,onNotificationAction:U,preferences:l.preferences,onPreferenceChange:j,isPreferencesLoading:A,specificPreferences:K,onLoadMoreSpecific:k,hasMoreSpecific:_,isListLoading:N,onMorePreferencesClick:u})})]})},ee=({sdkConfig:t,...n})=>s.jsx(D,{onError:n.onError,children:s.jsx(X,{config:t,children:s.jsx(Z,{...n})})}),te="3.0.0",ne="@edusight/notification-widget";exports.BellComponent=h.BellComponent;exports.InboxPopover=h.InboxPopover;exports.NotificationItem=h.NotificationItem;exports.PreferencesView=h.PreferencesView;exports.NotificationWidget=ee;exports.NotificationWidgetErrorBoundary=D;exports.VERSION=te;exports.WIDGET_NAME=ne;
|
|
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:n,"data-testid":"error-retry-button",children:[s.jsx(y.MdRefresh,{className:"mr-1 w-4 h-4","aria-hidden":"true"}),"Try again"]})]});class D extends i.Component{constructor(n){super(n),this.handleRetry=()=>{this.setState({hasError:!1,error:null,errorInfo:null})},this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(n){return{hasError:!0,error:n}}componentDidCatch(n,p){this.setState({errorInfo:p}),this.props.onError&&this.props.onError(n,p)}render(){return this.state.hasError?s.jsx(J,{error:this.state.error,onRetry:this.handleRetry}):this.props.children}}const P=i.createContext(null),G=()=>{const t=i.useContext(P);if(!t)throw new Error("useSDK must be used within a NotificationWidget");return t},Q={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}},X=({config:t,children:n})=>{const[p,w]=i.useState({client:null,isInitialized:!1,error:null});return i.useEffect(()=>{let c=!0;return(async()=>{try{const l=window.__notificationSDK;if(l?.client&&JSON.stringify(l.config)===JSON.stringify(t)){c&&w({client:l.client,isInitialized:!0,error:null});return}const r=new B.NotificationClient({apiUrl:t.baseUrl,apiKey:t.apiKey,tenantId:t.tenantId,environmentId:t.environmentId});window.__notificationSDK={client:r,config:t},c&&w({client:r,isInitialized:!0,error:null})}catch(l){c&&w({client:null,isInitialized:!1,error:l})}})(),()=>{c=!1}},[t]),s.jsx(P.Provider,{value:p,children:n})},Y=(t,n)=>{switch(n.type){case"SET_NOTIFICATIONS":return{...t,notifications:n.payload,unreadCount:n.payload.filter(f=>!f.isRead).length};case"ADD_NOTIFICATION":const p=[n.payload,...t.notifications];return{...t,notifications:p,unreadCount:p.filter(f=>!f.isRead).length};case"UPDATE_NOTIFICATION":const w=t.notifications.map(f=>f.id===n.payload.id?{...f,...n.payload.updates}:f);return{...t,notifications:w,unreadCount:w.filter(f=>!f.isRead).length};case"DELETE_NOTIFICATION":const c=t.notifications.filter(f=>f.id!==n.payload);return{...t,notifications:c,unreadCount:c.filter(f=>!f.isRead).length};case"SET_PREFERENCES":return{...t,preferences:n.payload};case"SET_UI_STATE":return{...t,ui:{...t.ui,...n.payload}};case"SET_WEBSOCKET_STATE":return{...t,websocket:{...t.websocket,...n.payload}};default:return t}},Z=({position:t="right",size:n="medium",theme:p="light",className:w="",onError:c,onMorePreferencesClick:f})=>{const[l,r]=i.useReducer(Y,Q),{client:u,isInitialized:m,error:h}=G(),g=i.useRef(null),k=i.useCallback(e=>{r({type:"SET_PREFERENCES",payload:e})},[]),T=i.useCallback(e=>{c&&c(e)},[c]),{error:E}=z({onPreferencesLoaded:k,onError:T}),{specificPreferences:d,isLoading:_,hasMore:N,loadMore:C}=$(),{updatePreference:j,isSaving:A,error:O}=v.useLivePreferences({preferences:l.preferences,onPreferencesChange:k,onError:T});i.useEffect(()=>{if(d.length>0){const o=[...l.preferences.subscriptions];let a=!1;d.forEach(I=>{const S=o.findIndex(b=>b.workflowId===I.workflowId);if(S===-1)o.push(I),a=!0;else{const b=o[S];b.name===b.workflowId&&I.name&&I.name!==I.workflowId&&(o[S]={...b,name:I.name},a=!0)}}),a&&r({type:"SET_PREFERENCES",payload:{...l.preferences,subscriptions:o}})}},[d]);const K=i.useMemo(()=>d.map(e=>l.preferences.subscriptions.find(a=>a.workflowId===e.workflowId)||e),[d,l.preferences.subscriptions]),x=i.useCallback(e=>{try{const o=v.createNotificationMapper();switch(e.type){case"notification_received":{const a=e.data;if(!o.validateWebSocketPayload(a))break;const I=o.toWidgetNotificationFromWebSocket(a);r({type:"ADD_NOTIFICATION",payload:I});break}case"notification_updated":r({type:"UPDATE_NOTIFICATION",payload:{id:e.data.id||e.data.notificationId,updates:e.data}});break;case"notification_deleted":r({type:"DELETE_NOTIFICATION",payload:e.data.id||e.data.notificationId});break;case"preferences_updated":r({type:"SET_PREFERENCES",payload:e.data});break;default:}}catch{}},[]),R=i.useCallback(async()=>{if(!(!u||!m||g.current))try{r({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 I=`${u.getApiHost()}/v1/notifications`,S=q.io(I,{query:{tenantId:e.tenantId,subscriberId:e.subscriberId,environmentId:e.environmentId},transports:["websocket"],autoConnect:!1,reconnection:!0,reconnectionAttempts:10,reconnectionDelay:1e3,reconnectionDelayMax:5e3});g.current=S,S.on("notification",b=>{x({type:"notification_received",data:b})}),S.on("connect",()=>{r({type:"SET_WEBSOCKET_STATE",payload:{connected:!0,reconnecting:!1}})}),S.on("disconnect",b=>{r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}})}),S.on("reconnect_attempt",b=>{r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!0}})}),S.on("connect_error",b=>{r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}}),c&&c(b)}),S.connect()}catch(e){r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}}),c&&c(e)}},[u,m,x,c]),W=i.useCallback(()=>{if(g.current)try{g.current.disconnect&&g.current.disconnect(),g.current=null,r({type:"SET_WEBSOCKET_STATE",payload:{connected:!1,reconnecting:!1}})}catch{}},[]),F=i.useCallback(()=>{r({type:"SET_UI_STATE",payload:{isOpen:!l.ui.isOpen}})},[l.ui.isOpen]),M=i.useCallback(()=>{r({type:"SET_UI_STATE",payload:{isOpen:!1}})},[]),L=i.useCallback(e=>{r({type:"SET_UI_STATE",payload:{currentView:e}})},[]),U=i.useCallback(async(e,o)=>{if(!u||!m)return;const a=window.__notificationSDK?.config;if(a){if(!e)throw new Error("notificationId is required");try{switch(o.type){case"mark_read":await u.inbox.markAsRead(e,a.tenantId,a.environmentId,a.subscriberId);break;case"mark_unread":await u.inbox.markAsUnread(e,a.tenantId,a.environmentId,a.subscriberId);break;case"archive":await u.inbox.archive(e,a.tenantId,a.environmentId,a.subscriberId);break;case"delete":await u.inbox.delete(e,a.tenantId,a.environmentId,a.subscriberId);break;default:o.handler&&await o.handler(e);break}switch(o.type){case"mark_read":r({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isRead:!0}}});break;case"mark_unread":r({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isRead:!1}}});break;case"archive":r({type:"UPDATE_NOTIFICATION",payload:{id:e,updates:{isArchived:!0}}});break;case"delete":r({type:"DELETE_NOTIFICATION",payload:e});break}}catch(I){c&&c(I)}}},[u]);return i.useEffect(()=>{if(!u||!m)return;(async()=>{try{r({type:"SET_UI_STATE",payload:{isLoading:!0}});const o=window.__notificationSDK?.config;if(!o)throw new Error("SDK configuration not available");const a=v.createNotificationMapper(),S=((await u.inbox.getRenderedNotifications({channel:"in_app",limit:50,offset:0},o.tenantId,o.environmentId,o.subscriberId))?.items||[]).map(b=>a.toWidgetNotification(b));r({type:"SET_NOTIFICATIONS",payload:S}),r({type:"SET_UI_STATE",payload:{isLoading:!1,error:null}})}catch(o){r({type:"SET_UI_STATE",payload:{isLoading:!1,error:o}}),c&&c(o)}})()},[u,m,c]),i.useEffect(()=>(u&&m&&R(),()=>{W()}),[u]),i.useEffect(()=>{if(!u||!m||l.websocket.connected)return;const e=setInterval(async()=>{try{const o=window.__notificationSDK?.config;if(!o)return;const a=v.createNotificationMapper(),S=((await u.inbox.getRenderedNotifications({channel:"in_app",limit:50,offset:0},o.tenantId,o.environmentId,o.subscriberId))?.items||[]).map(b=>a.toWidgetNotification(b));r({type:"SET_NOTIFICATIONS",payload:S})}catch{}},3e4);return()=>clearInterval(e)},[u,l.websocket.connected]),i.useEffect(()=>{const e=o=>{if(o.key==="notification_widget_sync"&&o.newValue)try{const a=JSON.parse(o.newValue);x(a)}catch{}};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)},[x]),i.useEffect(()=>{r({type:"SET_UI_STATE",payload:{isLoading:A}})},[A]),i.useEffect(()=>{const e=h||O||E;e&&r({type:"SET_UI_STATE",payload:{error:e}})},[h,O,E]),!m&&!h?s.jsx("div",{className:`mx-widget-root relative inline-block ${w}`,"data-mx-widget":"root","data-widget-size":n||"small","data-theme":p,"data-testid":"notification-widget",children:s.jsx(y.ComponentErrorBoundary,{componentName:"BellComponent",children:s.jsx(y.BellComponent,{unreadCount:0,onClick:()=>{},size:n,disabled:!0})})}):h?s.jsx("div",{className:`mx-widget-root relative inline-block ${w}`,"data-mx-widget":"root","data-widget-size":n||"small","data-theme":p,"data-testid":"notification-widget",children:s.jsx(y.ComponentErrorBoundary,{componentName:"BellComponent",fallback:s.jsx(y.SDKConnectionFallback,{error:h.message,onRetry:()=>window.location.reload()}),children:s.jsx(y.BellComponent,{unreadCount:0,onClick:()=>{},size:n,disabled:!0})})}):s.jsxs("div",{className:`mx-widget-root relative inline-block ${w}`,"data-mx-widget":"root","data-widget-size":n||"small","data-theme":p,"data-testid":"notification-widget",children:[s.jsx(y.ComponentErrorBoundary,{componentName:"BellComponent",children:s.jsx(y.BellComponent,{unreadCount:l.unreadCount,onClick:F,size:n,disabled:l.ui.isLoading})}),s.jsx(y.ComponentErrorBoundary,{componentName:"InboxPopover",fallback:s.jsx(y.LoadingFallback,{message:"Unable to load notifications"}),children:s.jsx(y.InboxPopover,{isOpen:l.ui.isOpen,onClose:M,position:t,currentView:l.ui.currentView,onViewChange:L,notifications:l.notifications,onNotificationAction:U,preferences:l.preferences,onPreferenceChange:j,isPreferencesLoading:A,specificPreferences:K,onLoadMoreSpecific:C,hasMoreSpecific:N,isListLoading:_,onMorePreferencesClick:f})})]})},ee=({sdkConfig:t,...n})=>s.jsx(D,{onError:n.onError,children:s.jsx(X,{config:t,children:s.jsx(Z,{...n})})}),te="3.0.0",ne="@edusight/notification-widget";exports.BellComponent=y.BellComponent;exports.InboxPopover=y.InboxPopover;exports.NotificationItem=y.NotificationItem;exports.PreferencesView=y.PreferencesView;exports.NotificationWidget=ee;exports.NotificationWidgetErrorBoundary=D;exports.VERSION=te;exports.WIDGET_NAME=ne;
|
|
4
4
|
//# sourceMappingURL=index.cjs.js.map
|