Merge pull request 'Notification Donasi & EULA on login' (#45) from mobile-notification/23-jan-26 into staging

Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi/pulls/45
This commit is contained in:
2026-01-23 17:06:56 +08:00
19 changed files with 381 additions and 103 deletions

View File

@@ -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. 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.37](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.36...v1.5.37) (2026-01-23)
## [1.5.36](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.35...v1.5.36) (2026-01-13) ## [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.35](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.34...v1.5.35) (2026-01-12)

View File

@@ -1,6 +1,6 @@
{ {
"name": "hipmi", "name": "hipmi",
"version": "1.5.36", "version": "1.5.37",
"private": true, "private": true,
"prisma": { "prisma": {
"seed": "bun prisma/seed.ts" "seed": "bun prisma/seed.ts"

View File

@@ -295,7 +295,7 @@
<p>You have the right to request access to the personal information we collect from you, details about how we have processed it, correct inaccuracies, or delete your personal information. You may also have the right to withdraw your consent to our processing of your personal information. These rights may be limited in some circumstances by applicable law.</p> <p>You have the right to request access to the personal information we collect from you, details about how we have processed it, correct inaccuracies, or delete your personal information. You may also have the right to withdraw your consent to our processing of your personal information. These rights may be limited in some circumstances by applicable law.</p>
<p>To make a request, please contact us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p> <p>To make a request, please contact us at <a href="mailto:bip.baliinteraktifperkasa@gmail.com">bip.baliinteraktifperkasa@gmail.com</a>.</p>
<hr style="margin: 30px 0; border: 0; border-top: 1px solid #eee;"> <hr style="margin: 30px 0; border: 0; border-top: 1px solid #eee;">
<p>© 2025 Bali Interaktif Perkasa. All rights reserved.</p> <p>© 2026 Bali Interaktif Perkasa. All rights reserved.</p>
</body> </body>
</html> </html>

View File

@@ -104,7 +104,7 @@
</p> </p>
<footer> <footer>
<p>© 2025 Bali Interaktif Perkasa. All rights reserved.</p> <p>© 2026 Bali Interaktif Perkasa. All rights reserved.</p>
</footer> </footer>
</body> </body>
</html> </html>

View File

@@ -2,12 +2,13 @@ import { prisma } from "@/lib";
import { randomOTP } from "@/app_modules/auth/fun/rondom_otp"; import { randomOTP } from "@/app_modules/auth/fun/rondom_otp";
import backendLogger from "@/util/backendLogger"; import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { sendCodeOtp } from "@/lib/code-otp-sender";
export async function POST(req: Request) { export async function POST(req: Request) {
if (req.method !== "POST") { if (req.method !== "POST") {
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Method Not Allowed" }, { success: false, message: "Method Not Allowed" },
{ status: 405 } { status: 405 },
); );
} }
@@ -26,29 +27,21 @@ export async function POST(req: Request) {
if (!createOtpId) if (!createOtpId)
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Gagal mengirim kode OTP" }, { success: false, message: "Gagal mengirim kode OTP" },
{ status: 400 } { status: 400 },
); );
const msg = `HIPMI%20-%20Kode%20ini%20bersifat%20RAHASIA%20dan%20JANGAN%20DI%20BAGIKAN%20KEPADA%20SIAPAPUN%2C%20termasuk%20anggota%20ataupun%20pengurus%20HIPMI%20lainnya.%5Cn%5Cn%3E%3E%20Kode%20OTP%20anda%3A%20${codeOtp}.`; const resSendCode = await sendCodeOtp({
// const encodedMsg = encodeURIComponent(msg); nomor,
codeOtp: codeOtp.toString(),
});
const res = await fetch( if (resSendCode.status !== 200)
`https://cld-dkr-prod-wajs-server.wibudev.com/api/wa/code?nom=${nomor}&text=${msg}`,
{
cache: "no-cache",
headers: {
Authorization: `Bearer ${process.env.WA_SERVER_TOKEN}`,
},
}
);
if (res.status !== 200)
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Nomor Whatsapp Tidak Aktif" }, { success: false, message: "Nomor Whatsapp Tidak Aktif" },
{ status: 400 } { status: 400 },
); );
const sendWa = await res.text(); const sendWa = await resSendCode.text();
console.log("WA Response:", sendWa); console.log("WA Response:", sendWa);
return NextResponse.json( return NextResponse.json(
@@ -57,7 +50,7 @@ export async function POST(req: Request) {
message: "Kode verifikasi terkirim", message: "Kode verifikasi terkirim",
kodeId: createOtpId.id, kodeId: createOtpId.id,
}, },
{ status: 200 } { status: 200 },
); );
} catch (error) { } catch (error) {
backendLogger.log("Error Login", error); backendLogger.log("Error Login", error);
@@ -67,7 +60,7 @@ export async function POST(req: Request) {
message: "Terjadi masalah saat login", message: "Terjadi masalah saat login",
reason: error as Error, reason: error as Error,
}, },
{ status: 500 } { status: 500 },
); );
} }
} }

