UNPKG

notification-kit

Version:

A unified notification library for React + Capacitor apps. One API for push notifications, in-app notifications, and local notifications across Web, iOS, and Android.

764 lines (763 loc) 22.2 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const react = require("react"); const inApp = require("./inApp-D3paDkmL.js"); function useNotifications() { const [state, setState] = react.useState({ isInitialized: false, isInitializing: false, permission: null, token: null, error: null, notifications: [], pendingNotifications: [], subscriptions: [] }); const notificationKitRef = react.useRef(null); const eventListenersRef = react.useRef(/* @__PURE__ */ new Map()); const updateState = react.useCallback((updates) => { setState((prev) => ({ ...prev, ...updates })); }, []); const init = react.useCallback( async (config) => { try { updateState({ isInitializing: true, error: null }); notificationKitRef.current = inApp.NotificationKit.getInstance(); await notificationKitRef.current.init(config); const permission = await notificationKitRef.current.checkPermission(); let token = null; if (permission === "granted") { try { token = await notificationKitRef.current.getToken(); } catch (error) { } } updateState({ isInitialized: true, isInitializing: false, permission, token }); } catch (error) { updateState({ isInitialized: false, isInitializing: false, error }); throw error; } }, [updateState] ); const destroy = react.useCallback(async () => { try { eventListenersRef.current.forEach((unsubscribe2) => unsubscribe2()); eventListenersRef.current.clear(); if (notificationKitRef.current) { await notificationKitRef.current.destroy(); notificationKitRef.current = null; } updateState({ isInitialized: false, isInitializing: false, permission: null, token: null, error: null, notifications: [], pendingNotifications: [], subscriptions: [] }); } catch (error) { updateState({ error }); throw error; } }, [updateState]); const requestPermission = react.useCallback(async () => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { const granted = await notificationKitRef.current.requestPermission(); const permission = await notificationKitRef.current.checkPermission(); let token = null; if (granted) { try { token = await notificationKitRef.current.getToken(); } catch (error) { } } updateState({ permission, token }); return granted; } catch (error) { updateState({ error }); throw error; } }, [updateState]); const checkPermission = react.useCallback(async () => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { const permission = await notificationKitRef.current.checkPermission(); updateState({ permission }); return permission; } catch (error) { updateState({ error }); throw error; } }, [updateState]); const getToken = react.useCallback(async () => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { const token = await notificationKitRef.current.getToken(); updateState({ token }); return token; } catch (error) { updateState({ error }); throw error; } }, [updateState]); const refreshToken = react.useCallback(async () => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { const token = await notificationKitRef.current.getToken(); updateState({ token }); return token; } catch (error) { updateState({ error }); throw error; } }, [updateState]); const subscribe = react.useCallback( async (topic) => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { await notificationKitRef.current.subscribe(topic); updateState({ subscriptions: [...state.subscriptions, topic] }); } catch (error) { updateState({ error }); throw error; } }, [state.subscriptions, updateState] ); const unsubscribe = react.useCallback( async (topic) => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { await notificationKitRef.current.unsubscribe(topic); updateState({ subscriptions: state.subscriptions.filter((sub) => sub !== topic) }); } catch (error) { updateState({ error }); throw error; } }, [state.subscriptions, updateState] ); const scheduleNotification = react.useCallback( async (options) => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { const priorityMap = { low: "low", normal: "default", high: "high", urgent: "max" }; const { at, in: inProp, every, count, until, on, days, timezone, allowWhileIdle, exact, wakeDevice, priority, category, identifier, triggerInBackground, skipIfBatteryLow, respectQuietHours, ...notificationPayload } = options; const scheduleOptions = {}; if (at !== void 0) scheduleOptions.at = at; if (inProp !== void 0) scheduleOptions.in = inProp; if (every !== void 0) scheduleOptions.every = every; if (count !== void 0) scheduleOptions.count = count; if (until !== void 0) scheduleOptions.until = until; if (on !== void 0) scheduleOptions.on = on; if (days !== void 0) scheduleOptions.days = days; if (timezone !== void 0) scheduleOptions.timezone = timezone; if (allowWhileIdle !== void 0) scheduleOptions.allowWhileIdle = allowWhileIdle; if (exact !== void 0) scheduleOptions.exact = exact; if (wakeDevice !== void 0) scheduleOptions.wakeDevice = wakeDevice; if (priority !== void 0) scheduleOptions.priority = priority; if (category !== void 0) scheduleOptions.category = category; if (identifier !== void 0) scheduleOptions.identifier = identifier; if (triggerInBackground !== void 0) scheduleOptions.triggerInBackground = triggerInBackground; if (skipIfBatteryLow !== void 0) scheduleOptions.skipIfBatteryLow = skipIfBatteryLow; if (respectQuietHours !== void 0) scheduleOptions.respectQuietHours = respectQuietHours; const payload = { ...notificationPayload, priority: priorityMap[priority || "normal"] || "default", schedule: scheduleOptions }; await notificationKitRef.current.scheduleLocalNotification( payload ); const pending = await notificationKitRef.current.getPendingLocalNotifications(); updateState({ pendingNotifications: pending }); } catch (error) { updateState({ error }); throw error; } }, [updateState] ); const cancelNotification = react.useCallback( async (id) => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { await notificationKitRef.current.cancelLocalNotification(id); const pending = await notificationKitRef.current.getPendingLocalNotifications(); updateState({ pendingNotifications: pending }); } catch (error) { updateState({ error }); throw error; } }, [updateState] ); const getPendingNotifications = react.useCallback(async () => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { const pending = await notificationKitRef.current.getPendingLocalNotifications(); updateState({ pendingNotifications: pending }); return pending; } catch (error) { updateState({ error }); throw error; } }, [updateState]); const createChannel = react.useCallback( async (channel) => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { await notificationKitRef.current.createChannel(channel); } catch (error) { updateState({ error }); throw error; } }, [updateState] ); const deleteChannel = react.useCallback( async (channelId) => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { await notificationKitRef.current.deleteChannel(channelId); } catch (error) { updateState({ error }); throw error; } }, [updateState] ); const listChannels = react.useCallback(async () => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } try { return await notificationKitRef.current.listChannels(); } catch (error) { updateState({ error }); throw error; } }, [updateState]); const addEventListener = react.useCallback( (event, callback) => { if (!notificationKitRef.current) { throw new Error("NotificationKit not initialized"); } const unsubscribe2 = notificationKitRef.current.on(event, callback); const listenerId = `${event}-${Date.now()}`; eventListenersRef.current.set(listenerId, unsubscribe2); return () => { unsubscribe2(); eventListenersRef.current.delete(listenerId); }; }, [] ); const clearNotifications = react.useCallback(() => { updateState({ notifications: [] }); }, [updateState]); const clearError = react.useCallback(() => { updateState({ error: null }); }, [updateState]); const refresh = react.useCallback(async () => { if (!notificationKitRef.current) { return; } try { const [permission, pending] = await Promise.all([ notificationKitRef.current.checkPermission(), notificationKitRef.current.getPendingLocalNotifications() ]); let token = null; if (permission === "granted") { try { token = await notificationKitRef.current.getToken(); } catch (error) { } } updateState({ permission, token, pendingNotifications: pending }); } catch (error) { updateState({ error }); throw error; } }, [updateState]); const isSupported = react.useCallback(async () => { if (!notificationKitRef.current) { return false; } try { return await notificationKitRef.current.isSupported(); } catch (error) { return false; } }, []); const showInApp = { show: react.useCallback(async (options) => { return await inApp.notifications.showInApp(options); }, []), success: react.useCallback(async (title, message) => { return await inApp.notifications.success(title, message); }, []), error: react.useCallback(async (title, message) => { return await inApp.notifications.error(title, message); }, []), warning: react.useCallback(async (title, message) => { return await inApp.notifications.warning(title, message); }, []), info: react.useCallback(async (title, message) => { return await inApp.notifications.info(title, message); }, []) }; react.useEffect(() => { if (!notificationKitRef.current || !state.isInitialized) { return; } const unsubscribeNotification = notificationKitRef.current.on( "notificationReceived", (event) => { const notification = { id: event.notification.id, title: event.notification.title, body: event.notification.body, data: event.notification.data || {} }; updateState({ notifications: [...state.notifications, notification] }); } ); const unsubscribeToken = notificationKitRef.current.on( "tokenRefreshed", (data) => { updateState({ token: data.token ?? null }); } ); const unsubscribePermission = notificationKitRef.current.on( "permissionChanged", (data) => { updateState({ permission: data.status }); } ); const unsubscribeError = notificationKitRef.current.on("error", (data) => { updateState({ error: data.error ?? null }); }); return () => { unsubscribeNotification(); unsubscribeToken(); unsubscribePermission(); unsubscribeError(); }; }, [state.isInitialized, state.notifications, updateState]); return { ...state, init, destroy, requestPermission, checkPermission, getToken, refreshToken, subscribe, unsubscribe, scheduleNotification, cancelNotification, getPendingNotifications, createChannel, deleteChannel, listChannels, addEventListener, showInApp, clearNotifications, clearError, refresh, isSupported }; } function useInAppNotification() { const [state, setState] = react.useState({ activeNotifications: [], isConfigured: false, config: null }); const managerRef = react.useRef(null); const showCallbacksRef = react.useRef(/* @__PURE__ */ new Set()); const dismissCallbacksRef = react.useRef(/* @__PURE__ */ new Set()); const intervalRef = react.useRef(null); const updateState = react.useCallback( (updates) => { setState((prev) => ({ ...prev, ...updates })); }, [] ); const initializeManager = react.useCallback(() => { if (!managerRef.current) { managerRef.current = inApp.InAppNotificationManager.getInstance(); } return managerRef.current; }, []); const updateActiveNotifications = react.useCallback(() => { const active = inApp.getActiveInAppNotifications(); updateState({ activeNotifications: active }); }, [updateState]); const configure = react.useCallback( (config) => { initializeManager(); inApp.configureInAppNotifications(config); updateState({ isConfigured: true, config: { ...state.config, ...config } }); }, [initializeManager, state.config, updateState] ); const show = react.useCallback( async (options) => { initializeManager(); const id = await inApp.showInAppNotification(options, state.config || void 0); updateActiveNotifications(); const notification = inApp.getActiveInAppNotifications().find((n) => n.id === id); if (notification) { showCallbacksRef.current.forEach((callback) => { try { callback(notification); } catch (error2) { } }); } return id; }, [initializeManager, state.config, updateActiveNotifications] ); const success = react.useCallback( async (title, message, options) => { return await show({ title, message: message ?? title, type: "success", ...options }); }, [show] ); const error = react.useCallback( async (title, message, options) => { return await show({ title, message: message ?? title, type: "error", ...options }); }, [show] ); const warning = react.useCallback( async (title, message, options) => { return await show({ title, message: message ?? title, type: "warning", ...options }); }, [show] ); const info = react.useCallback( async (title, message, options) => { return await show({ title, message: message ?? title, type: "info", ...options }); }, [show] ); const dismiss = react.useCallback( async (id) => { await inApp.dismissInAppNotification(id); updateActiveNotifications(); dismissCallbacksRef.current.forEach((callback) => { try { callback(id); } catch (error2) { } }); }, [updateActiveNotifications] ); const dismissAll = react.useCallback(async () => { const activeIds = state.activeNotifications.map((n) => n.id); await inApp.dismissAllInAppNotifications(); updateActiveNotifications(); activeIds.forEach((id) => { dismissCallbacksRef.current.forEach((callback) => { try { callback(id); } catch (error2) { } }); }); }, [state.activeNotifications, updateActiveNotifications]); const getActive = react.useCallback(() => { return inApp.getActiveInAppNotifications(); }, []); const onShow = react.useCallback( (callback) => { showCallbacksRef.current.add(callback); return () => { showCallbacksRef.current.delete(callback); }; }, [] ); const onDismiss = react.useCallback((callback) => { dismissCallbacksRef.current.add(callback); return () => { dismissCallbacksRef.current.delete(callback); }; }, []); react.useEffect(() => { intervalRef.current = setInterval(() => { updateActiveNotifications(); }, 1e3); return () => { if (intervalRef.current) { clearInterval(intervalRef.current); } }; }, [updateActiveNotifications]); react.useEffect(() => { updateActiveNotifications(); }, [updateActiveNotifications]); react.useEffect(() => { return () => { showCallbacksRef.current.clear(); dismissCallbacksRef.current.clear(); if (intervalRef.current) { clearInterval(intervalRef.current); } }; }, []); return { ...state, configure, show, success, error, warning, info, dismiss, dismissAll, getActive, hasActive: state.activeNotifications.length > 0, activeCount: state.activeNotifications.length, onShow, onDismiss }; } function useInAppNotificationSimple() { const { show, success, error, warning, info, dismiss, dismissAll, hasActive, activeCount } = useInAppNotification(); return { show, success, error, warning, info, dismiss, dismissAll, hasActive, activeCount }; } function useInAppNotificationQueue() { const [queue, setQueue] = react.useState([]); const [isProcessing, setIsProcessing] = react.useState(false); const { show, hasActive } = useInAppNotification(); const enqueue = react.useCallback((options) => { setQueue((prev) => [...prev, options]); }, []); const processQueue = react.useCallback(async () => { if (isProcessing || queue.length === 0 || hasActive) { return; } setIsProcessing(true); try { const next = queue[0]; if (next) { await show(next); setQueue((prev) => prev.slice(1)); } } catch (error) { } finally { setIsProcessing(false); } }, [isProcessing, queue, hasActive, show]); const clearQueue = react.useCallback(() => { setQueue([]); }, []); react.useEffect(() => { if (!hasActive && queue.length > 0 && !isProcessing) { processQueue(); } }, [hasActive, queue.length, isProcessing, processQueue]); return { queue, queueLength: queue.length, isProcessing, enqueue, processQueue, clearQueue }; } function useInAppNotificationPersistence() { const [persistedNotifications, setPersistedNotifications] = react.useState([]); const { activeNotifications } = useInAppNotification(); const saveNotifications = react.useCallback(() => { try { const serialized = activeNotifications.map((n) => ({ id: n.id, options: n.options, timestamp: n.timestamp.toISOString() })); localStorage.setItem( "notification-kit-persisted", JSON.stringify(serialized) ); } catch (error) { } }, [activeNotifications]); const loadNotifications = react.useCallback(() => { try { const stored = localStorage.getItem("notification-kit-persisted"); if (stored) { const parsed = JSON.parse(stored); setPersistedNotifications( parsed.map((n) => ({ ...n, timestamp: new Date(n.timestamp) })) ); } } catch (error) { } }, []); const clearPersistence = react.useCallback(() => { try { localStorage.removeItem("notification-kit-persisted"); setPersistedNotifications([]); } catch (error) { } }, []); react.useEffect(() => { saveNotifications(); }, [activeNotifications, saveNotifications]); react.useEffect(() => { loadNotifications(); }, [loadNotifications]); return { persistedNotifications, saveNotifications, loadNotifications, clearPersistence }; } exports.SchedulingUtils = inApp.SchedulingUtils; exports.configureInAppNotifications = inApp.configureInAppNotifications; exports.dismissAllInAppNotifications = inApp.dismissAllInAppNotifications; exports.dismissInAppNotification = inApp.dismissInAppNotification; exports.format = inApp.format; exports.getActiveInAppNotifications = inApp.getActiveInAppNotifications; exports.inApp = inApp.inApp; exports.permissions = inApp.permissions; exports.platform = inApp.platform; exports.showInAppNotification = inApp.showInAppNotification; exports.storage = inApp.storage; exports.validate = inApp.validate; exports.useInAppNotification = useInAppNotification; exports.useInAppNotificationPersistence = useInAppNotificationPersistence; exports.useInAppNotificationQueue = useInAppNotificationQueue; exports.useInAppNotificationSimple = useInAppNotificationSimple; exports.useNotifications = useNotifications; //# sourceMappingURL=react.js.map