Merge pull request #256 from bipproduction/bagas/28-jan-25

fix database event
This commit is contained in:
Bagasbanuna02
2025-01-30 10:26:33 +08:00
committed by GitHub
18 changed files with 423 additions and 127 deletions

View File

@@ -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?
}

View File

@@ -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 }
);
}
}

View File

@@ -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 }
);
}
}

View File

@@ -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 (

View File

@@ -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 (
<>
<Event_Invoice userLoginId={userLoginId} />
</>
);
}
export default Page;

View File

@@ -1,12 +0,0 @@
import Event_Invoice from '@/app_modules/event/detail/invoice';
import React from 'react';
function Page() {
return (
<>
<Event_Invoice/>
</>
);
}
export default Page;

View File

@@ -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}`,
};

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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 (
<>
<Stack spacing={"lg"} py={"md"}>
@@ -54,17 +67,19 @@ function Event_Invoice() {
>
<Grid>
<Grid.Col span={8}>
<Group position='left' align='center' h={"100%"}>
<Group position="left" align="center" h={"100%"}>
<Title order={4} color={MainColor.yellow}>
9065456754325643
</Title>
</Group>
</Grid.Col>
<Grid.Col span={4}>
<Group position='right'>
<Button radius={"xl"}
<Group position="right">
<Button
radius={"xl"}
style={{ backgroundColor: MainColor.yellow }}
c={MainColor.darkblue}>
c={MainColor.darkblue}
>
Salin
</Button>
</Group>
@@ -101,15 +116,19 @@ function Event_Invoice() {
>
<Grid>
<Grid.Col span={8}>
<Group position='left' align='center' h={"100%"}>
<Group position="left" align="center" h={"100%"}>
<Title order={4} color={MainColor.yellow}>
Rp. 100.000
</Title>
</Group>
</Grid.Col>
<Grid.Col span={4}>
<Group position='right'>
<Button radius={"xl"} style={{ backgroundColor: MainColor.yellow }} c={MainColor.darkblue}>
<Group position="right">
<Button
radius={"xl"}
style={{ backgroundColor: MainColor.yellow }}
c={MainColor.darkblue}
>
Salin
</Button>
</Group>
@@ -131,15 +150,22 @@ function Event_Invoice() {
}}
>
<Stack spacing={"sm"}>
<Group position='center'>
<Button leftIcon={<IconCamera />} radius={"xl"} style={{ backgroundColor: MainColor.yellow }} c={MainColor.darkblue}>
<Group position="center">
<Button
leftIcon={<IconCamera />}
radius={"xl"}
style={{ backgroundColor: MainColor.yellow }}
c={MainColor.darkblue}
>
Upload
</Button>
</Group>
<Text ta={"center"} fz={"xs"} fs={"italic"}>Upload bukti transfer anda</Text>
<Text ta={"center"} fz={"xs"} fs={"italic"}>
Upload bukti transfer anda
</Text>
</Stack>
</Paper>
<Button radius={"xl"} bg={MainColor.yellow} color='yellow' c="black">
<Button radius={"xl"} bg={MainColor.yellow} color="yellow" c="black">
Saya Sudah Transfer
</Button>
</Stack>

View File

@@ -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<MODEL_MASTER_BANK[] | null>(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 (
<>
<Stack>
{Array.from({ length: 2 }).map((e, i) => (
<CustomSkeleton key={i} height={50} width={"100%"} />
))}
</Stack>
</>
);
}
return (
<>
<Stack>
<Radio.Group
value={pilihBank}
onChange={setPilihBank}
withAsterisk
color='yellow'
>
{bank.map((e) => (
<Paper
key={e.id}
style={{
backgroundColor: AccentColor.blue,
border: `2px solid ${AccentColor.darkblue}`,
padding: "15px",
cursor: "pointer",
borderRadius: "10px",
color: "white",
marginBottom: "15px",
{_.isEmpty(data) ? (
<ComponentGlobal_IsEmptyData />
) : (
<Stack>
<Radio.Group
value={pilihBank}
onChange={setPilihBank}
withAsterisk
color="yellow"
>
{data.map((e) => (
<Paper
key={e.id}
style={{
backgroundColor: AccentColor.blue,
border: `2px solid ${AccentColor.darkblue}`,
padding: "15px",
cursor: "pointer",
borderRadius: "10px",
color: "white",
marginBottom: "15px",
}}
>
<Radio
styles={{
radio: {
color: "yellow",
},
}}
value={e.id}
label={
<Title order={6} color="white">
{e.namaBank}
</Title>
}
/>
</Paper>
))}
</Radio.Group>
<Button
loading={isLoading}
loaderPosition="center"
disabled={pilihBank === ""}
style={{ transition: "0.5s" }}
radius={"xl"}
bg={MainColor.yellow}
color="yellow"
c={"black"}
onClick={() => {
try {
setIsLoading(true);
setBankId(pilihBank);
router.push(RouterEvent.invoice({ id: params.id }), {
scroll: false,
});
} catch (error) {
console.log(error);
}
}}
>
<Radio
styles={{
radio: {
color: "yellow"
},
}}
value={e.id}
label={
<Title order={6} color='white'>
{e.namaBank}
</Title>
}
/>
</Paper>
))}
</Radio.Group>
<Button
style={{ transition: "0.5s" }}
radius={"xl"}
bg={MainColor.yellow}
color='yellow'
c={"black"}
onClick={() => router.push("/dev/event/invoice")}
>
Pilih
</Button>
</Stack>
Pilih
</Button>
</Stack>
)}
</>
);
}
export default Event_MetodePembayaran;
export default Event_MetodePembayaran;

View File

@@ -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: <IconMoodSmile />,
},
{
id: 2,
jumlah: " 50.000",
value: 50000,
icon: <IconMoodSmileBeam />,
},
{
id: 3,
jumlah: " 75.000",
value: 75000,
icon: <IconMoodSmileDizzy />,
},
{
id: 4,
jumlah: " 100.000",
value: 100000,
icon: <IconMoodXd />,
},
];
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 (
<>
<Stack>
@@ -54,6 +64,7 @@ function Event_PilihNominalSponsor() {
<Paper
key={e.id}
style={{
transition: "all 0.3s ease-in-out",
backgroundColor: AccentColor.blue,
border: `2px solid ${AccentColor.darkblue}`,
padding: "15px",
@@ -62,13 +73,32 @@ function Event_PilihNominalSponsor() {
color: "white",
marginBottom: "15px",
}}
onClick={() => {
try {
setChooseId(e.id);
setLoadingPaper(true);
setFixNominal(e.value);
router.push(RouterEvent.metode_pembayaran({ id: params.id }));
} catch (error) {
console.error(error);
}
}}
>
<Group position="apart">
<Group>
{e.icon}
<Title order={4}>Rp.{e.jumlah}</Title>
<Title order={4}>
Rp.
{new Intl.NumberFormat("id-ID", { currency: "IDR" }).format(
e.value
)}
</Title>
</Group>
<IconChevronRight />
{isLoadingPaper && e.id === chooseId ? (
<Loader size={20} color="yellow" />
) : (
<IconChevronRight />
)}
</Group>
</Paper>
))}
@@ -89,21 +119,41 @@ function Event_PilihNominalSponsor() {
icon={<Text fw={"bold"}>Rp.</Text>}
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);
}}
/>
<Text c={"gray"} fz={"xs"}>
Minimal Donasi Rp. 10.000
</Text>
</Stack>
</Paper>
<Button
style={{ transition: "0.5s" }}
disabled={valueNominal <= 0}
loaderPosition="center"
loading={isLoading}
style={{ transition: " all 0.3s ease-in-out" }}
radius={"xl"}
bg={MainColor.yellow}
color="yellow"
c={"black"}
onClick={() =>
router.push("/dev/event/detail/sponsor/metode_pembayaran")
}
onClick={() => {
setLoading(true);
setFixNominal(valueNominal);
router.push(RouterEvent.metode_pembayaran({ id: params.id }));
}}
>
Lanjutan Pembayaran
</Button>

View File

@@ -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<string | any>("gs_status_event", "Publish")
export const gs_event_status = atomWithStorage<string | any>(
"gs_status_event",
"Publish"
);
export const gs_nominal_sponsor = atomWithStorage<number>(
"gs_nominal_sponsor",
0
);
export const gs_event_bank_id = atomWithStorage<string>("gs_event_bank_id", "");

View File

@@ -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 };

View File

@@ -0,0 +1,18 @@
[
{
"id": "1",
"name": "Berhasil"
},
{
"id": "2",
"name": "Proses"
},
{
"id": "3",
"name": "Menunggu"
},
{
"id": "4",
"name": "Gagal"
}
]

View File

@@ -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",