View File

@@ -1,6 +1,7 @@
import { prisma } from "@/lib"; import { prisma } from "@/lib";
import { randomOTP } from "@/app_modules/auth/fun/rondom_otp"; import { randomOTP } from "@/app_modules/auth/fun/rondom_otp";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { sendCodeOtp } from "@/lib/code-otp-sender";
export async function POST(req: Request) { export async function POST(req: Request) {
try { try {
@@ -31,30 +32,21 @@ export async function POST(req: Request) {
if (!createOtpId) if (!createOtpId)
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Gagal mengirim kode OTP" }, { success: false, message: "Gagal mengirim kode OTP" },
{ status: 400 } { status: 400 },
); );
// const msg = `HIPMI - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPAADA SIAPAPUN, termasuk anggota ataupun pengurus HIPMI lainnya.\n\n\n> Kode OTP anda: ${codeOtp}.`; const resSendCode = await sendCodeOtp({
// const encodedMsg = encodeURIComponent(msg); nomor,
const msg = `HIPMI%20-%20Kode%20ini%20bersifat%20RAHASIA%20dan%20JANGAN%20DI%20BAGIKAN%20KEPADA%20SIAPAPUN%2C%20termasuk%20anggota%20ataupun%20pengurus%20HIPMI%20lainnya.%20Kode%20OTP%20anda%3A%20${codeOtp}.`; codeOtp: codeOtp.toString(),
});
const res = await fetch( if (resSendCode.status !== 200)
`https://cld-dkr-prod-wajs-server.wibudev.com/api/wa/code?nom=${nomor}&text=${msg}`,
{
cache: "no-cache",
headers: {
Authorization: `Bearer ${process.env.WA_SERVER_TOKEN}`,
},
}
);
if (res.status !== 200)
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Nomor Whatsapp Tidak Aktif" }, { success: false, message: "Nomor Whatsapp Tidak Aktif" },
{ status: 400 } { status: 400 },
); );
const sendWa = await res.text(); const sendWa = await resSendCode.text();
console.log("WA Response:", sendWa); console.log("WA Response:", sendWa);
return NextResponse.json( return NextResponse.json(
@@ -64,7 +56,7 @@ export async function POST(req: Request) {
kodeId: createOtpId.id, kodeId: createOtpId.id,
isAcceptTerms: user.termsOfServiceAccepted, isAcceptTerms: user.termsOfServiceAccepted,
}, },
{ status: 200 } { status: 200 },
); );
} catch (error) { } catch (error) {
return NextResponse.json( return NextResponse.json(
@@ -73,7 +65,7 @@ export async function POST(req: Request) {
message: "Terjadi masalah saat login", message: "Terjadi masalah saat login",
reason: error as Error, reason: error as Error,
}, },
{ status: 500 } { status: 500 },
); );
} }
} }

View File

