diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8fcbf136..eab897c0 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,7 +11,6 @@ datasource db { url = env("DATABASE_URL") } - model User { id String @id @default(cuid()) username String @unique @@ -182,6 +181,15 @@ model MasterStatus { Job Job[] } +model MasterStatusTransaksi { + id String @id @default(cuid()) + name String + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + EventTransaksi EventTransaksi[] +} + // -------------------- INVESTASI --------------------- // // Table investasi / saham model Investasi { @@ -983,16 +991,17 @@ model EventSponsor { } model EventTransaksi { - id String @id @default(cuid()) - isActive Boolean @default(true) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id String @id @default(cuid()) + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt nominal Int - MasterBank MasterBank? @relation(fields: [masterBankId], references: [id]) - masterBankId String? status String transferImageId String? + MasterBank MasterBank? @relation(fields: [masterBankId], references: [id]) + masterBankId String? + AuthorId User? @relation(fields: [authorId], references: [id]) authorId String? @@ -1001,4 +1010,7 @@ model EventTransaksi { EventSponsor EventSponsor? @relation(fields: [eventSponsorId], references: [id]) eventSponsorId String? @unique + + MasterStatusTransaksi MasterStatusTransaksi? @relation(fields: [masterStatusTransaksiId], references: [id]) + masterStatusTransaksiId String? } diff --git a/src/app/api/master/bank/route.ts b/src/app/api/master/bank/route.ts new file mode 100644 index 00000000..2ce3228b --- /dev/null +++ b/src/app/api/master/bank/route.ts @@ -0,0 +1,41 @@ +import { prisma } from "@/app/lib"; +import backendLogger from "@/util/backendLogger"; +import { NextResponse } from "next/server"; + +export async function GET(request: Request) { + const method = request.method; + if (method !== "GET") { + return NextResponse.json( + { success: false, message: "Method not allowed" }, + { status: 405 } + ); + } + + try { + const res = await prisma.masterBank.findMany({ + orderBy: { + updatedAt: "asc", + }, + where: { + isActive: true, + }, + }); + + await prisma.$disconnect(); + return NextResponse.json( + { success: true, message: "Berhasil mendapatkan data", data: res }, + { status: 200 } + ); + } catch (error) { + await prisma.$disconnect(); + backendLogger.error("Error Get Master Bank >>", error); + return NextResponse.json( + { + success: false, + message: "API Error Get Data", + reason: (error as Error).message, + }, + { status: 500 } + ); + } +} diff --git a/src/app/api/master/status_transaksi/route.ts b/src/app/api/master/status_transaksi/route.ts new file mode 100644 index 00000000..e7abd5e0 --- /dev/null +++ b/src/app/api/master/status_transaksi/route.ts @@ -0,0 +1,41 @@ +import { prisma } from "@/app/lib"; +import backendLogger from "@/util/backendLogger"; +import { NextResponse } from "next/server"; + +export async function GET(request: Request) { + const method = request.method; + if (method !== "GET") { + return NextResponse.json( + { success: false, message: "Method not allowed" }, + { status: 405 } + ); + } + + try { + const res = await prisma.masterStatusTransaksi.findMany({ + orderBy: { + updatedAt: "asc", + }, + where: { + isActive: true, + }, + }); + + await prisma.$disconnect(); + return NextResponse.json( + { success: true, message: "Berhasil mendapatkan data", data: res }, + { status: 200 } + ); + } catch (error) { + await prisma.$disconnect(); + backendLogger.error("Error Get Master Status Transaksi >>", error); + return NextResponse.json( + { + success: false, + message: "API Error Get Data", + reason: (error as Error).message, + }, + { status: 500 } + ); + } +} diff --git a/src/app/dev/event/detail/sponsor/metode_pembayaran/layout.tsx b/src/app/dev/event/detail/sponsor/metode_pembayaran/[id]/layout.tsx similarity index 100% rename from src/app/dev/event/detail/sponsor/metode_pembayaran/layout.tsx rename to src/app/dev/event/detail/sponsor/metode_pembayaran/[id]/layout.tsx diff --git a/src/app/dev/event/detail/sponsor/metode_pembayaran/page.tsx b/src/app/dev/event/detail/sponsor/metode_pembayaran/[id]/page.tsx similarity index 66% rename from src/app/dev/event/detail/sponsor/metode_pembayaran/page.tsx rename to src/app/dev/event/detail/sponsor/metode_pembayaran/[id]/page.tsx index 7ebc92bf..9e749bdd 100644 --- a/src/app/dev/event/detail/sponsor/metode_pembayaran/page.tsx +++ b/src/app/dev/event/detail/sponsor/metode_pembayaran/[id]/page.tsx @@ -1,7 +1,5 @@ import Event_MetodePembayaran from '@/app_modules/event/detail/sponsor/metode_pembayaran'; -import { MODEL_MASTER_BANK } from '@/app_modules/investasi/_lib/interface'; -import React from 'react'; function Page() { return ( diff --git a/src/app/dev/event/invoice/layout.tsx b/src/app/dev/event/invoice/[id]/layout.tsx similarity index 100% rename from src/app/dev/event/invoice/layout.tsx rename to src/app/dev/event/invoice/[id]/layout.tsx diff --git a/src/app/dev/event/invoice/[id]/page.tsx b/src/app/dev/event/invoice/[id]/page.tsx new file mode 100644 index 00000000..7574ae8b --- /dev/null +++ b/src/app/dev/event/invoice/[id]/page.tsx @@ -0,0 +1,14 @@ +import { funGetUserIdByToken } from '@/app_modules/_global/fun/get'; +import Event_Invoice from '@/app_modules/event/detail/invoice'; +import React from 'react'; + +async function Page() { + const userLoginId = await funGetUserIdByToken(); + return ( + <> + + + ); +} + +export default Page; diff --git a/src/app/dev/event/invoice/page.tsx b/src/app/dev/event/invoice/page.tsx deleted file mode 100644 index 9c6a990b..00000000 --- a/src/app/dev/event/invoice/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import Event_Invoice from '@/app_modules/event/detail/invoice'; -import React from 'react'; - -function Page() { - return ( - <> - - - ); -} - -export default Page; diff --git a/src/app/lib/router_hipmi/router_event.ts b/src/app/lib/router_hipmi/router_event.ts index c98a3b9e..41154204 100644 --- a/src/app/lib/router_hipmi/router_event.ts +++ b/src/app/lib/router_hipmi/router_event.ts @@ -43,7 +43,11 @@ export const RouterEvent = { `/dev/event/detail/sponsor/tambah_sponsor/${id}`, detail_sponsor: ({ id }: { id: string }) => `/dev/event/detail/detail_sponsor/${id}`, - nominal_sponsor: ({ id }: { id: string }) => `/dev/event/detail/sponsor/nominal_sponsor/${id}`, + + metode_pembayaran: ({ id }: { id: string }) => + `/dev/event/detail/sponsor/metode_pembayaran/${id}`, + invoice: ({ id }: { id: string }) => + `/dev/event/invoice/${id}`, }; diff --git a/src/app_modules/_global/fun/generate_seeder.ts b/src/app_modules/_global/fun/generate_seeder.ts index 3704edf4..3e549c78 100644 --- a/src/app_modules/_global/fun/generate_seeder.ts +++ b/src/app_modules/_global/fun/generate_seeder.ts @@ -25,6 +25,7 @@ import voting_status from "../../../bin/seeder/voting/master_status.json"; import { master_kategori_app } from "@/bin/seeder/master"; import { new_status_transaksi_investasi } from "@/bin/seeder/investasi"; import { master_nama_bank } from "@/bin/seeder/master"; +import { master_status_transaksi } from "@/bin/seeder/master"; import pLimit from "p-limit"; async function masterUserRole() { @@ -543,6 +544,26 @@ async function masterInvestasiNewTransaksiStatus() { console.log("masterInvestasiNewTransaksiStatus success"); } +async function masterStatusTransaksi() { + for (let a of master_status_transaksi) { + await prisma.masterStatusTransaksi.upsert({ + where: { + id: a.id, + }, + create: { + id: a.id, + name: a.name, + }, + update: { + id: a.id, + name: a.name, + }, + }); + } + + console.log("masterStatusTransaksi success"); +} + const listSeederQueue = [ masterUserRole, seederUser, @@ -570,6 +591,7 @@ const listSeederQueue = [ seederNomorAdmin, masterKategoriApp, masterInvestasiNewTransaksiStatus, + masterStatusTransaksi, ]; const limit = pLimit(1); diff --git a/src/app_modules/_global/lib/api_master.ts b/src/app_modules/_global/lib/api_master.ts new file mode 100644 index 00000000..7443c12e --- /dev/null +++ b/src/app_modules/_global/lib/api_master.ts @@ -0,0 +1,19 @@ +export { apiGetMasterBank }; + +const apiGetMasterBank = async () => { + const { token } = await fetch("/api/get-cookie").then((res) => res.json()); + if (!token) return await token.json().catch(() => null); + + const respone = await fetch(`/api/master/bank`, { + headers: { + "Content-Type": "application/json", + Accept: "application/json", + "Access-Control-Allow-Origin": "*", + Authorization: `Bearer ${token}`, + }, + }); + return await respone.json().catch(() => null); +}; + + + diff --git a/src/app_modules/event/detail/invoice/index.tsx b/src/app_modules/event/detail/invoice/index.tsx index 127b1fd5..d3a4ee70 100644 --- a/src/app_modules/event/detail/invoice/index.tsx +++ b/src/app_modules/event/detail/invoice/index.tsx @@ -1,10 +1,23 @@ -'use client'; -import { AccentColor, MainColor } from '@/app_modules/_global/color'; -import { ActionIcon, Button, Grid, Group, Paper, Stack, Text, Title } from '@mantine/core'; -import { IconCamera } from '@tabler/icons-react'; -import React from 'react'; +"use client"; + +import { AccentColor, MainColor } from "@/app_modules/_global/color"; +import { Button, Grid, Group, Paper, Stack, Text, Title } from "@mantine/core"; +import { IconCamera } from "@tabler/icons-react"; +import { useAtom } from "jotai"; +import { useParams, useRouter } from "next/navigation"; +import { gs_nominal_sponsor, gs_event_bank_id } from "../../global_state"; + +function Event_Invoice({ userLoginId }: { userLoginId: string }) { + const router = useRouter(); + const params = useParams<{ id: string }>(); + const sponsorId = params.id; + + const [nominal, setNominal] = useAtom(gs_nominal_sponsor); + const [bankId, setBankId] = useAtom(gs_event_bank_id); + + console.log("nominal >>", nominal); + console.log("bankId >>", bankId); -function Event_Invoice() { return ( <> @@ -54,17 +67,19 @@ function Event_Invoice() { > - + 9065456754325643 - - @@ -101,15 +116,19 @@ function Event_Invoice() { > - + Rp. 100.000 - - @@ -131,15 +150,22 @@ function Event_Invoice() { }} > - - - Upload bukti transfer anda + + Upload bukti transfer anda + - diff --git a/src/app_modules/event/detail/sponsor/metode_pembayaran/index.tsx b/src/app_modules/event/detail/sponsor/metode_pembayaran/index.tsx index 365af7dc..18ad624e 100644 --- a/src/app_modules/event/detail/sponsor/metode_pembayaran/index.tsx +++ b/src/app_modules/event/detail/sponsor/metode_pembayaran/index.tsx @@ -1,84 +1,130 @@ -'use client'; +"use client"; -import { AccentColor, MainColor } from '@/app_modules/_global/color'; -import { MODEL_MASTER_BANK } from '@/app_modules/investasi/_lib/interface'; -import { Button, Paper, Radio, Stack, Title } from '@mantine/core'; -import { useRouter } from 'next/navigation'; -import React, { useState } from 'react'; - -const bank = [ - { - id: 1, - namaBank: "BRI", - }, - { - id: 2, - namaBank: "BCA", - }, - { - id: 3, - namaBank: "BNI", - }, - { - id: 4, - namaBank: "BSI", - } -] +import { RouterEvent } from "@/app/lib/router_hipmi/router_event"; +import { AccentColor, MainColor } from "@/app_modules/_global/color"; +import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data"; +import { apiGetMasterBank } from "@/app_modules/_global/lib/api_master"; +import CustomSkeleton from "@/app_modules/components/CustomSkeleton"; +import { + gs_event_bank_id, + gs_nominal_sponsor, +} from "@/app_modules/event/global_state"; +import { MODEL_MASTER_BANK } from "@/app_modules/investasi/_lib/interface"; +import { clientLogger } from "@/util/clientLogger"; +import { Button, Paper, Radio, Stack, Title } from "@mantine/core"; +import { useShallowEffect } from "@mantine/hooks"; +import { useAtom } from "jotai"; +import _ from "lodash"; +import { useParams, useRouter } from "next/navigation"; +import { useState } from "react"; function Event_MetodePembayaran() { + const params = useParams<{ id: string }>(); const [pilihBank, setPilihBank] = useState(""); const router = useRouter(); + const [nominal, setNominal] = useAtom(gs_nominal_sponsor); + const [bankId, setBankId] = useAtom(gs_event_bank_id); + const [isLoading, setIsLoading] = useState(false); + console.log("nominal >>", nominal); + + const [data, setData] = useState(null); + useShallowEffect(() => { + onLoadBank(); + }, []); + + async function onLoadBank() { + try { + const respone = await apiGetMasterBank(); + + if (respone) { + setData(respone.data); + } + } catch (error) { + clientLogger.error("Error get data bank", error); + } + } + + if (!data) { + return ( + <> + + {Array.from({ length: 2 }).map((e, i) => ( + + ))} + + + ); + } + return ( <> - - - {bank.map((e) => ( - + ) : ( + + + {data.map((e) => ( + + + {e.namaBank} + + } + /> + + ))} + + + - + Pilih + + + )} ); } -export default Event_MetodePembayaran; \ No newline at end of file +export default Event_MetodePembayaran; diff --git a/src/app_modules/event/detail/sponsor/nominal_sponsor/index.tsx b/src/app_modules/event/detail/sponsor/nominal_sponsor/index.tsx index 846ec486..3f437159 100644 --- a/src/app_modules/event/detail/sponsor/nominal_sponsor/index.tsx +++ b/src/app_modules/event/detail/sponsor/nominal_sponsor/index.tsx @@ -1,5 +1,7 @@ "use client"; +import { RouterEvent } from "@/app/lib/router_hipmi/router_event"; import { AccentColor, MainColor } from "@/app_modules/_global/color"; +import { gs_nominal_sponsor } from "@/app_modules/event/global_state"; import { Box, Button, @@ -9,6 +11,7 @@ import { Text, TextInput, Title, + Loader, } from "@mantine/core"; import { IconChevronRight, @@ -17,35 +20,42 @@ import { IconMoodSmileDizzy, IconMoodXd, } from "@tabler/icons-react"; +import { useAtom } from "jotai"; import { useParams, useRouter } from "next/navigation"; -import React from "react"; +import { useState } from "react"; const listNominal = [ { id: 1, - jumlah: " 25.000", + value: 25000, icon: , }, { id: 2, - jumlah: " 50.000", + value: 50000, icon: , }, { id: 3, - jumlah: " 75.000", + value: 75000, icon: , }, { id: 4, - jumlah: " 100.000", + value: 100000, icon: , }, ]; function Event_PilihNominalSponsor() { const params = useParams<{ id: string }>(); const router = useRouter(); - + const [inputNominal, setInputNominal] = useState(""); + const [valueNominal, setValueNominal] = useState(0); + const [fixNominal, setFixNominal] = useAtom(gs_nominal_sponsor); + const [isLoading, setLoading] = useState(false); + const [isLoadingPaper, setLoadingPaper] = useState(false); + const [chooseId, setChooseId] = useState(0); + return ( <> @@ -54,6 +64,7 @@ function Event_PilihNominalSponsor() { { + try { + setChooseId(e.id); + setLoadingPaper(true); + setFixNominal(e.value); + router.push(RouterEvent.metode_pembayaran({ id: params.id })); + } catch (error) { + console.error(error); + } + }} > {e.icon} - Rp.{e.jumlah} + + Rp. + {new Intl.NumberFormat("id-ID", { currency: "IDR" }).format( + e.value + )} + - + {isLoadingPaper && e.id === chooseId ? ( + + ) : ( + + )} ))} @@ -89,21 +119,41 @@ function Event_PilihNominalSponsor() { icon={Rp.} placeholder="0" min={0} + value={inputNominal} + onChange={(val) => { + const match = val.currentTarget.value + .replace(/\./g, "") + .match(/^[0-9]+$/); + + if (val.currentTarget.value === "") + return setInputNominal(0 + ""); + + if (!match?.[0]) return null; + + const nilai = val.currentTarget.value.replace(/\./g, ""); + const target = Intl.NumberFormat("id-ID").format(+nilai); + + setValueNominal(+nilai); + setInputNominal(target); + }} /> - - Minimal Donasi Rp. 10.000 - + diff --git a/src/app_modules/event/global_state/index.ts b/src/app_modules/event/global_state/index.ts index 310e4a91..2574ed23 100644 --- a/src/app_modules/event/global_state/index.ts +++ b/src/app_modules/event/global_state/index.ts @@ -1,13 +1,24 @@ +import { atom } from "jotai"; import { atomWithStorage } from "jotai/utils"; /** * @param index | 0 - 3 | 0: Beranda, 1: Status, 2: Kontibusi, 3: Riwayat * @type number */ -export const gs_event_hotMenu = atomWithStorage("gs_event_hotMenu", 0) +export const gs_event_hotMenu = atomWithStorage("gs_event_hotMenu", 0); /** * @param status | "Publish", "Review", "Draft", "Reject" * @type string */ -export const gs_event_status = atomWithStorage("gs_status_event", "Publish") +export const gs_event_status = atomWithStorage( + "gs_status_event", + "Publish" +); + +export const gs_nominal_sponsor = atomWithStorage( + "gs_nominal_sponsor", + 0 +); + +export const gs_event_bank_id = atomWithStorage("gs_event_bank_id", ""); diff --git a/src/bin/seeder/master/index.ts b/src/bin/seeder/master/index.ts index b2a301c4..8cb000b1 100644 --- a/src/bin/seeder/master/index.ts +++ b/src/bin/seeder/master/index.ts @@ -1,5 +1,7 @@ import master_kategori_app from "./master_kategori_app.json"; import master_nama_bank from "./master_nama_bank.json"; +import master_status_transaksi from "./master_status_transaksi.json"; export { master_kategori_app }; export { master_nama_bank }; +export { master_status_transaksi }; diff --git a/src/bin/seeder/master/master_status_transaksi.json b/src/bin/seeder/master/master_status_transaksi.json new file mode 100644 index 00000000..6093bdd0 --- /dev/null +++ b/src/bin/seeder/master/master_status_transaksi.json @@ -0,0 +1,18 @@ +[ + { + "id": "1", + "name": "Berhasil" + }, + { + "id": "2", + "name": "Proses" + }, + { + "id": "3", + "name": "Menunggu" + }, + { + "id": "4", + "name": "Gagal" + } +] diff --git a/src/middleware.ts b/src/middleware.ts index dc993068..82fae375 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -32,9 +32,13 @@ const middlewareConfig: MiddlewareConfig = { "/api/auth/*", "/api/origin-url", "/api/event/*", + "/api/master/*", // "/api/image/*", // "/api/user/*", // "/api/new/*", + // ADMIN API + + // Akses awal "/api/get-cookie", "/api/user/activation",