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
JavaScript
"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