@@ -7,6 +7,7 @@ import {
NotificationMobileBodyType, NotificationMobileBodyType,
NotificationMobileTitleType, NotificationMobileTitleType,
} from "../../../../../types/type-mobile-notification"; } from "../../../../../types/type-mobile-notification";
import { sendCodeOtp } from "@/lib/code-otp-sender";
export async function POST(req: Request) { export async function POST(req: Request) {
if (req.method !== "POST") { if (req.method !== "POST") {
@@ -69,23 +70,21 @@ export async function POST(req: Request) {
{ status: 400 } { status: 400 }
); );
// const msg = `HIPMI - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPAADA SIAPAPUN, termasuk anggota ataupun pengurus HIPMI lainnya.\n\n\n> Kode OTP anda: ${codeOtp}.`; const resSendCode = await sendCodeOtp({
const msg = `HIPMI%20-%20Kode%20ini%20bersifat%20RAHASIA%20dan%20JANGAN%20DI%20BAGIKAN%20KEPADA%20SIAPAPUN%2C%20termasuk%20anggota%20ataupun%20pengurus%20HIPMI%20lainnya.%20Kode%20OTP%20anda%3A%20${codeOtp}.`; nomor: data.nomor,
// // const encodedMsg = encodeURIComponent(msg); codeOtp: codeOtp.toString(),
});
const res = await fetch( if (resSendCode.status !== 200)
`https://wa.wibudev.com/code?nom=${data.nomor}&text=${msg}`,
{ cache: "no-cache" }
);
const sendWa = await res.json();
if (sendWa.status !== "success")
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Nomor Whatsapp Tidak Aktif" }, { success: false, message: "Nomor Whatsapp Tidak Aktif" },
{ status: 400 } { status: 400 },
); );
const sendWa = await resSendCode.text();
console.log("WA Response:", sendWa);
// =========== START SEND NOTIFICATION =========== // // =========== START SEND NOTIFICATION =========== //
const adminUsers = await prisma.user.findMany({ const adminUsers = await prisma.user.findMany({

View File

@@ -2,12 +2,13 @@ import { prisma } from "@/lib";
import { randomOTP } from "@/app_modules/auth/fun/rondom_otp"; import { randomOTP } from "@/app_modules/auth/fun/rondom_otp";
import backendLogger from "@/util/backendLogger"; import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { sendCodeOtp } from "@/lib/code-otp-sender";
export async function POST(req: Request) { export async function POST(req: Request) {
if (req.method !== "POST") { if (req.method !== "POST") {
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Method Not Allowed" }, { success: false, message: "Method Not Allowed" },
{ status: 405 } { status: 405 },
); );
} }
@@ -16,25 +17,18 @@ export async function POST(req: Request) {
const body = await req.json(); const body = await req.json();
const { nomor } = body; const { nomor } = body;
const msg = `HIPMI%20-%20Kode%20ini%20bersifat%20RAHASIA%20dan%20JANGAN%20DI%20BAGIKAN%20KEPADA%20SIAPAPUN%2C%20termasuk%20anggota%20ataupun%20pengurus%20HIPMI%20lainnya.%5Cn%5Cn%3E%3E%20Kode%20OTP%20anda%3A%20${codeOtp}.`; const resSendCode = await sendCodeOtp({
nomor,
codeOtp: codeOtp.toString(),
});
const res = await fetch( if (resSendCode.status !== 200)
`https://cld-dkr-prod-wajs-server.wibudev.com/api/wa/code?nom=${nomor}&text=${msg}`,
{
cache: "no-cache",
headers: {
Authorization: `Bearer ${process.env.WA_SERVER_TOKEN}`,
},
}
);
if (res.status !== 200)
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Nomor Whatsapp Tidak Aktif" }, { success: false, message: "Nomor Whatsapp Tidak Aktif" },
{ status: 400 } { status: 400 },
); );
const sendWa = await res.text(); const sendWa = await resSendCode.text();
console.log("WA Response:", sendWa); console.log("WA Response:", sendWa);
const createOtpId = await prisma.kodeOtp.create({ const createOtpId = await prisma.kodeOtp.create({
@@ -50,7 +44,7 @@ export async function POST(req: Request) {
success: false, success: false,
message: "Gagal Membuat Kode OTP", message: "Gagal Membuat Kode OTP",
}, },
{ status: 400 } { status: 400 },
); );
return NextResponse.json( return NextResponse.json(
@@ -59,7 +53,7 @@ export async function POST(req: Request) {
message: "Kode Verifikasi Dikirim", message: "Kode Verifikasi Dikirim",
kodeId: createOtpId.id, kodeId: createOtpId.id,
}, },
{ status: 200 } { status: 200 },
); );
} catch (error) { } catch (error) {
backendLogger.error(" Error Resend OTP", error); backendLogger.error(" Error Resend OTP", error);
@@ -68,7 +62,7 @@ export async function POST(req: Request) {
success: false, success: false,
message: "Server Whatsapp Error !!", message: "Server Whatsapp Error !!",
}, },
{ status: 500 } { status: 500 },
); );
} finally { } finally {
await prisma.$disconnect(); await prisma.$disconnect();

View File

@@ -1,6 +1,9 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { prisma } from "@/lib"; import { prisma } from "@/lib";
import _ from "lodash"; 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, PUT }; export { GET, PUT };
@@ -50,6 +53,7 @@ async function GET(req: Request, { params }: { params: { id: string } }) {
interface DataType { interface DataType {
donationId: string; donationId: string;
nominal: number; nominal: number;
senderId: string;
} }
async function PUT(req: Request, { params }: { params: { id: string } }) { async function PUT(req: Request, { params }: { params: { id: string } }) {
@@ -111,6 +115,9 @@ async function PUT(req: Request, { params }: { params: { id: string } }) {
data: { data: {
donasiMaster_StatusInvoiceId: checkStatusTransaksi.id, donasiMaster_StatusInvoiceId: checkStatusTransaksi.id,
}, },
select: {
authorId: true,
},
}); });
if (!updateInvoice) { if (!updateInvoice) {
@@ -154,6 +161,38 @@ async function PUT(req: Request, { params }: { params: { id: string } }) {
); );
} }
// SEND NOTIFICATION: to donatur
await sendNotificationMobileToOneUser({
recipientId: updateInvoice?.authorId as string,
senderId: data?.senderId || "",
payload: {
title: "Transaksi Berhasil" as NotificationMobileTitleType,
body: `Selamat anda menjadi donatur pada ${updateDonasi?.title}` as NotificationMobileBodyType,
type: "announcement",
kategoriApp: "DONASI",
deepLink: routeUserMobile.donationTransaction,
},
});
// SEND NOTIFICATION: to creator
await sendNotificationMobileToOneUser({
recipientId: updateDonasi?.authorId as any,
senderId: data?.senderId || "",
payload: {
title: "Ada Donatur Baru !" as NotificationMobileTitleType,
body: `Cek daftar donatur pada ${updateDonasi?.title}` as NotificationMobileBodyType,
type: "announcement",
kategoriApp: "DONASI",
deepLink: routeUserMobile.donationDetailPublish({
id: updateDonasi?.id as string,
}),
},
});
return NextResponse.json( return NextResponse.json(
{ {
success: true, success: true,

View File

@@ -1,6 +1,15 @@
import {
sendNotificationMobileToManyUser,
sendNotificationMobileToOneUser,
} from "@/lib/mobile/notification/send-notification";
import { routeUserMobile } from "@/lib/mobile/route-page-mobile";
import prisma from "@/lib/prisma"; import prisma from "@/lib/prisma";
import _ from "lodash"; import _ from "lodash";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import {
NotificationMobileBodyType,
NotificationMobileTitleType,
} from "../../../../../../../types/type-mobile-notification";
export { GET, PUT }; export { GET, PUT };
@@ -60,7 +69,7 @@ async function GET(request: Request, { params }: { params: { id: string } }) {
donatur: successInvoice, donatur: successInvoice,
}, },
}, },
{ status: 200 } { status: 200 },
); );
} catch (error) { } catch (error) {
return NextResponse.json( return NextResponse.json(
@@ -69,7 +78,7 @@ async function GET(request: Request, { params }: { params: { id: string } }) {
message: "Error get detail Investasi", message: "Error get detail Investasi",
reason: (error as Error).message, reason: (error as Error).message,
}, },
{ status: 500 } { status: 500 },
); );
} }
} }
@@ -77,6 +86,10 @@ async function GET(request: Request, { params }: { params: { id: string } }) {
async function PUT(request: Request, { params }: { params: { id: string } }) { async function PUT(request: Request, { params }: { params: { id: string } }) {
const { id } = params; const { id } = params;
const { data } = await request.json(); const { data } = await request.json();
const { catatan, senderId } = data;
console.log("[PUT CATATAN]", catatan);
console.log("[PUT SENDER ID]", senderId);
const { searchParams } = new URL(request.url); const { searchParams } = new URL(request.url);
const status = searchParams.get("status"); const status = searchParams.get("status");
const fixStatus = _.startCase(status as string); const fixStatus = _.startCase(status as string);
@@ -102,7 +115,7 @@ async function PUT(request: Request, { params }: { params: { id: string } }) {
message: "Error update data event", message: "Error update data event",
reason: "Status not found", reason: "Status not found",
}, },
{ status: 500 } { status: 500 },
); );
if (fixStatus === "Reject") { if (fixStatus === "Reject") {
@@ -111,11 +124,24 @@ async function PUT(request: Request, { params }: { params: { id: string } }) {
id: id, id: id,
}, },
data: { data: {
catatan: data, catatan: catatan,
donasiMaster_StatusDonasiId: checkStatus.id, donasiMaster_StatusDonasiId: checkStatus.id,
}, },
}); });
// SEND NOTIFICATION
await sendNotificationMobileToOneUser({
recipientId: updateData.authorId as any,
senderId: senderId,
payload: {
title: "Pengajuan Review Ditolak",
body: "Mohon perbaiki data sesuai catatan penolakan !",
type: "announcement",
kategoriApp: "DONASI",
deepLink: routeUserMobile.donationByStatus({ status: "reject" }),
},
});
fixData = updateData; fixData = updateData;
} else if (fixStatus === "Publish") { } else if (fixStatus === "Publish") {
const updateData = await prisma.donasi.update({ const updateData = await prisma.donasi.update({
@@ -128,6 +154,39 @@ async function PUT(request: Request, { params }: { params: { id: string } }) {
}, },
}); });
// SEND NOTIFICAtION
await sendNotificationMobileToOneUser({
recipientId: updateData.authorId as any,
senderId: senderId,
payload: {
title: "Review Selesai",
body: `Donasi kamu telah dipublikasikan ! ${updateData.title}` as NotificationMobileBodyType,
type: "announcement",
kategoriApp: "DONASI",
deepLink: routeUserMobile.donationByStatus({ status: "publish" }),
},
});
const allUsers = await prisma.user.findMany({
where: {
NOT: { id: updateData.authorId as any },
active: true,
},
select: { id: true },
});
await sendNotificationMobileToManyUser({
recipientIds: allUsers.map((user) => user.id),
senderId: senderId,
payload: {
title: "Ayo Cek Donasi Terbaru" as NotificationMobileTitleType,
body: `${updateData.title}` as NotificationMobileBodyType,
type: "announcement",
kategoriApp: "DONASI",
deepLink: routeUserMobile.donationDetailPublish({ id: id }),
},
});
fixData = updateData; fixData = updateData;
} }
@@ -137,7 +196,7 @@ async function PUT(request: Request, { params }: { params: { id: string } }) {
message: "Data Donasi Berhasil Diambil", message: "Data Donasi Berhasil Diambil",
data: data, data: data,
}, },
{ status: 200 } { status: 200 },
); );
} catch (error) { } catch (error) {
return NextResponse.json( return NextResponse.json(
@@ -146,7 +205,7 @@ async function PUT(request: Request, { params }: { params: { id: string } }) {
message: "Error get detail Investasi", message: "Error get detail Investasi",
reason: (error as Error).message, reason: (error as Error).message,
}, },
{ status: 500 } { status: 500 },
); );
} }
} }

