Skip to content
This repository was archived by the owner on Jun 26, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/src/controllers/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ router.post(

const userId = user.id;

const notif = await prisma.notification.create({
await prisma.notification.create({
data: {
user: { connect: { id: userId } },
type: type ? type : "DEFI1_DAY1",
Expand Down
6 changes: 6 additions & 0 deletions api/src/cronjobs.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
scheduleNotificationsNotFilledWeekCronJob,
scheduleNotificationsInactivity10DaysCronJob,
scheduleNotificationPlan,
scheduleNotificationsNotActivated3DaysCronJob,
} = require("./utils/notifications");
const { reminderCronJob } = require("./controllers/reminder");

Expand Down Expand Up @@ -39,6 +40,11 @@ cron.schedule("0 0 4 * * 1 *", async () => {
launchCronJob("schedule notifications not filled week", scheduleNotificationsNotFilledWeekCronJob);
});

cron.schedule("0 0 4 * * * *", async () => {
// every thursday at 4 am, find users with no lastConsoAdded and createdAt = 3 days ago and create a notification for tomorrow (4th day)
launchCronJob("schedule notifications not activated 3 days", scheduleNotificationsNotActivated3DaysCronJob);
});

//every day at 19H59 launch the notification plan
cron.schedule("59 19 * * *", async () => {
launchCronJob("schedule notification plan", scheduleNotificationPlan);
Expand Down
3 changes: 3 additions & 0 deletions api/src/services/push-notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const sendPushNotification = async ({ userId, matomoId, pushNotifToken, title, b
await matomo.logEvent({
category: "PUSH_NOTIFICATION_SEND",
action: "SENDING",
name: type || "",
userId: matomoId,
});

Expand All @@ -75,6 +76,7 @@ const sendPushNotification = async ({ userId, matomoId, pushNotifToken, title, b
await matomo.logEvent({
category: "PUSH_NOTIFICATION_SEND",
action: "SUCCESS",
name: type || "",
userId: matomoId,
});
} else if (results[0]?.failure) {
Expand Down Expand Up @@ -116,6 +118,7 @@ const sendPushNotification = async ({ userId, matomoId, pushNotifToken, title, b
await matomo.logEvent({
category: "PUSH_NOTIFICATION_SEND",
action: "ERROR",
name: type || "",
userId: matomoId,
});
return { ok: false, error };
Expand Down
6 changes: 6 additions & 0 deletions api/src/utils/notifications-catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ const NOTIFICATIONS_TYPES = {
body: "Mettez toutes les chances de votre côté en remplissant vos consommations régulièrement 😊",
link: "oz://APP/ADD_DRINK",
},
NOT_ACTIVATED_3_DAYS: {
type: "NOT_ACTIVATED_3_DAYS",
title: "Vous n'êtes pas resté longtemps",
body: "Nous aimerions savoir ce qui vous ferait rester sur Oz",
link: "oz://NOT_ACTIVATED_NPS_SCREEN",
},
INACTIVITY_10_DAYS: {
type: "INACTIVITY_10_DAYS",
title: "5 sec pour un dernier retour ?",
Expand Down
59 changes: 53 additions & 6 deletions api/src/utils/notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,58 @@ const saveInactivity5Days = async (userId) => {
},
});
};
const saveNotActivated3Days = async (userId) => {
const type = "NOT_ACTIVATED_3_DAYS";
const notif = await prisma.notification.findFirst({
where: {
userId,
type,
status: "NotSent",
},
});
if (notif) return;

const reminder = await prisma.reminder.findUnique({
where: {
userId,
},
});
if (reminder) return;

await prisma.notification.create({
data: {
user: { connect: { id: userId } },
type,
date: dayjs().utc().add(14, "hour").startOf("minute").toDate(),
},
});
};

const scheduleNotificationsNotActivated3DaysCronJob = async () => {
try {
const users = await prisma.user.findMany({
where: {
lastConsoAdded: {
//last conso added is null
equals: null,
},
appVersion: {
gte: "313",
},
createdAt: {
gte: dayjs().utc().subtract(3, "day").startOf("day").toDate(),
lte: dayjs().utc().subtract(3, "day").endOf("day").toDate(),
},
},
});

for (const { id } of users) {
await saveNotActivated3Days(id);
}
} catch (e) {
capture(e, { level: "error" });
}
};

const scheduleNotificationsInactivity5DaysCronJob = async () => {
try {
Expand Down Expand Up @@ -111,12 +163,6 @@ const saveNotFilledWeek = async (userId) => {
});
if (reminder?.type === "Daily") return;

const utcHour = dayjs().utc().hour();
const hourInParis = dayjs().tz("Europe/Paris").hour();
const timeDifference = hourInParis - utcHour;
const utcTimeHours = (!reminder?.disabled && reminder?.date?.utcTimeHours) || 18 - timeDifference;
const utcTimeMinutes = (!reminder?.disabled && reminder?.date?.utcTimeMinutes) || 0;

await prisma.notification.create({
data: {
user: { connect: { id: userId } },
Expand Down Expand Up @@ -468,4 +514,5 @@ module.exports = {
scheduleUserSurvey,
scheduleNotificationsNotFilledWeekCronJob,
scheduleNotificationPlan,
scheduleNotificationsNotActivated3DaysCronJob,
};
4 changes: 2 additions & 2 deletions expo/app.versions.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"buildNumber": 312,
"buildName": "1.26.4"
"buildNumber": 313,
"buildName": "1.26.5"
}
2 changes: 1 addition & 1 deletion expo/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "oz-ensemble",
"version": "1.26.4",
"version": "1.26.5",
"scripts": {
"get-ip": "./get-ip.sh && echo \"this script updates the API IP to your own IP, because that's what Android Emulator needs to work. It's based on your wifi IP, if you need ethernet it won't work (needs en1 instead of en0)\"",
"start": "expo start --dev-client",
Expand Down
9 changes: 9 additions & 0 deletions expo/src/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { isInCravingKeyState } from "./recoil/craving";
import { dayjsInstance } from "./services/dates";
import SuccessStrategyModal from "./scenes/Craving/SuccessStrategyModal";
import ExportedDataDone from "./scenes/Craving/ExportedDataDone";
import Not_Activated_NPSScreen from "./scenes/NPS/not_activated_NPSScreen";

const Label = ({ children, focused, color }) => (
<LabelStyled focused={focused} color={color}>
Expand Down Expand Up @@ -384,6 +385,14 @@ const Router = () => {
headerShown: false,
}}
/>
<ModalsStack.Screen
name="NOT_ACTIVATED_NPS_SCREEN"
component={Not_Activated_NPSScreen}
options={{
presentation: "modal",
headerShown: false,
}}
/>
<ModalsStack.Screen
name="BADGES_LIST"
component={BadgesList}
Expand Down
Loading