From b9354cb6bf7d568b1281ae21d14f2aceaee570d8 Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Tue, 13 Jan 2026 17:45:37 +0800 Subject: [PATCH 1/4] Penerapan notifikasi pada event Fix: - src/app/api/mobile/admin/event/[id]/route.ts - src/app/api/mobile/admin/job/[id]/route.ts - src/app/api/mobile/event/route.ts - src/app/api/mobile/job/route.ts - src/app/api/mobile/notification/[id]/route.ts - src/lib/mobile/notification/send-notification.ts - src/lib/mobile/route-page-mobile.ts - types/type-mobile-notification.ts ### No Issue --- src/app/api/mobile/admin/event/[id]/route.ts | 57 +++- src/app/api/mobile/admin/job/[id]/route.ts | 10 +- src/app/api/mobile/event/route.ts | 20 ++ src/app/api/mobile/job/route.ts | 5 +- src/app/api/mobile/notification/[id]/route.ts | 257 +++++++++--------- .../mobile/notification/send-notification.ts | 12 +- src/lib/mobile/route-page-mobile.ts | 11 +- types/type-mobile-notification.ts | 10 +- 8 files changed, 241 insertions(+), 141 deletions(-) diff --git a/src/app/api/mobile/admin/event/[id]/route.ts b/src/app/api/mobile/admin/event/[id]/route.ts index 1215c1ea..0f1b534c 100644 --- a/src/app/api/mobile/admin/event/[id]/route.ts +++ b/src/app/api/mobile/admin/event/[id]/route.ts @@ -1,6 +1,15 @@ import { NextResponse } from "next/server"; import prisma from "@/lib/prisma"; import _ from "lodash"; +import { + sendNotificationMobileToManyUser, + sendNotificationMobileToOneUser, +} from "@/lib/mobile/notification/send-notification"; +import { + NotificationMobileBodyType, + NotificationMobileTitleType, +} from "../../../../../../../types/type-mobile-notification"; +import { routeUserMobile } from "@/lib/mobile/route-page-mobile"; export { GET, PUT }; @@ -57,6 +66,8 @@ async function GET(request: Request, { params }: { params: { id: string } }) { async function PUT(request: Request, { params }: { params: { id: string } }) { const { id } = params; const { data } = await request.json(); + const { catatan, senderId } = data; + const { searchParams } = new URL(request.url); const status = searchParams.get("status"); const fixStatus = _.startCase(status as string); @@ -89,11 +100,23 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { id: id, }, data: { - catatan: data, + catatan: catatan, eventMaster_StatusId: checkStatus.id, }, }); + await sendNotificationMobileToOneUser({ + recipientId: updateData.authorId as any, + senderId: senderId, + payload: { + title: "Pengajuan Review Ditolak", + body: "Mohon perbaiki data sesuai catatan penolakan !", + type: "announcement", + kategoriApp: "EVENT", + deepLink: routeUserMobile.eventByStatus({status: "reject"}), + }, + }); + fixData = updateData; } else if (fixStatus === "Publish") { const updateData = await prisma.event.update({ @@ -105,6 +128,38 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { }, }); + await sendNotificationMobileToOneUser({ + recipientId: updateData.authorId as any, + senderId: senderId, + payload: { + title: "Review Selesai", + body: "Event kamu telah dipublikasikan !" as NotificationMobileBodyType, + type: "announcement", + kategoriApp: "EVENT", + deepLink: routeUserMobile.eventByStatus({status: "publish"}), + }, + }); + + const adminUsers = await prisma.user.findMany({ + where: { + masterUserRoleId: "1", + NOT: { id: updateData.authorId as any }, + }, + select: { id: true }, + }); + + await sendNotificationMobileToManyUser({ + recipientIds: adminUsers.map((user) => user.id), + senderId: senderId, + payload: { + title: "Event Baru" as NotificationMobileTitleType, + body: `${updateData.title}` as NotificationMobileBodyType, + type: "announcement", + kategoriApp: "EVENT", + deepLink: routeUserMobile.eventDetailPublised({ id: id }), + }, + }); + fixData = updateData; } diff --git a/src/app/api/mobile/admin/job/[id]/route.ts b/src/app/api/mobile/admin/job/[id]/route.ts index bc2fe57e..36811210 100644 --- a/src/app/api/mobile/admin/job/[id]/route.ts +++ b/src/app/api/mobile/admin/job/[id]/route.ts @@ -6,7 +6,7 @@ import { sendNotificationMobileToOneUser, } from "@/lib/mobile/notification/send-notification"; import { routeUserMobile } from "@/lib/mobile/route-page-mobile"; -import { NotificationMobileBodyType } from "../../../../../../../types/type-mobile-notification"; +import { NotificationMobileBodyType, NotificationMobileTitleType } from "../../../../../../../types/type-mobile-notification"; export { GET, PUT }; @@ -110,8 +110,8 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { recipientId: updt.authorId as any, senderId: senderId, payload: { - title: "Pengajuan Review", - body: "Pengajuan data anda telah di tolak !", + title: "Pengajuan Review Ditolak", + body: "Mohon perbaiki data sesuai catatan penolakan !", type: "announcement", kategoriApp: "JOB", deepLink: routeUserMobile.jobByStatus({ status: "reject" }), @@ -143,7 +143,7 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { recipientId: updt.authorId as any, senderId: senderId, payload: { - title: "Pengajuan Review", + title: "Review Selesai", body: "Selamat data anda telah terpublikasi", type: "announcement", kategoriApp: "JOB", @@ -160,7 +160,7 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { recipientIds: adminUsers.map((user) => user.id), senderId: data.authorId, payload: { - title: "Ada lowongan kerja baru", + title: "Ada Lowongan Kerja Baru" as NotificationMobileTitleType, body: `${updt.title}` as NotificationMobileBodyType, type: "announcement", deepLink: routeUserMobile.jobDetailPublised({ id: id }), diff --git a/src/app/api/mobile/event/route.ts b/src/app/api/mobile/event/route.ts index 705ed953..2d9f48d5 100644 --- a/src/app/api/mobile/event/route.ts +++ b/src/app/api/mobile/event/route.ts @@ -1,7 +1,10 @@ +import { sendNotificationMobileToManyUser } from "@/lib/mobile/notification/send-notification"; +import { routeAdminMobile } from "@/lib/mobile/route-page-mobile"; import prisma from "@/lib/prisma"; import _ from "lodash"; import moment from "moment"; import { NextResponse } from "next/server"; +import { NotificationMobileBodyType } from "../../../../../types/type-mobile-notification"; export { GET, POST }; @@ -30,6 +33,23 @@ async function POST(request: Request) { }, }); + const adminUsers = await prisma.user.findMany({ + where: { masterUserRoleId: "2", NOT: { id: data.authorId } }, + select: { id: true }, + }); + + await sendNotificationMobileToManyUser({ + recipientIds: adminUsers.map((user) => user.id), + senderId: data.authorId, + payload: { + title: "Pengajuan Review Baru", + body: create.title as NotificationMobileBodyType, + type: "announcement", + deepLink: routeAdminMobile.eventByStatus({ status: "review" }), + kategoriApp: "EVENT", + }, + }); + return NextResponse.json( { success: true, diff --git a/src/app/api/mobile/job/route.ts b/src/app/api/mobile/job/route.ts index d2c61abe..460e2d11 100644 --- a/src/app/api/mobile/job/route.ts +++ b/src/app/api/mobile/job/route.ts @@ -2,6 +2,7 @@ import { sendNotificationMobileToManyUser } from "@/lib/mobile/notification/send import { routeAdminMobile } from "@/lib/mobile/route-page-mobile"; import prisma from "@/lib/prisma"; import { NextResponse } from "next/server"; +import { NotificationMobileBodyType } from "../../../../../types/type-mobile-notification"; export { POST, GET }; @@ -30,8 +31,8 @@ async function POST(request: Request) { recipientIds: adminUsers.map((user) => user.id), senderId: data.authorId, payload: { - title: "Pengajuan Review", - body: "Terdapat pengajuan baru yang perlu direview", + title: "Pengajuan Review Baru", + body: `${create.title}` as NotificationMobileBodyType, type: "announcement", deepLink: routeAdminMobile.jobByStatus({ status: "review" }), kategoriApp: "JOB", diff --git a/src/app/api/mobile/notification/[id]/route.ts b/src/app/api/mobile/notification/[id]/route.ts index e9a03897..0a3275b6 100644 --- a/src/app/api/mobile/notification/[id]/route.ts +++ b/src/app/api/mobile/notification/[id]/route.ts @@ -45,23 +45,38 @@ export async function PUT( { params }: { params: { id: string } } ) { const { id } = params; + const { searchParams } = new URL(request.url); + const category = searchParams.get("category"); try { - await prisma.notifikasi.update({ - where: { - id: id, - }, - data: { - isRead: true, - readAt: new Date(), - }, - }); + if (category === "one") { + await prisma.notifikasi.update({ + where: { + id: id, + }, + data: { + isRead: true, + readAt: new Date(), + }, + }); + } else if (category === "all") { + await prisma.notifikasi.updateMany({ + where: { + recipientId: id, + }, + data: { + isRead: true, + readAt: new Date(), + }, + }); + } return NextResponse.json({ success: true, message: "Notifications marked as read", }); } catch (error) { + console.error("Error marking notifications as read:", error); return NextResponse.json( { error: (error as Error).message }, { status: 500 } @@ -69,129 +84,129 @@ export async function PUT( } } -export async function POST( - request: NextRequest, - { params }: { params: { id: string } } -) { - const { id } = params; +// export async function POST( +// request: NextRequest, +// { params }: { params: { id: string } } +// ) { +// const { id } = params; - const { data } = await request.json(); +// const { data } = await request.json(); - const { - title, - body: notificationBody, - userLoginId, - type, - kategoriApp, - appId, - status, - deepLink, - } = data as NotificationProp; +// const { +// title, +// body: notificationBody, +// userLoginId, +// type, +// kategoriApp, +// appId, +// status, +// deepLink, +// } = data as NotificationProp; - console.log("Notification Send >>", data); +// console.log("Notification Send >>", data); - try { - // Cari user yang login - const findUserLogin = await prisma.user.findUnique({ - where: { - id: userLoginId, - }, - }); +// try { +// // Cari user yang login +// const findUserLogin = await prisma.user.findUnique({ +// where: { +// id: userLoginId, +// }, +// }); - if (!findUserLogin) { - return NextResponse.json({ error: "User not found" }, { status: 404 }); - } +// if (!findUserLogin) { +// return NextResponse.json({ error: "User not found" }, { status: 404 }); +// } - // Cari token fcm user yang login - const checkFcmToken = await prisma.tokenUserDevice.findFirst({ - where: { - userId: findUserLogin.id, - }, - }); +// // Cari token fcm user yang login +// const checkFcmToken = await prisma.tokenUserDevice.findFirst({ +// where: { +// userId: findUserLogin.id, +// }, +// }); - if (!checkFcmToken) { - return NextResponse.json( - { error: "FCM Token not found" }, - { status: 404 } - ); - } +// if (!checkFcmToken) { +// return NextResponse.json( +// { error: "FCM Token not found" }, +// { status: 404 } +// ); +// } - const created = await prisma.notifikasi.create({ - data: { - title, - type, - createdAt: new Date(), - appId, - kategoriApp, - pesan: notificationBody || "", - userRoleId: findUserLogin.masterUserRoleId, - status, - deepLink, - senderId: findUserLogin.id, - recipientId: id, - }, - }); +// const created = await prisma.notifikasi.create({ +// data: { +// title, +// type, +// createdAt: new Date(), +// appId, +// kategoriApp, +// pesan: notificationBody || "", +// userRoleId: findUserLogin.masterUserRoleId, +// status, +// deepLink, +// senderId: findUserLogin.id, +// recipientId: id, +// }, +// }); - if (created) { - const deviceToken = await prisma.tokenUserDevice.findMany({ - where: { - userId: id, - isActive: true, - }, - }); +// if (created) { +// const deviceToken = await prisma.tokenUserDevice.findMany({ +// where: { +// userId: id, +// isActive: true, +// }, +// }); - for (let i of deviceToken) { - const message = { - token: i.token, - notification: { - title, - body: notificationBody || "", - }, - data: { - sentAt: new Date().toISOString(), // ✅ Simpan metadata di data - id: created.id, - deepLink: deepLink || "", - }, - // Konfigurasi Android untuk prioritas tinggi - android: { - priority: "high" as const, // Kirim secepatnya, bahkan di doze mode untuk notifikasi penting - notification: { - channelId: "default", // Sesuaikan dengan channel yang kamu buat di Android - }, +// for (let i of deviceToken) { +// const message = { +// token: i.token, +// notification: { +// title, +// body: notificationBody || "", +// }, +// data: { +// sentAt: new Date().toISOString(), // ✅ Simpan metadata di data +// id: created.id, +// deepLink: deepLink || "", +// }, +// // Konfigurasi Android untuk prioritas tinggi +// android: { +// priority: "high" as const, // Kirim secepatnya, bahkan di doze mode untuk notifikasi penting +// notification: { +// channelId: "default", // Sesuaikan dengan channel yang kamu buat di Android +// }, - ttl: 0 as const, // Kirim secepatnya, jangan tunda - }, - // Opsional: tambahkan untuk iOS juga - apns: { - payload: { - aps: { - sound: "default" as const, - // 'content-available': 1 as const, // jika butuh silent push - }, - }, - }, - }; +// ttl: 0 as const, // Kirim secepatnya, jangan tunda +// }, +// // Opsional: tambahkan untuk iOS juga +// apns: { +// payload: { +// aps: { +// sound: "default" as const, +// // 'content-available': 1 as const, // jika butuh silent push +// }, +// }, +// }, +// }; - try { - const response = await adminMessaging.send(message); - console.log("✅ FCM sent successfully", "Response:", response); - } catch (error: any) { - console.error("❌ FCM send failed:", error); - // Lanjutkan ke token berikutnya meski satu gagal - } - } - } +// try { +// const response = await adminMessaging.send(message); +// console.log("✅ FCM sent successfully", "Response:", response); +// } catch (error: any) { +// console.error("❌ FCM send failed:", error); +// // Lanjutkan ke token berikutnya meski satu gagal +// } +// } +// } - return NextResponse.json({ - success: true, - message: "Notification sent successfully", - }); - } catch (error) { - console.error("❌ FCM error:", error); +// return NextResponse.json({ +// success: true, +// message: "Notification sent successfully", +// }); +// } catch (error) { +// console.error("❌ FCM error:", error); - return NextResponse.json( - { error: (error as Error).message }, - { status: 500 } - ); - } -} +// return NextResponse.json( +// { error: (error as Error).message }, +// { status: 500 } +// ); +// } +// } diff --git a/src/lib/mobile/notification/send-notification.ts b/src/lib/mobile/notification/send-notification.ts index 7299890b..86ca28fd 100644 --- a/src/lib/mobile/notification/send-notification.ts +++ b/src/lib/mobile/notification/send-notification.ts @@ -43,7 +43,7 @@ export async function sendNotificationMobileToOneUser({ // 2. Ambil semua token aktif milik penerima const tokens = await prisma.tokenUserDevice.findMany({ - where: { userId: recipientId, isActive: true }, + where: { userId: recipientId }, select: { token: true, id: true }, }); @@ -53,7 +53,6 @@ export async function sendNotificationMobileToOneUser({ } // 3. Kirim FCM ke semua token - await Promise.allSettled( tokens.map(async ({ token, id }) => { try { @@ -80,12 +79,11 @@ export async function sendNotificationMobileToOneUser({ }); } catch (fcmError: any) { // Hapus token jika invalid - console.log("fcmError", fcmError); - if (fcmError.code === "messaging/invalid-registration-token") { - await prisma.tokenUserDevice.delete({ where: { id: id } }); - console.log(`❌ Invalid token removed: ${token}`); + if (fcmError.code === "messaging/registration-token-not-registered") { + // Hapus token dari DB + await prisma.tokenUserDevice.delete({ where: { id } }); + console.log(`🗑️ Invalid token removed: ${id}`); } - console.error(`FCM failed for token ${token}:`, fcmError.message); } }) ); diff --git a/src/lib/mobile/route-page-mobile.ts b/src/lib/mobile/route-page-mobile.ts index 5c7b7ed9..f9596d66 100644 --- a/src/lib/mobile/route-page-mobile.ts +++ b/src/lib/mobile/route-page-mobile.ts @@ -9,12 +9,21 @@ const routeAdminMobile = { `/admin/job/${id}/${status}`, jobByStatus: ({ status }: { status: StatusApp }) => `/admin/job/${status}/status`, + + // EVENT + eventByStatus: ({ status }: { status: StatusApp }) => + `/admin/event/${status}/status`, }; const routeUserMobile = { home: `/(user)/home`, // JOB - jobDetailPublised: ({ id }: { id: string }) => `/job/${id}`, jobByStatus: ({ status }: { status?: StatusApp }) => `/job/(tabs)/status?status=${status}`, + jobDetailPublised: ({ id }: { id: string }) => `/job/${id}`, + + // EVENT + eventByStatus: ({ status }: { status?: StatusApp }) => + `/event/(tabs)/status?status=${status}`, + eventDetailPublised: ({ id }: { id: string }) => `/event/${id}/publish`, }; diff --git a/types/type-mobile-notification.ts b/types/type-mobile-notification.ts index cc966439..ef9cb95f 100644 --- a/types/type-mobile-notification.ts +++ b/types/type-mobile-notification.ts @@ -13,18 +13,20 @@ export type NotificationMobilePayload = { export type NotificationMobileTitleType = | (string & { __type: "NotificationMobileTitleType" }) - | "Pengajuan Review" + // Admin + | "Pengajuan Review Baru" + // USER + | "Pengajuan Review Ditolak" | "Review Selesai" // to ALL user - | "Ada lowongan kerja baru" export type NotificationMobileBodyType = // USER | (string & { __type: "NotificationMobileBodyType" }) - | "Terdapat pengajuan baru yang perlu direview" + | "Ada pengajuan review" // tambah title // ADMIN - | "Pengajuan data anda telah di tolak !" + | "Mohon perbaiki data sesuai catatan penolakan !" | "Selamat data anda telah terpublikasi" export type TypeNotificationCategoryApp = From 3a558cec8ef565eca840b49726309b88f9a09e3e Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Tue, 13 Jan 2026 17:45:58 +0800 Subject: [PATCH 2/4] chore(release): 1.5.36 --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17453ee1..efc63381 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. +## [1.5.36](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.35...v1.5.36) (2026-01-13) + ## [1.5.35](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.34...v1.5.35) (2026-01-12) ## [1.5.34](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.33...v1.5.34) (2026-01-09) diff --git a/package.json b/package.json index db5e4a7a..64915a43 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hipmi", - "version": "1.5.35", + "version": "1.5.36", "private": true, "prisma": { "seed": "bun prisma/seed.ts" From c8bd928c330b068488c3ce6a1d433031fdeb0f81 Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Thu, 15 Jan 2026 13:57:00 +0800 Subject: [PATCH 3/4] Fix notifikasi join dari event Fix: modified: src/app/api/mobile/event/[id]/participants/route.ts modified: src/bin/seeder/user_seeder.json ### No Issue --- .../mobile/event/[id]/participants/route.ts | 36 +++++++++++++------ src/bin/seeder/user_seeder.json | 4 +-- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/app/api/mobile/event/[id]/participants/route.ts b/src/app/api/mobile/event/[id]/participants/route.ts index 062a0ab5..c0d2b46b 100644 --- a/src/app/api/mobile/event/[id]/participants/route.ts +++ b/src/app/api/mobile/event/[id]/participants/route.ts @@ -1,5 +1,11 @@ +import { sendNotificationMobileToOneUser } from "@/lib/mobile/notification/send-notification"; import prisma from "@/lib/prisma"; import { NextResponse } from "next/server"; +import { + NotificationMobileBodyType, + NotificationMobileTitleType, +} from "../../../../../../../types/type-mobile-notification"; +import { routeUserMobile } from "@/lib/mobile/route-page-mobile"; export { GET, POST }; @@ -13,18 +19,28 @@ async function POST(request: Request, { params }: { params: { id: string } }) { eventId: id, userId: userId, }, - - // select: { - // Event: { - // select: { - // id: true, - // title: true, - // authorId: true, - // }, - // }, - // }, }); + const findEvent = await prisma.event.findUnique({ + where: { id: id }, + select: { authorId: true, title: true }, + }); + + // SEND NOTIFICATION + if (userId !== findEvent?.authorId) { + await sendNotificationMobileToOneUser({ + recipientId: findEvent?.authorId as string, + senderId: userId, + payload: { + title: "Peserta Baru Join" as NotificationMobileTitleType, + body: `Ada peserta baru dalam event: ${findEvent?.title}` as NotificationMobileBodyType, + type: "announcement", + deepLink: routeUserMobile.eventDetailPublised({ id: id }), + kategoriApp: "EVENT", + }, + }); + } + return NextResponse.json( { success: true, diff --git a/src/bin/seeder/user_seeder.json b/src/bin/seeder/user_seeder.json index d4b739fc..91e497e4 100644 --- a/src/bin/seeder/user_seeder.json +++ b/src/bin/seeder/user_seeder.json @@ -1,13 +1,13 @@ [ { - "name": "default_user", + "name": "demo_user", "nomor": "6282340374412", "masterUserRoleId": "1", "active": true, "termsOfServiceAccepted": false }, { - "name": "admin_911", + "name": "demo_admin", "nomor": "6281339158911", "masterUserRoleId": "3", "active": true, From d09e30c04994bc1000124f3ed9faf94f3d447fac Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Thu, 15 Jan 2026 17:38:33 +0800 Subject: [PATCH 4/4] Voting notifikasi for mobile Fix: - src/app/api/mobile/admin/voting/[id]/route.ts - src/app/api/mobile/event/route.ts - src/app/api/mobile/voting/[id]/route.ts - src/app/api/mobile/voting/route.ts - src/lib/mobile/route-page-mobile.ts ### No Issue --- src/app/api/mobile/admin/voting/[id]/route.ts | 66 ++++++++++++++++++- src/app/api/mobile/event/route.ts | 1 + src/app/api/mobile/voting/[id]/route.ts | 43 +++++++++--- src/app/api/mobile/voting/route.ts | 23 ++++++- src/lib/mobile/route-page-mobile.ts | 11 +++- 5 files changed, 127 insertions(+), 17 deletions(-) diff --git a/src/app/api/mobile/admin/voting/[id]/route.ts b/src/app/api/mobile/admin/voting/[id]/route.ts index e88bdccb..0392ee11 100644 --- a/src/app/api/mobile/admin/voting/[id]/route.ts +++ b/src/app/api/mobile/admin/voting/[id]/route.ts @@ -1,8 +1,17 @@ import { NextResponse } from "next/server"; import { prisma } from "@/lib"; import _ from "lodash"; +import { + sendNotificationMobileToManyUser, + sendNotificationMobileToOneUser, +} from "@/lib/mobile/notification/send-notification"; +import { routeUserMobile } from "@/lib/mobile/route-page-mobile"; +import { + NotificationMobileBodyType, + NotificationMobileTitleType, +} from "../../../../../../../types/type-mobile-notification"; -export { GET , PUT}; +export { GET, PUT }; async function GET(request: Request, { params }: { params: { id: string } }) { const { id } = params; @@ -41,12 +50,16 @@ async function GET(request: Request, { params }: { params: { id: string } }) { async function PUT(request: Request, { params }: { params: { id: string } }) { const { id } = params; const { data } = await request.json(); + const { catatan, senderId } = data; + + console.log("catatan", catatan); + console.log("senderId", senderId); + const { searchParams } = new URL(request.url); const status = searchParams.get("status"); const fixStatus = _.startCase(status as string); let fixData; - try { const checkStatus = await prisma.voting_Status.findFirst({ where: { @@ -71,9 +84,23 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { }, data: { voting_StatusId: checkStatus.id, - catatan: data, + catatan: catatan, }, }); + + // SEND NOTIFICATION + await sendNotificationMobileToOneUser({ + recipientId: updateStatus.authorId as any, + senderId: senderId, + payload: { + title: "Pengajuan Review Ditolak", + body: "Mohon perbaiki data sesuai catatan penolakan !", + type: "announcement", + kategoriApp: "VOTING", + deepLink: routeUserMobile.votingByStatus({ status: "reject" }), + }, + }); + fixData = updateStatus; } else if (fixStatus === "Publish") { const updateStatus = await prisma.voting.update({ @@ -84,6 +111,39 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { voting_StatusId: checkStatus.id, }, }); + + await sendNotificationMobileToOneUser({ + recipientId: updateStatus.authorId as any, + senderId: senderId, + payload: { + title: "Review Selesai", + body: "Voting kamu telah dipublikasikan !" as NotificationMobileBodyType, + type: "announcement", + kategoriApp: "VOTING", + deepLink: routeUserMobile.votingByStatus({ status: "publish" }), + }, + }); + + const adminUsers = await prisma.user.findMany({ + where: { + masterUserRoleId: "1", + NOT: { id: updateStatus.authorId as any }, + }, + select: { id: true }, + }); + + await sendNotificationMobileToManyUser({ + recipientIds: adminUsers.map((user) => user.id), + senderId: senderId, + payload: { + title: "Cek Voting Baru Terpublikasi" as NotificationMobileTitleType, + body: `${updateStatus.title}` as NotificationMobileBodyType, + type: "announcement", + kategoriApp: "VOTING", + deepLink: routeUserMobile.votingDetailPublised({ id: id }), + }, + }); + fixData = updateStatus; } diff --git a/src/app/api/mobile/event/route.ts b/src/app/api/mobile/event/route.ts index 2d9f48d5..9dc25a2c 100644 --- a/src/app/api/mobile/event/route.ts +++ b/src/app/api/mobile/event/route.ts @@ -38,6 +38,7 @@ async function POST(request: Request) { select: { id: true }, }); + // SEND NOTIFICATION await sendNotificationMobileToManyUser({ recipientIds: adminUsers.map((user) => user.id), senderId: data.authorId, diff --git a/src/app/api/mobile/voting/[id]/route.ts b/src/app/api/mobile/voting/[id]/route.ts index a6ff1597..39f9aaf5 100644 --- a/src/app/api/mobile/voting/[id]/route.ts +++ b/src/app/api/mobile/voting/[id]/route.ts @@ -1,6 +1,12 @@ import { NextResponse } from "next/server"; import prisma from "@/lib/prisma"; import _ from "lodash"; +import { sendNotificationMobileToOneUser } from "@/lib/mobile/notification/send-notification"; +import { + NotificationMobileBodyType, + NotificationMobileTitleType, +} from "../../../../../../types/type-mobile-notification"; +import { routeUserMobile } from "@/lib/mobile/route-page-mobile"; export { GET, DELETE, PUT, POST }; @@ -39,7 +45,6 @@ async function GET(request: Request, { params }: { params: { id: string } }) { const listNamaVote = data?.Voting_DaftarNamaVote || []; for (let v of listNamaVote) { - const kontributor = await prisma.voting_Kontributor.findMany({ where: { voting_DaftarNamaVoteId: v.id, @@ -90,7 +95,6 @@ async function DELETE( }, }); - return NextResponse.json({ success: true, message: "Berhasil menghapus data", @@ -171,7 +175,6 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { }, }); - if (!updateVoting) return NextResponse.json({ status: 400, message: "Gagal Update" }); } @@ -193,11 +196,12 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { async function POST(request: Request, { params }: { params: { id: string } }) { const { id } = params; const { data } = await request.json(); + const { chooseId, userId } = data; try { - const findData = await prisma.voting_DaftarNamaVote.findFirst({ + const findDatapilihan = await prisma.voting_DaftarNamaVote.findFirst({ where: { - id: data.chooseId, + id: chooseId, }, select: { jumlah: true, @@ -205,28 +209,32 @@ async function POST(request: Request, { params }: { params: { id: string } }) { }, }); - if (!findData) + if (!findDatapilihan) return NextResponse.json({ success: false, message: "Data tidak ditemukan", }); - const updateData = await prisma.voting_DaftarNamaVote.update({ + const updateDataPilihan = await prisma.voting_DaftarNamaVote.update({ where: { id: data.chooseId, }, data: { - jumlah: findData.jumlah + 1, + jumlah: findDatapilihan.jumlah + 1, }, }); - - if (!updateData) + if (!updateDataPilihan) return NextResponse.json({ success: false, message: "Gagal Update Data", }); + const findVotingData = await prisma.voting.findUnique({ + where: { id: id }, + select: { authorId: true, title: true }, + }); + const createKontributor = await prisma.voting_Kontributor.create({ data: { votingId: id, @@ -250,6 +258,21 @@ async function POST(request: Request, { params }: { params: { id: string } }) { message: "Gagal Menjadi Kontributor", }); + // SEND NOTIFICATION + if (userId !== findVotingData?.authorId) { + await sendNotificationMobileToOneUser({ + recipientId: findVotingData?.authorId as string, + senderId: userId, + payload: { + title: "User Melakukan Vote" as NotificationMobileTitleType, + body: `Salah satu user telah melakukan voting pada: ${findVotingData?.title}` as NotificationMobileBodyType, + type: "announcement", + deepLink: routeUserMobile.votingDetailPublised({ id: id }), + kategoriApp: "VOTING", + }, + }); + } + return NextResponse.json({ success: true, message: "Berhasil Voting", diff --git a/src/app/api/mobile/voting/route.ts b/src/app/api/mobile/voting/route.ts index a7dc3f49..659e6621 100644 --- a/src/app/api/mobile/voting/route.ts +++ b/src/app/api/mobile/voting/route.ts @@ -1,6 +1,9 @@ import { NextResponse } from "next/server"; import prisma from "@/lib/prisma"; import _ from "lodash"; +import { sendNotificationMobileToManyUser } from "@/lib/mobile/notification/send-notification"; +import { NotificationMobileBodyType } from "../../../../../types/type-mobile-notification"; +import { routeAdminMobile } from "@/lib/mobile/route-page-mobile"; export { POST, GET }; @@ -41,6 +44,24 @@ async function POST(request: Request) { }); } + const adminUsers = await prisma.user.findMany({ + where: { masterUserRoleId: "2", NOT: { id: data.authorId } }, + select: { id: true }, + }); + + // SEND NOTIFICATION + await sendNotificationMobileToManyUser({ + recipientIds: adminUsers.map((user) => user.id), + senderId: data.authorId, + payload: { + title: "Pengajuan Review Baru", + body: create.title as NotificationMobileBodyType, + type: "announcement", + deepLink: routeAdminMobile.votingByStatus({ status: "review" }), + kategoriApp: "VOTING", + }, + }); + return NextResponse.json( { success: true, @@ -125,8 +146,6 @@ async function GET(request: Request) { }); fixData = data; - - } else if (category === "contribution") { const data = await prisma.voting_Kontributor.findMany({ orderBy: { diff --git a/src/lib/mobile/route-page-mobile.ts b/src/lib/mobile/route-page-mobile.ts index f9596d66..ef8ae87b 100644 --- a/src/lib/mobile/route-page-mobile.ts +++ b/src/lib/mobile/route-page-mobile.ts @@ -5,14 +5,16 @@ type StatusApp = "review" | "draft" | "reject" | "publish"; const routeAdminMobile = { userAccess: ({ id }: { id: string }) => `/admin/user-access/${id}`, // JOB - jobDetail: ({ id, status }: { id: string; status: StatusApp }) => - `/admin/job/${id}/${status}`, jobByStatus: ({ status }: { status: StatusApp }) => `/admin/job/${status}/status`, // EVENT eventByStatus: ({ status }: { status: StatusApp }) => `/admin/event/${status}/status`, + + // VOTING + votingByStatus: ({ status }: { status: StatusApp }) => + `/admin/voting/${status}/status`, }; const routeUserMobile = { @@ -26,4 +28,9 @@ const routeUserMobile = { eventByStatus: ({ status }: { status?: StatusApp }) => `/event/(tabs)/status?status=${status}`, eventDetailPublised: ({ id }: { id: string }) => `/event/${id}/publish`, + + // VOTING + votingByStatus: ({ status }: { status?: StatusApp }) => + `/voting/(tabs)/status?status=${status}`, + votingDetailPublised: ({ id }: { id: string }) => `/voting/${id}`, };