View File

@@ -90,7 +90,7 @@ async function PUT(req: Request, { params }: { params: { id: string } }) {
body: `Maaf transaksi kamu telah ditolak ! ${updt?.Investasi?.title}` as NotificationMobileBodyType, body: `Maaf transaksi kamu telah ditolak ! ${updt?.Investasi?.title}` as NotificationMobileBodyType,
type: "announcement", type: "announcement",
kategoriApp: "INVESTASI", kategoriApp: "INVESTASI",
deepLink: routeUserMobile.investasiTransaction, deepLink: routeUserMobile.investmentTransaction,
}, },
}); });
@@ -182,7 +182,7 @@ async function PUT(req: Request, { params }: { params: { id: string } }) {
body: `Selamat anda menjadi investor pada investasi ${findInvestasi?.title}` as NotificationMobileBodyType, body: `Selamat anda menjadi investor pada investasi ${findInvestasi?.title}` as NotificationMobileBodyType,
type: "announcement", type: "announcement",
kategoriApp: "INVESTASI", kategoriApp: "INVESTASI",
deepLink: routeUserMobile.investasiTransaction, deepLink: routeUserMobile.investmentTransaction,
}, },
}); });
@@ -195,7 +195,7 @@ async function PUT(req: Request, { params }: { params: { id: string } }) {
body: `Cek daftar investor pada ${findInvestasi?.title}` as NotificationMobileBodyType, body: `Cek daftar investor pada ${findInvestasi?.title}` as NotificationMobileBodyType,
type: "announcement", type: "announcement",
kategoriApp: "INVESTASI", kategoriApp: "INVESTASI",
deepLink: routeUserMobile.investasiDetailPublish({ deepLink: routeUserMobile.investmentDetailPublish({
id: findInvestasi?.id as string, id: findInvestasi?.id as string,
}), }),
}, },

