277 lines
7.2 KiB
JavaScript
277 lines
7.2 KiB
JavaScript
import { Platform } from "react-native";
|
|
import notifee, { EventType } from "@notifee/react-native";
|
|
import * as Sentry from "@sentry/react-native";
|
|
import kebabCase from "lodash.kebabcase";
|
|
import { createLogger } from "~/lib/logger";
|
|
import { BACKGROUND_SCOPES } from "~/lib/logger/scopes";
|
|
|
|
import actionOpenAlert from "./actions/actionOpenAlert";
|
|
import actionCloseAlert from "./actions/actionCloseAlert";
|
|
import actionKeepOpenAlert from "./actions/actionKeepOpenAlert";
|
|
|
|
import actionOpenRelatives from "./actions/actionOpenRelatives";
|
|
import actionRelativeAllowAccept from "./actions/actionRelativeAllowAccept";
|
|
import actionRelativeAllowReject from "./actions/actionRelativeAllowReject";
|
|
import actionRelativeInvitationAccept from "./actions/actionRelativeInvitationAccept";
|
|
import actionRelativeInvitationReject from "./actions/actionRelativeInvitationReject";
|
|
|
|
import { navActions } from "~/stores";
|
|
|
|
export const onForegroundEvent = async (event) => {
|
|
const { detail } = event;
|
|
const { notification, pressAction } = detail;
|
|
const { type } = event;
|
|
|
|
eventLogger.info("Received foreground event", {
|
|
type,
|
|
notificationId: notification?.id,
|
|
notificationData: notification?.data,
|
|
pressAction,
|
|
eventDetail: detail,
|
|
});
|
|
|
|
await onEvent({ notification, pressAction, type });
|
|
};
|
|
|
|
export const onBackgroundEvent = async (event) => {
|
|
const { detail } = event;
|
|
const { notification, pressAction } = detail;
|
|
const { type } = event;
|
|
|
|
eventLogger.info("Received background event", {
|
|
type,
|
|
notificationId: notification?.id,
|
|
notificationData: notification?.data,
|
|
pressAction,
|
|
eventDetail: detail,
|
|
});
|
|
|
|
await onEvent({ notification, pressAction, type });
|
|
};
|
|
|
|
export const onBoostrapEvent = async (event) => {
|
|
const { notification, pressAction, input: type } = event;
|
|
|
|
eventLogger.info("Received bootstrap event", {
|
|
type,
|
|
notificationId: notification?.id,
|
|
notificationData: notification?.data,
|
|
pressAction,
|
|
event,
|
|
});
|
|
|
|
await onEvent({ notification, pressAction, type });
|
|
};
|
|
|
|
const eventLogger = createLogger({
|
|
module: BACKGROUND_SCOPES.NOTIFICATIONS,
|
|
feature: "events",
|
|
});
|
|
|
|
const getPressActionIdFromAndroidClickAction = (clickAction) => {
|
|
clickAction = clickAction.replace("com.alertesecours.", "");
|
|
clickAction = kebabCase(clickAction);
|
|
return clickAction;
|
|
};
|
|
|
|
const getPressActionId = (remoteMessage) => {
|
|
let actionId;
|
|
if (
|
|
Platform.OS === "android" &&
|
|
remoteMessage.notification?.android?.clickAction
|
|
) {
|
|
actionId = getPressActionIdFromAndroidClickAction(
|
|
remoteMessage.notification.android.clickAction,
|
|
);
|
|
}
|
|
if (!actionId) {
|
|
actionId = remoteMessage.data?.actionId;
|
|
}
|
|
return actionId;
|
|
};
|
|
|
|
export const onNotificationOpenedAppEvent = async (remoteMessage) => {
|
|
// if (Platform.OS === "ios") {
|
|
// // deprecated in favor of foreground event
|
|
// return;
|
|
// }
|
|
try {
|
|
eventLogger.info("Processing background notification tap", {
|
|
messageId: remoteMessage?.messageId,
|
|
data: remoteMessage?.data,
|
|
notification: remoteMessage?.notification,
|
|
clickAction: remoteMessage?.notification?.android?.clickAction,
|
|
});
|
|
|
|
if (!remoteMessage?.notification) {
|
|
eventLogger.warn("No notification data in message");
|
|
return;
|
|
}
|
|
|
|
const event = {
|
|
notification: {
|
|
id: remoteMessage.messageId,
|
|
title: remoteMessage.notification.title,
|
|
body: remoteMessage.notification.body,
|
|
data: remoteMessage.data || { json: "{}" },
|
|
},
|
|
pressAction: {
|
|
id: getPressActionId(remoteMessage),
|
|
},
|
|
type: EventType.PRESS,
|
|
};
|
|
|
|
eventLogger.debug("Created event from remote message", { event });
|
|
|
|
await onEvent(event);
|
|
eventLogger.info("Background notification tap processed", {
|
|
messageId: remoteMessage.messageId,
|
|
event,
|
|
});
|
|
} catch (error) {
|
|
const errorData = {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
messageId: remoteMessage?.messageId,
|
|
remoteMessage,
|
|
};
|
|
eventLogger.error(
|
|
"Failed to process background notification tap",
|
|
errorData,
|
|
);
|
|
|
|
Sentry.withScope((scope) => {
|
|
scope.setExtra("messageData", remoteMessage);
|
|
scope.setExtra("errorDetails", errorData);
|
|
Sentry.captureException(
|
|
new Error("Failed to process background notification tap"),
|
|
);
|
|
});
|
|
}
|
|
};
|
|
|
|
export const onEvent = async ({ type, notification, pressAction }) => {
|
|
eventLogger.debug("Starting event processing", {
|
|
type,
|
|
notificationId: notification?.id,
|
|
notificationData: notification?.data,
|
|
pressAction,
|
|
});
|
|
|
|
if (
|
|
type === EventType.DISMISSED ||
|
|
type === EventType.PRESS ||
|
|
type === EventType.ACTION_PRESS
|
|
) {
|
|
await notifee.cancelNotification(notification.id);
|
|
if (Platform.OS === "ios") {
|
|
if ((await notifee.getBadgeCount()) > 0) {
|
|
await notifee.decrementBadgeCount();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type === EventType.DISMISSED) {
|
|
eventLogger.info("User dismissed notification", {
|
|
notificationId: notification.id,
|
|
notificationData: notification.data,
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!(type === EventType.PRESS || type === EventType.ACTION_PRESS)) {
|
|
eventLogger.debug("Ignoring event type", { type });
|
|
return;
|
|
}
|
|
|
|
eventLogger.debug("Processing notification press", {
|
|
type,
|
|
notificationId: notification.id,
|
|
notificationData: notification.data,
|
|
pressAction,
|
|
});
|
|
|
|
let data;
|
|
try {
|
|
data = JSON.parse(notification.data.json);
|
|
eventLogger.debug("Parsed notification data", { data });
|
|
} catch (error) {
|
|
eventLogger.error("Failed to parse notification data", {
|
|
error: error.message,
|
|
notificationData: notification.data,
|
|
});
|
|
return;
|
|
}
|
|
|
|
const actionId = pressAction.id;
|
|
eventLogger.info("User pressed notification", {
|
|
actionId,
|
|
data,
|
|
type,
|
|
notificationId: notification.id,
|
|
});
|
|
|
|
if (data.expires && data.expires < Math.round(new Date() / 1000)) {
|
|
if (pressAction.launchActivity === "default") {
|
|
navActions.setNextNavigation([
|
|
{
|
|
name: "Expired",
|
|
},
|
|
]);
|
|
} else {
|
|
await notifee.displayNotification({
|
|
...notification,
|
|
title: "Expirée",
|
|
body: notification.title + " expirée",
|
|
android: {
|
|
...notification.android,
|
|
actions: [
|
|
{
|
|
id: "noop",
|
|
title: "Fermer",
|
|
},
|
|
],
|
|
},
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
switch (actionId) {
|
|
case "noop": {
|
|
break;
|
|
}
|
|
case "open-alert": {
|
|
await actionOpenAlert({ data });
|
|
break;
|
|
}
|
|
case "close-alert": {
|
|
await actionCloseAlert({ data });
|
|
break;
|
|
}
|
|
case "keep-open-alert": {
|
|
await actionKeepOpenAlert({ data });
|
|
break;
|
|
}
|
|
case "open-relatives": {
|
|
await actionOpenRelatives({ data });
|
|
break;
|
|
}
|
|
case "relative-allow-accept": {
|
|
await actionRelativeAllowAccept({ data });
|
|
break;
|
|
}
|
|
case "relative-allow-reject": {
|
|
await actionRelativeAllowReject({ data });
|
|
break;
|
|
}
|
|
case "relative-invitation-accept": {
|
|
await actionRelativeInvitationAccept({ data });
|
|
break;
|
|
}
|
|
case "relative-invitation-reject": {
|
|
await actionRelativeInvitationReject({ data });
|
|
break;
|
|
}
|
|
}
|
|
};
|