From adf8fcf8f613fbd8e0dfa5c9cd3ae201a26a9be7 Mon Sep 17 00:00:00 2001 From: amal Date: Wed, 9 Jul 2025 16:42:05 +0800 Subject: [PATCH] upd: penerapan firebase Deskripsi: - pengumuman - diskusi umum - diskusi divisi - divisi - kegiatan - tugas divisi No Issues --- src/app/api/mobile/announcement/route.ts | 13 +++-- .../api/mobile/discussion-general/route.ts | 39 ++++++++++++++ src/app/api/mobile/discussion/route.ts | 44 ++++++++++++++-- src/app/api/mobile/division/route.ts | 47 +++++++++++++++-- src/app/api/mobile/project/route.ts | 51 ++++++++++++++++--- src/app/api/mobile/task/[id]/member/route.ts | 4 +- src/app/api/mobile/task/route.ts | 42 +++++++++++++-- src/app/api/version-app/route.ts | 2 +- xsendMany.ts | 8 +-- 9 files changed, 215 insertions(+), 35 deletions(-) diff --git a/src/app/api/mobile/announcement/route.ts b/src/app/api/mobile/announcement/route.ts index 7d2d758..28ff983 100644 --- a/src/app/api/mobile/announcement/route.ts +++ b/src/app/api/mobile/announcement/route.ts @@ -175,8 +175,8 @@ export async function POST(request: Request) { subscription: true } }, - TokenDeviceUser:{ - select:{ + TokenDeviceUser: { + select: { token: true } } @@ -228,8 +228,8 @@ export async function POST(request: Request) { subscription: true } }, - TokenDeviceUser:{ - select:{ + TokenDeviceUser: { + select: { token: true } } @@ -255,7 +255,6 @@ export async function POST(request: Request) { - const pushNotif = dataPush.filter((item) => item.subscription != undefined) const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Pengumuman Baru', body: 'Anda memiliki pengumuman baru. Silahkan periksa detailnya.' } }) @@ -263,13 +262,13 @@ export async function POST(request: Request) { data: dataNotif }) - const tokenUnique = [...new Set(tokenDup)]; + const tokenUnique = [...new Set(tokenDup.flat())]; await sendFCMNotificationMany({ token: tokenUnique, title: "Pengumuman Baru", body: "Anda memiliki pengumuman baru. Silahkan periksa detailnya.", data: { id: data.id, category: "announcement", content: data.id } - }) + }) // create log user const log = await createLogUserMobile({ act: 'CREATE', desc: 'User membuat data pengumuman baru', table: 'announcement', data: data.id, user: userMobile.id }) diff --git a/src/app/api/mobile/discussion-general/route.ts b/src/app/api/mobile/discussion-general/route.ts index c8c46fd..b410613 100644 --- a/src/app/api/mobile/discussion-general/route.ts +++ b/src/app/api/mobile/discussion-general/route.ts @@ -5,6 +5,7 @@ import _ from "lodash"; import moment from "moment"; import "moment/locale/id"; import { NextResponse } from "next/server"; +import { sendFCMNotificationMany } from "../../../../../xsendMany"; @@ -141,6 +142,29 @@ export async function POST(request: Request) { data: dataMember }) + const memberNotifMobile = await prisma.discussionMember.findMany({ + where: { + idDiscussion: data.id + }, + select: { + User: { + select: { + TokenDeviceUser: { + select: { + token: true + } + } + } + } + } + }) + + const dataFCM = memberNotifMobile.map((v: any) => ({ + ..._.omit(v, ["User", "TokenDeviceUser"]), + tokens: v.User.TokenDeviceUser.map((v: any) => v.token) + })) + const tokenDup = dataFCM.filter((v: any) => v.tokens.length > 0).map((v: any) => v.tokens).flat(); + const dataNotif = member.map((v: any) => ({ ..._.omit(v, ["idUser", "name", "img"]), idUserTo: v.idUser, @@ -164,10 +188,17 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + tokenDup.push(perbekel?.TokenDeviceUser.map((v: any) => v.token).flat()) + dataNotif.push({ idUserTo: perbekel?.id, idUserFrom: userId, @@ -182,6 +213,14 @@ export async function POST(request: Request) { data: dataNotif }) + const tokenUnique = [...new Set(tokenDup.flat())]; + await sendFCMNotificationMany({ + token: tokenUnique, + title: "Diskusi Umum Baru", + body: "Anda memiliki diskusi umum baru. Silahkan periksa detailnya.", + data: { id: data.id, category: "discussion", content: data.id } + }) + // create log user const log = await createLogUserMobile({ act: 'CREATE', desc: 'User membuat data diskusi umum', table: 'discussion', data: data.id, user }) diff --git a/src/app/api/mobile/discussion/route.ts b/src/app/api/mobile/discussion/route.ts index c1b36b1..fa8a1ef 100644 --- a/src/app/api/mobile/discussion/route.ts +++ b/src/app/api/mobile/discussion/route.ts @@ -1,10 +1,11 @@ -import { prisma } from "@/module/_global"; +import { funSendWebPush, prisma } from "@/module/_global"; import { funGetUserById } from "@/module/auth"; import { createLogUserMobile } from "@/module/user"; import _ from "lodash"; import moment from "moment"; import "moment/locale/id"; import { NextResponse } from "next/server"; +import { sendFCMNotificationMany } from "../../../../../xsendMany"; // GET ALL DISCUSSION DIVISION ACTIVE = TRUE @@ -143,6 +144,11 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } } @@ -151,10 +157,17 @@ export async function POST(request: Request) { // mengirim notifikasi + // dataFCM untuk push notifikasi mobile // datanotif untuk realtime notifikasi // datapush untuk web push notifikasi ketika aplikasi tidak aktif + const dataFCM = memberDivision.map((v: any) => ({ + ..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]), + tokens: v.User.TokenDeviceUser.map((v: any) => v.token) + })) + const tokenDup = dataFCM.filter((v: any) => v.tokens.length > 0).map((v: any) => v.tokens).flat(); + const dataNotif = memberDivision.map((v: any) => ({ - ..._.omit(v, ["User", "Subscribe"]), + ..._.omit(v, ["User", "Subscribe", "TokenDeviceUser"]), idUserTo: v.User.id, idUserFrom: String(userId), category: 'division/' + idDivision + '/discussion', @@ -164,7 +177,7 @@ export async function POST(request: Request) { })) const dataPush = memberDivision.map((v: any) => ({ - ..._.omit(v, ["User", "Subscribe"]), + ..._.omit(v, ["User", "Subscribe", "TokenDeviceUser"]), idUser: v.User.id, subscription: v.User.Subscribe?.subscription, })) @@ -182,10 +195,17 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + tokenDup.push(perbekel?.TokenDeviceUser.map((v: any) => v.token).flat()) + dataNotif.push({ idUserTo: perbekel?.id, idUserFrom: userId, @@ -214,10 +234,17 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + tokenDup.push(ketuaGrup?.TokenDeviceUser.map((v: any) => v.token).flat()) + dataNotif.push({ idUserTo: ketuaGrup?.id, idUserFrom: userId, @@ -235,11 +262,20 @@ export async function POST(request: Request) { const pushNotif = dataPush.filter((item) => item.subscription != undefined) - // const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: 'Terdapat diskusi baru. Silahkan periksa detailnya.', title: 'Diskusi Baru' } }) + const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: 'Terdapat diskusi baru. Silahkan periksa detailnya.', title: 'Diskusi Baru' } }) const insertNotif = await prisma.notifications.createMany({ data: dataNotif }) + const tokenUnique = [...new Set(tokenDup.flat())]; + + await sendFCMNotificationMany({ + token: tokenUnique, + title: "Diskusi Baru", + body: "Anda memiliki diskusi baru. Silahkan periksa detailnya.", + data: { id: data.id, category: "division/" + idDivision + "/discussion", content: data.id } + }) + // create log user const log = await createLogUserMobile({ act: 'CREATE', desc: 'User membuat data diskusi', table: 'divisionDisscussion', data: data.id, user: userId }) diff --git a/src/app/api/mobile/division/route.ts b/src/app/api/mobile/division/route.ts index 63c6f7b..fbe17ff 100644 --- a/src/app/api/mobile/division/route.ts +++ b/src/app/api/mobile/division/route.ts @@ -1,8 +1,9 @@ -import { prisma } from "@/module/_global"; +import { funSendWebPush, prisma } from "@/module/_global"; import { funGetUserById } from "@/module/auth"; import { createLogUserMobile } from "@/module/user"; import _ from "lodash"; import { NextResponse } from "next/server"; +import { sendFCMNotificationMany } from "../../../../../xsendMany"; // GET ALL DATA DIVISI == LIST DATA DIVISI @@ -172,6 +173,7 @@ export async function POST(request: Request) { // mengirim notifikasi + // dataFCM untuk push notifikasi mobile // datanotif untuk realtime notifikasi // datapush untuk web push notifikasi ketika aplikasi tidak aktif const dataNotif = sent.member.map((v: any) => ({ @@ -197,12 +199,23 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } } } }) + const dataFCM = selectUser.map((v: any) => ({ + ..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]), + tokens: v.User.TokenDeviceUser.map((v: any) => v.token) + })) + const tokenDup = dataFCM.filter((v: any) => v.tokens.length > 0).map((v: any) => v.tokens).flat(); + const dataPush = selectUser.map((v: any) => ({ ..._.omit(v, ["idUser", "User", "Subscribe"]), idUser: v.idUser, @@ -222,10 +235,17 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + tokenDup.push(perbekel?.TokenDeviceUser.map((v: any) => v.token).flat()) + dataNotif.push({ idUserTo: perbekel?.id, idUserFrom: userId, @@ -258,12 +278,22 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + const omitFCM = atasanGroup.map((v: any) => ({ + ..._.omit(v, ["id", "Subscribe", "TokenDeviceUser"]), + tokens: v.TokenDeviceUser.map((v: any) => v.token) + })) + const omitData = atasanGroup.map((v: any) => ({ - ..._.omit(v, ["id", "Subscribe"]), + ..._.omit(v, ["id", "Subscribe", "TokenDeviceUser"]), idUserTo: v.id, idUserFrom: userId, category: 'division', @@ -273,24 +303,31 @@ export async function POST(request: Request) { })) const omitPush = atasanGroup.map((v: any) => ({ - ..._.omit(v, ["id", "Subscribe"]), + ..._.omit(v, ["id", "Subscribe", "TokenDeviceUser"]), idUser: v.id, subscription: v.Subscribe?.subscription, })) dataNotif.push(...omitData) dataPush.push(...omitPush) - + tokenDup.push(...omitFCM.map((v: any) => v.tokens).flat()) } const pushNotif = dataPush.filter((item) => item.subscription != undefined) - // const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Divisi Baru', body: 'Terdapat divisi baru. Silahkan periksa detailnya.' } }) + const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Divisi Baru', body: 'Terdapat divisi baru. Silahkan periksa detailnya.' } }) const insertNotif = await prisma.notifications.createMany({ data: dataNotif }) + const tokenUnique = [...new Set(tokenDup.flat())]; + await sendFCMNotificationMany({ + token: tokenUnique, + title: "Divisi Baru", + body: "Anda memiliki divisi baru. Silahkan periksa detailnya.", + data: { id: data.id, category: "division", content: data.id } + }) // create log user const log = await createLogUserMobile({ act: 'CREATE', desc: 'User membuat data divisi', table: 'division', data: data.id, user: userId }) diff --git a/src/app/api/mobile/project/route.ts b/src/app/api/mobile/project/route.ts index 209ed55..35a840d 100644 --- a/src/app/api/mobile/project/route.ts +++ b/src/app/api/mobile/project/route.ts @@ -1,10 +1,11 @@ -import { DIR, funUploadFile, prisma } from "@/module/_global"; +import { DIR, funSendWebPush, funUploadFile, prisma } from "@/module/_global"; import { funGetUserById } from "@/module/auth"; import { createLogUserMobile } from "@/module/user"; import _, { ceil } from "lodash"; import moment from "moment"; import "moment/locale/id"; import { NextResponse } from "next/server"; +import { sendFCMNotificationMany } from "../../../../../xsendMany"; // GET ALL DATA PROJECT @@ -237,6 +238,11 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } } @@ -245,10 +251,17 @@ export async function POST(request: Request) { // mengirim notifikasi + // dataFCM untuk push notifikasi mobile // datanotif untuk realtime notifikasi - // datapush untuk web push notifikasi ketika aplikasi tidak aktif + // datapush untuk web push notifikasi ketika aplikasi tidak + const dataFCM = memberNotif.map((v: any) => ({ + ..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]), + tokens: v.User.TokenDeviceUser.map((v: any) => v.token) + })) + const tokenDup = dataFCM.filter((v: any) => v.tokens.length > 0).map((v: any) => v.tokens).flat(); + const dataNotif = memberNotif.map((v: any) => ({ - ..._.omit(v, ["idUser", "User", "Subscribe"]), + ..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]), idUserTo: v.idUser, idUserFrom: userId, category: 'project', @@ -258,7 +271,7 @@ export async function POST(request: Request) { })) const dataPush = memberNotif.map((v: any) => ({ - ..._.omit(v, ["idUser", "User", "Subscribe"]), + ..._.omit(v, ["idUser", "User", "Subscribe", "TokenDeviceUser"]), idUser: v.idUser, subscription: v.User.Subscribe?.subscription, })) @@ -276,10 +289,17 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + tokenDup.push(perbekel?.TokenDeviceUser.map((v: any) => v.token).flat()) + dataNotif.push({ idUserTo: perbekel?.id, idUserFrom: userId, @@ -311,10 +331,21 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + const omitFCM = atasanGroup.map((v: any) => ({ + ..._.omit(v, ["id", "Subscribe", "TokenDeviceUser"]), + tokens: v.TokenDeviceUser.map((v: any) => v.token) + })) + + const omitData = atasanGroup.map((v: any) => ({ ..._.omit(v, ["id", "Subscribe"]), idUserTo: v.id, @@ -333,16 +364,24 @@ export async function POST(request: Request) { dataNotif.push(...omitData) dataPush.push(...omitPush) - + tokenDup.push(...omitFCM.map((v: any) => v.tokens).flat()) } const pushNotif = dataPush.filter((item) => item.subscription != undefined) - // const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Kegiatan Baru', body: 'Terdapat kegiatan baru. Silahkan periksa detailnya.' } }) + const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { title: 'Kegiatan Baru', body: 'Terdapat kegiatan baru. Silahkan periksa detailnya.' } }) const insertNotif = await prisma.notifications.createMany({ data: dataNotif }) + const tokenUnique = [...new Set(tokenDup.flat())]; + await sendFCMNotificationMany({ + token: tokenUnique, + title: "Kegiatan Baru", + body: "Anda memiliki kegiatan baru. Silahkan periksa detailnya.", + data: { id: data.id, category: "project", content: data.id } + }) + // create log user const log = await createLogUserMobile({ act: 'CREATE', desc: 'User membuat data kegiatan', table: 'project', data: data.id, user: userMobile.id }) diff --git a/src/app/api/mobile/task/[id]/member/route.ts b/src/app/api/mobile/task/[id]/member/route.ts index 0330080..98cc6d6 100644 --- a/src/app/api/mobile/task/[id]/member/route.ts +++ b/src/app/api/mobile/task/[id]/member/route.ts @@ -1,6 +1,6 @@ import { prisma } from "@/module/_global"; -import { funGetUserByCookies, funGetUserById } from "@/module/auth"; -import { createLogUser, createLogUserMobile } from "@/module/user"; +import { funGetUserById } from "@/module/auth"; +import { createLogUserMobile } from "@/module/user"; import _ from "lodash"; import { NextResponse } from "next/server"; diff --git a/src/app/api/mobile/task/route.ts b/src/app/api/mobile/task/route.ts index b4ce49d..ebaf027 100644 --- a/src/app/api/mobile/task/route.ts +++ b/src/app/api/mobile/task/route.ts @@ -1,8 +1,9 @@ -import { DIR, funUploadFile, prisma } from "@/module/_global"; +import { DIR, funSendWebPush, funUploadFile, prisma } from "@/module/_global"; import { funGetUserById } from "@/module/auth"; import { createLogUserMobile } from "@/module/user"; import _, { ceil } from "lodash"; import { NextResponse } from "next/server"; +import { sendFCMNotificationMany } from "../../../../../xsendMany"; // GET ALL DATA TUGAS DIVISI @@ -222,6 +223,11 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } } @@ -229,10 +235,17 @@ export async function POST(request: Request) { }) // mengirim notifikasi + // dataFCM untuk push notifikasi mobile // datanotif untuk realtime notifikasi // datapush untuk web push notifikasi ketika aplikasi tidak aktif + const dataFCM = memberDivision.map((v: any) => ({ + ..._.omit(v, ["User", "Subscribe", "TokenDeviceUser"]), + tokens: v.User.TokenDeviceUser.map((v: any) => v.token) + })) + const tokenDup = dataFCM.filter((v: any) => v.tokens.length > 0).map((v: any) => v.tokens).flat(); + const dataNotif = memberDivision.map((v: any) => ({ - ..._.omit(v, ["User", "Subscribe"]), + ..._.omit(v, ["User", "Subscribe", "TokenDeviceUser"]), idUserTo: v.User.id, idUserFrom: String(userMobile.id), category: 'division/' + idDivision + '/task', @@ -242,7 +255,7 @@ export async function POST(request: Request) { })) const dataPush = memberDivision.map((v: any) => ({ - ..._.omit(v, ["User", "Subscribe"]), + ..._.omit(v, ["User", "Subscribe", "TokenDeviceUser"]), idUser: v.User.id, subscription: v.User.Subscribe?.subscription, })) @@ -260,10 +273,17 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + tokenDup.push(perbekel?.TokenDeviceUser.map((v: any) => v.token).flat()) + dataNotif.push({ idUserTo: perbekel?.id, idUserFrom: userId, @@ -292,10 +312,17 @@ export async function POST(request: Request) { select: { subscription: true } + }, + TokenDeviceUser: { + select: { + token: true + } } } }) + tokenDup.push(ketuaGrup?.TokenDeviceUser.map((v: any) => v.token).flat()) + dataNotif.push({ idUserTo: ketuaGrup?.id, idUserFrom: userId, @@ -313,11 +340,18 @@ export async function POST(request: Request) { const pushNotif = dataPush.filter((item) => item.subscription != undefined) - // const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: 'Terdapat tugas baru. Silahkan periksa detailnya.', title: 'Tugas Baru' } }) + const sendWebPush = await funSendWebPush({ sub: pushNotif, message: { body: 'Terdapat tugas baru. Silahkan periksa detailnya.', title: 'Tugas Baru' } }) const insertNotif = await prisma.notifications.createMany({ data: dataNotif }) + const tokenUnique = [...new Set(tokenDup.flat())]; + await sendFCMNotificationMany({ + token: tokenUnique, + title: "Tugas Baru", + body: "Anda memiliki tugas baru. Silahkan periksa detailnya.", + data: { id: data.id, category:'division/' + idDivision + '/task', content: data.id } + }) // create log user const log = await createLogUserMobile({ act: 'CREATE', desc: 'User membuat tugas divisi baru', table: 'divisionProject', data: data.id, user: userMobile.id }) diff --git a/src/app/api/version-app/route.ts b/src/app/api/version-app/route.ts index 9569bf8..42a0458 100644 --- a/src/app/api/version-app/route.ts +++ b/src/app/api/version-app/route.ts @@ -2,7 +2,7 @@ import { NextResponse } from "next/server"; export async function GET(request: Request) { try { - return NextResponse.json({ success: true, version: "1.5.4", tahap: "beta", update: "-percobaan firebase admin fcm many device (tambah pengumuman)" }, { status: 200 }); + return NextResponse.json({ success: true, version: "1.5.5", tahap: "beta", update: "-firebase notification many device" }, { status: 200 }); } catch (error) { console.error(error); return NextResponse.json({ success: false, version: "Gagal mendapatkan version, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); diff --git a/xsendMany.ts b/xsendMany.ts index 3b06325..974b502 100644 --- a/xsendMany.ts +++ b/xsendMany.ts @@ -22,7 +22,7 @@ export async function sendFCMNotificationMany({ token, title, body, data }: { to title, body, }, - token, + tokens:token, data, android: { priority: "high", @@ -42,10 +42,7 @@ export async function sendFCMNotificationMany({ token, title, body, data }: { to }; // Kirim pesan - const response = await getMessaging().sendEachForMulticast({ - tokens: token, - ...message, - } as any); + const response = await getMessaging().sendEachForMulticast(message as any); if (response.failureCount > 0) { const failedTokens: any[] = []; response.responses.forEach((resp, idx) => { @@ -59,6 +56,5 @@ export async function sendFCMNotificationMany({ token, title, body, data }: { to return { success: true, message: "Notifikasi berhasil dikirim", }; } catch (error) { console.error("Error mengirim notifikasi:", error); - throw error; } } \ No newline at end of file