View File

@@ -174,7 +174,7 @@ async function PUT(request: Request, { params }: { params: { id: string } }) {
body: `${updatedData.title}` as NotificationMobileBodyType, body: `${updatedData.title}` as NotificationMobileBodyType,
type: "announcement", type: "announcement",
kategoriApp: "INVESTASI", kategoriApp: "INVESTASI",
deepLink: routeUserMobile.investasiDetailPublish({ id: id }), deepLink: routeUserMobile.investmentDetailPublish({ id: id }),
}, },
}); });

View File

@@ -1,6 +1,12 @@
import _ from "lodash"; import _ from "lodash";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import prisma from "@/lib/prisma"; import prisma from "@/lib/prisma";
import { sendNotificationMobileToManyUser } from "@/lib/mobile/notification/send-notification";
import {
NotificationMobileBodyType,
NotificationMobileTitleType,
} from "../../../../../../../types/type-mobile-notification";
import { routeAdminMobile } from "@/lib/mobile/route-page-mobile";
export { POST, GET, PUT }; export { POST, GET, PUT };
@@ -33,6 +39,14 @@ async function POST(request: Request, { params }: { params: { id: string } }) {
}, },
}); });
if (!create) {
return NextResponse.json({
status: 500,
success: false,
message: "Gagal membuat invoice",
});
}
return NextResponse.json({ return NextResponse.json({
status: 201, status: 201,
success: true, success: true,
@@ -65,7 +79,7 @@ async function GET(request: Request, { params }: { params: { id: string } }) {
createdAt: true, createdAt: true,
donasiMaster_BankId: true, donasiMaster_BankId: true,
donasiMaster_StatusInvoiceId: true, donasiMaster_StatusInvoiceId: true,
MasterBank: true, MasterBank: true,
Donasi: { Donasi: {
select: { select: {
id: true, id: true,
@@ -139,7 +153,7 @@ async function PUT(request: Request, { params }: { params: { id: string } }) {
}); });
} }
const update = await prisma.donasi_Invoice.update({ const updated = await prisma.donasi_Invoice.update({
where: { where: {
id: id, id: id,
}, },
@@ -164,7 +178,40 @@ async function PUT(request: Request, { params }: { params: { id: string } }) {
}, },
}); });
console.log("[UPDATE INVOICE]", update); if (!updated) {
return NextResponse.json({
status: 500,
success: false,
message: "Gagal memperbarui data",
});
}
const findUsers = await prisma.user.findMany({
where: {
masterUserRoleId: "2",
active: true,
NOT: { id: updated?.Donasi?.authorId as string },
},
select: { id: true },
});
// SEND NOTIFICATION
await sendNotificationMobileToManyUser({
recipientIds: findUsers.map((user) => user.id),
senderId: data.authorId,
payload: {
title: "Ada Donasi Baru !" as NotificationMobileTitleType,
body: `Cek data investor pada ${updated?.Donasi?.title}` as NotificationMobileBodyType,
type: "announcement",
kategoriApp: "DONASI",
deepLink: routeAdminMobile.donationDetailPublish({
id: updated?.Donasi?.id as string,
status: "publish",
}),
},
});
console.log("[UPDATE INVOICE]", updated);
return NextResponse.json({ return NextResponse.json({
status: 200, status: 200,

View File

@@ -1,6 +1,9 @@
import { sendNotificationMobileToManyUser } from "@/lib/mobile/notification/send-notification";
import prisma from "@/lib/prisma"; import prisma from "@/lib/prisma";
import _ from "lodash"; import _ from "lodash";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { NotificationMobileBodyType } from "../../../../../types/type-mobile-notification";
import { routeAdminMobile } from "@/lib/mobile/route-page-mobile";
export { POST }; export { POST };
@@ -49,6 +52,26 @@ async function POST(request: Request) {
console.log("[DATA DONASI]", dataDonasi); console.log("[DATA DONASI]", dataDonasi);
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: data.title as NotificationMobileBodyType,
type: "announcement",
deepLink: routeAdminMobile.donationByStatus({ status: "review" }),
kategoriApp: "DONASI",
},
});
if (!dataDonasi) if (!dataDonasi)
return NextResponse.json({ return NextResponse.json({
status: 400, status: 400,

View File

@@ -5,6 +5,7 @@ import {
NotificationMobileBodyType, NotificationMobileBodyType,
NotificationMobileTitleType, NotificationMobileTitleType,
} from "../../../../../../../types/type-mobile-notification"; } from "../../../../../../../types/type-mobile-notification";
import { routeAdminMobile, routeUserMobile } from "@/lib/mobile/route-page-mobile";
export { POST, GET, DELETE }; export { POST, GET, DELETE };
@@ -33,11 +34,14 @@ async function POST(request: Request, { params }: { params: { id: string } }) {
investasi: { investasi: {
select: { select: {
title: true, title: true,
authorId: true,
}, },
}, },
}, },
}); });
console.log("[CREATED DOCS]", createdDocs);
const findInvestor = await prisma.investasi_Invoice.findMany({ const findInvestor = await prisma.investasi_Invoice.findMany({
where: { where: {
investasiId: id, investasiId: id,
@@ -45,23 +49,27 @@ async function POST(request: Request, { params }: { params: { id: string } }) {
name: "Berhasil", name: "Berhasil",
}, },
}, },
select: {
authorId: true,
},
}); });
console.log("[FIND INVESTOR]", findInvestor);
// SEND NOTIFICATION // SEND NOTIFICATION
// await sendNotificationMobileToManyUser({ await sendNotificationMobileToManyUser({
// recipientIds: findInvestor.map((user) => user.id), recipientIds: findInvestor.map((e) => e.authorId!),
// senderId: data.authorId, senderId: createdDocs.investasi?.authorId as string,
// payload: { payload: {
// title: "Cek Dokumen" as NotificationMobileTitleType, title: "Cek Dokumen" as NotificationMobileTitleType,
// body: `Ada informasi dokumen yang di\\\ ${createdDocs.investasi?.title}` as NotificationMobileBodyType, body: `Ada dokumen terupdate pada ${createdDocs.investasi?.title}` as NotificationMobileBodyType,
// type: "announcement", type: "announcement",
// kategoriApp: "INVESTASI", kategoriApp: "INVESTASI",
// deepLink: routeAdminMobile.investmentDetailPublish({ deepLink: routeUserMobile.investmentDetailPublish({
// id: update.investasiId as string, id: createdDocs.investasiId as string,
// status: "publish", }),
// }), },
// }, });
// });
if (!createdDocs) if (!createdDocs)
return NextResponse.json({ return NextResponse.json({

View File

@@ -1,6 +1,7 @@
import _ from "lodash"; import _ from "lodash";
import { prisma } from "@/lib"; import { prisma } from "@/lib";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { sendNotificationInvestmentAddNews } from "@/lib/mobile/notification/notification-add-news-investment";
export { POST, GET, DELETE }; export { POST, GET, DELETE };
@@ -21,6 +22,21 @@ async function POST(request: Request, { params }: { params: { id: string } }) {
deskripsi: data.deskripsi, deskripsi: data.deskripsi,
imageId: data.imageId, imageId: data.imageId,
}, },
select: {
investasiId: true,
investasi: {
select: {
title: true,
authorId: true,
},
},
},
});
await sendNotificationInvestmentAddNews({
invesmentId: createWithFile.investasiId,
senderId: createWithFile.investasi.authorId as string,
title: createWithFile.investasi.title,
}); });
fixData = createWithFile; fixData = createWithFile;
@@ -31,6 +47,21 @@ async function POST(request: Request, { params }: { params: { id: string } }) {
title: _.startCase(data.title), title: _.startCase(data.title),
deskripsi: data.deskripsi, deskripsi: data.deskripsi,
}, },
select: {
investasiId: true,
investasi: {
select: {
title: true,
authorId: true,
},
},
},
});
await sendNotificationInvestmentAddNews({
invesmentId: createWitOutFile.investasiId,
senderId: createWitOutFile.investasi.authorId as string,
title: createWitOutFile.investasi.title,
}); });
fixData = createWitOutFile; fixData = createWitOutFile;
@@ -111,7 +142,7 @@ async function GET(request: Request, { params }: { params: { id: string } }) {
async function DELETE( async function DELETE(
request: Request, request: Request,
{ params }: { params: { id: string } } { params }: { params: { id: string } },
) { ) {
const { id } = params; const { id } = params;
console.log("id", id); console.log("id", id);

View File

@@ -0,0 +1,28 @@
const sendCodeOtp = async ({
nomor,
codeOtp,
}: {
nomor: string;
codeOtp: string;
}) => {
const msg = `HIPMI%20-%20Kode%20ini%20bersifat%20RAHASIA%20dan%20JANGAN%20DI%20BAGIKAN%20KEPADA%20SIAPAPUN%2C%20termasuk%20anggota%20ataupun%20pengurus%20HIPMI%20lainnya.%20Kode%20OTP%20anda%3A%20${codeOtp}.`;
const res = await fetch(
`https://cld-dkr-prod-wajs-server.wibudev.com/api/wa/code?nom=${nomor}&text=${msg}`,
{
cache: "no-cache",
headers: {
Authorization: `Bearer ${process.env.WA_SERVER_TOKEN}`,
},
},
);
// const res = await fetch(
// `https://wa.wibudev.com/code?nom=${nomor}&text=HIPMI - Kode ini bersifat RAHASIA dan JANGAN DI BAGIKAN KEPADA SIAPAPUN, termasuk anggota ataupun pengurus HIPMI lainnya.
// \n
// >> Kode OTP anda: ${codeOtp}.
// `,
// );
return res;
};
export { sendCodeOtp };

View File

@@ -0,0 +1,46 @@
import {
NotificationMobileBodyType,
NotificationMobileTitleType,
} from "../../../../types/type-mobile-notification";
import { sendNotificationMobileToManyUser } from "./send-notification";
import { routeUserMobile } from "../route-page-mobile";
import prisma from "@/lib/prisma";
export const sendNotificationInvestmentAddNews = async ({
invesmentId,
senderId,
title,
}: {
invesmentId: string;
senderId: string;
title: string;
}) => {
const findInvestor = await prisma.investasi_Invoice.findMany({
where: {
investasiId: invesmentId,
StatusInvoice: {
name: "Berhasil",
},
},
select: {
authorId: true,
},
});
console.log("[FIND INVESTOR]", findInvestor);
// SEND NOTIFICATION
await sendNotificationMobileToManyUser({
recipientIds: findInvestor.map((e) => e.authorId!),
senderId: senderId,
payload: {
title: "Berita terbaru" as NotificationMobileTitleType,
body: `Ada berita yang terupdate pada ${title}` as NotificationMobileBodyType,
type: "announcement",
kategoriApp: "INVESTASI",
deepLink: routeUserMobile.investmentDetailPublish({
id: invesmentId,
}),
},
});
};

View File

@@ -29,8 +29,19 @@ const routeAdminMobile = {
id: string; id: string;
status: StatusApp; status: StatusApp;
}) => `/admin/investment/${id}/${status}`, }) => `/admin/investment/${id}/${status}`,
// DONATION
donationByStatus: ({ status }: { status: StatusApp }) => `/admin/donation/${status}/status`,
donationDetailPublish: ({
id,
status,
}: {
id: string;
status: StatusApp;
}) => `/admin/donation/${id}/${status}`,
}; };
// ================ ROUTER USER =================
const routeUserMobile = { const routeUserMobile = {
home: `/(user)/home`, home: `/(user)/home`,
// JOB // JOB
@@ -59,6 +70,12 @@ const routeUserMobile = {
// INVESTMENT // INVESTMENT
investmentPortofolioByStatus: ({ status }: { status?: StatusApp }) => investmentPortofolioByStatus: ({ status }: { status?: StatusApp }) =>
`/investment/(tabs)/portofolio?status=${status}`, `/investment/(tabs)/portofolio?status=${status}`,
investasiDetailPublish: ({ id }: { id: string }) => `/investment/${id}`, investmentDetailPublish: ({ id }: { id: string }) => `/investment/${id}`,
investasiTransaction: `/investment/(tabs)/transaction` investmentTransaction: `/investment/(tabs)/transaction`,
// DONATION
donationByStatus: ({ status }: { status?: StatusApp }) =>
`/donation/(tabs)/status?status=${status}`,
donationDetailPublish: ({ id }: { id: string }) => `/donation/${id}`,
donationTransaction: `/donation/(tabs)/my-donation`,
}; };