API Dashboard Investasi & Event

This commit is contained in:
2025-01-30 17:44:18 +08:00
36 changed files with 1070 additions and 288 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.2.42](https://github.com/bipproduction/hipmi/compare/v1.2.41...v1.2.42) (2025-01-30)
## [1.2.41](https://github.com/bipproduction/hipmi/compare/v1.2.40...v1.2.41) (2025-01-21) ## [1.2.41](https://github.com/bipproduction/hipmi/compare/v1.2.40...v1.2.41) (2025-01-21)
## [1.2.40](https://github.com/bipproduction/hipmi/compare/v1.2.39...v1.2.40) (2025-01-16) ## [1.2.40](https://github.com/bipproduction/hipmi/compare/v1.2.39...v1.2.40) (2025-01-16)

View File

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

View File

@@ -11,7 +11,6 @@ datasource db {
url = env("DATABASE_URL") url = env("DATABASE_URL")
} }
model User { model User {
id String @id @default(cuid()) id String @id @default(cuid())
username String @unique username String @unique
@@ -182,6 +181,15 @@ model MasterStatus {
Job Job[] 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 --------------------- // // -------------------- INVESTASI --------------------- //
// Table investasi / saham // Table investasi / saham
model Investasi { model Investasi {
@@ -983,16 +991,17 @@ model EventSponsor {
} }
model EventTransaksi { model EventTransaksi {
id String @id @default(cuid()) id String @id @default(cuid())
isActive Boolean @default(true) isActive Boolean @default(true)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
nominal Int nominal Int
MasterBank MasterBank? @relation(fields: [masterBankId], references: [id])
masterBankId String?
status String status String
transferImageId String? transferImageId String?
MasterBank MasterBank? @relation(fields: [masterBankId], references: [id])
masterBankId String?
AuthorId User? @relation(fields: [authorId], references: [id]) AuthorId User? @relation(fields: [authorId], references: [id])
authorId String? authorId String?
@@ -1001,4 +1010,7 @@ model EventTransaksi {
EventSponsor EventSponsor? @relation(fields: [eventSponsorId], references: [id]) EventSponsor EventSponsor? @relation(fields: [eventSponsorId], references: [id])
eventSponsorId String? @unique eventSponsorId String? @unique
MasterStatusTransaksi MasterStatusTransaksi? @relation(fields: [masterStatusTransaksiId], references: [id])
masterStatusTransaksiId String?
} }

View File

@@ -0,0 +1,50 @@
import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger";
import { data } from "autoprefixer";
import _ from "lodash";
import { NextResponse } from "next/server";
export async function GET(request: Request, { params }: {
params: { name: string }
}) {
const method = request.method;
if (method !== "GET") {
return NextResponse.json({
success: false,
message: "Method not allowed",
},
{ status: 405 }
);
}
const { name } = params;
try {
let fixData;
const fixStatus = _.startCase(name);
fixData = await prisma.donasi.count({
where: {
DonasiMaster_Status: {
name: fixStatus
}
}
});
return NextResponse.json({
success: true,
message: "Success get data donasi dashboard",
data: fixData
},
{ status: 200 }
)
} catch (error) {
backendLogger.error("Error get data donasi dashboard >>", error);
return NextResponse.json({
success: false,
message: "Failed to get data donasi dashboard",
reason: (error as Error).message
},
{ status: 500 }
)
} finally {
await prisma.$disconnect();
}
}

View File

@@ -0,0 +1,53 @@
import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger";
import _ from "lodash";
import { NextResponse } from "next/server";
export async function GET(
request: Request,
{ params }: { params: { name: string } }
) {
const method = request.method;
if (method !== "GET") {
return NextResponse.json(
{ success: false, message: "Method not allowed" },
{ status: 405 }
);
}
const { name } = params;
try {
let fixData;
const fixStatus = _.startCase(name);
fixData = await prisma.event.count({
where: {
EventMaster_Status: {
name: fixStatus,
},
isArsip: false,
},
});
return NextResponse.json(
{
success: true,
message: "Success get data event dashboard",
data: fixData,
},
{ status: 200 }
);
} catch (error) {
backendLogger.error("Error get data event dashboard >>", error);
return NextResponse.json(
{
success: false,
message: "Failed to get data",
reason: (error as Error).message,
},
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
}

View File

@@ -0,0 +1,47 @@
import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger";
import _ from "lodash";
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 {
let fixData;
fixData = await prisma.event.count({
where: {
EventMaster_Status: {
name: "Publish",
},
isArsip: true,
},
});
return NextResponse.json(
{
success: true,
message: "Success get data riwayat event dashboard",
data: fixData,
},
{ status: 200 }
);
} catch (error) {
backendLogger.error("Error get data riwayat event dashboard >>", error);
return NextResponse.json(
{
success: false,
message: "Failed to get data",
reason: (error as Error).message,
},
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
}

View File

@@ -0,0 +1,44 @@
import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger";
import _ from "lodash";
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 {
let fixData;
fixData = await prisma.eventMaster_TipeAcara.count({
where: {
active: true,
},
});
return NextResponse.json(
{
success: true,
message: "Success get data riwayat event dashboard",
data: fixData,
},
{ status: 200 }
);
} catch (error) {
backendLogger.error("Error get data riwayat event dashboard >>", error);
return NextResponse.json(
{
success: false,
message: "Failed to get data",
reason: (error as Error).message,
},
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
}

View File

@@ -1,24 +1,41 @@
import { prisma } from "@/app/lib"; import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger"; import backendLogger from "@/util/backendLogger";
import _ from "lodash";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
export async function GET(request: Request) { export async function GET(request: Request, { params }: { params: { name: string } }) {
const method = request.method;
if (method !== "GET") {
return NextResponse.json({
success: false,
message: "Method not allowed",
},
{ status: 405 }
);
}
const { name } = params;
try { try {
const data = await prisma.investasi.count({ let fixData;
const fixStatus = _.startCase(name);
fixData = await prisma.investasi.count({
where: { where: {
active: true MasterStatusInvestasi: {
}, name: fixStatus
},
}
}) })
return NextResponse.json({ return NextResponse.json({
message: "Data Investasi", success: true,
data: data, message: "Success get data investasi dashboard",
data: fixData,
}, },
{ status: 200 } { status: 200 }
) )
} catch (error) { } catch (error) {
backendLogger.error("Error Get Count Investasi Main Dashboard") backendLogger.error("Error get data investasi dashboard >>", error);
return NextResponse.json({ return NextResponse.json({
message: "Error Get Count Investasi Main Dashboard", success: false,
message: "Error get data investasi dashboard",
reason: (error as Error).message reason: (error as Error).message
}, },
{ status: 500 } { status: 500 }

View File

@@ -32,19 +32,17 @@ export async function GET(
}, },
}); });
await prisma.$disconnect();
return NextResponse.json({ return NextResponse.json({
success: true, success: true,
message: "Berhasil mendapatkan data", message: "Berhasil mendapatkan data",
data: fixData, data: fixData,
}); });
} catch (error) { } catch (error) {
await prisma.$disconnect();
return NextResponse.json( return NextResponse.json(
{ success: false, message: "Gagal mendapatkan data" }, { success: false, message: "Gagal mendapatkan data" },
{ status: 500 } { status: 500 }
); );
} finally {
await prisma.$disconnect();
} }
} }

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

@@ -0,0 +1,60 @@
export {
apiGetEventStatusCountDashboard,
apiGetEventTipeAcara,
apiGetEventRiwayatCount,
};
const apiGetEventStatusCountDashboard = async ({
name,
}: {
name: "Publish" | "Review" | "Reject";
}) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(`/api/admin/event/dashboard/${name}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
return await response.json().catch(() => null);
};
const apiGetEventRiwayatCount = async () => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(`/api/admin/event/dashboard/riwayat`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
return await response.json().catch(() => null);
}
const apiGetEventTipeAcara = async () => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(`/api/admin/event/dashboard/tipe-acara`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
return await response.json().catch(() => null);
};

View File

@@ -1,26 +1,9 @@
import { AdminEvent_Main } from "@/app_modules/admin/event"; import { AdminEvent_Main } from "@/app_modules/admin/event";
import AdminEvent_funCountByStatusId from "@/app_modules/admin/event/fun/count/fun_count_event_by_status_id";
import { AdminEvent_funCountRiwayat } from "@/app_modules/admin/event/fun/count/fun_count_riwayat";
import { AdminEvent_funCountTipeAcara } from "@/app_modules/admin/event/fun/count/fun_count_tipe_acara";
export default async function Page() { export default async function Page() {
const countPublish = await AdminEvent_funCountByStatusId("1");
const countReview = await AdminEvent_funCountByStatusId("2");
const countDraft = await AdminEvent_funCountByStatusId("3");
const countReject = await AdminEvent_funCountByStatusId("4");
const countTipeAcara = await AdminEvent_funCountTipeAcara();
const countRiwayat = await AdminEvent_funCountRiwayat();
return ( return (
<> <>
<AdminEvent_Main <AdminEvent_Main />
countPublish={countPublish as number}
countReview={countReview as number}
countDraft={countDraft as number}
countReject={countReject as number}
countTipeAcara={countTipeAcara as number}
countRiwayat={countRiwayat}
/>
</> </>
); );
} }

View File

@@ -6,10 +6,10 @@ import Admin_getTotalInvestasiByUser from "@/app_modules/admin/investasi/fun/get
export default async function Page() { export default async function Page() {
const listInvestasi = await Admin_funGetAllInvestasi(); const listInvestasi = await Admin_funGetAllInvestasi();
const countDraft = await Admin_CountStatusInvestasi(1); // const countDraft = await Admin_CountStatusInvestasi(1);
const countReview = await Admin_CountStatusInvestasi(2); // const countReview = await Admin_CountStatusInvestasi(2);
const countPublish = await Admin_CountStatusInvestasi(3); // const countPublish = await Admin_CountStatusInvestasi(3);
const countReject = await Admin_CountStatusInvestasi(4); // const countReject = await Admin_CountStatusInvestasi(4);
const totalInvestasiByUser = await Admin_getTotalInvestasiByUser() const totalInvestasiByUser = await Admin_getTotalInvestasiByUser()
const publishProgres = await Admin_getPublishProgresInvestasi() const publishProgres = await Admin_getPublishProgresInvestasi()
// console.log(targetTerbesar) // console.log(targetTerbesar)
@@ -18,10 +18,10 @@ export default async function Page() {
<> <>
<Admin_Investasi <Admin_Investasi
listInvestasi={listInvestasi as any} listInvestasi={listInvestasi as any}
countDraft={countDraft} // countDraft={countDraft}
countReview={countReview} // countReview={countReview}
countPublish={countPublish} // countPublish={countPublish}
countReject={countReject} // countReject={countReject}
totalInvestasiByUser={totalInvestasiByUser} totalInvestasiByUser={totalInvestasiByUser}
publishProgres={publishProgres} publishProgres={publishProgres}

View File

@@ -1,7 +1,5 @@
import Event_MetodePembayaran from '@/app_modules/event/detail/sponsor/metode_pembayaran'; 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() { function Page() {
return ( 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;

5
src/app/lib/limit.ts Normal file
View File

@@ -0,0 +1,5 @@
import pLimit from "p-limit";
const global_limit = pLimit(1);
export default global_limit;

View File

@@ -1,28 +0,0 @@
"use server";
import _ from "lodash";
import { cookies } from "next/headers";
import { decrypt } from "../auth/_lib/decrypt";
import backendLogger from "@/util/backendLogger";
export async function newFunGetUserId() {
try {
const key = process.env.NEXT_PUBLIC_BASE_SESSION_KEY;
const c = cookies().get("hipmi-key");
if (!c || !c?.value || _.isEmpty(c?.value) || _.isUndefined(c?.value)) {
return null;
}
const token = c.value;
const dataUser = await decrypt({
token: token,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!,
});
return dataUser?.id;
} catch (error) {
backendLogger.log("Gagal mendapatkan user id", error);
return null;
}
}

View File

@@ -43,7 +43,11 @@ export const RouterEvent = {
`/dev/event/detail/sponsor/tambah_sponsor/${id}`, `/dev/event/detail/sponsor/tambah_sponsor/${id}`,
detail_sponsor: ({ id }: { id: string }) => detail_sponsor: ({ id }: { id: string }) =>
`/dev/event/detail/detail_sponsor/${id}`, `/dev/event/detail/detail_sponsor/${id}`,
nominal_sponsor: ({ id }: { id: string }) => nominal_sponsor: ({ id }: { id: string }) =>
`/dev/event/detail/sponsor/nominal_sponsor/${id}`, `/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 { master_kategori_app } from "@/bin/seeder/master";
import { new_status_transaksi_investasi } from "@/bin/seeder/investasi"; import { new_status_transaksi_investasi } from "@/bin/seeder/investasi";
import { master_nama_bank } from "@/bin/seeder/master"; import { master_nama_bank } from "@/bin/seeder/master";
import { master_status_transaksi } from "@/bin/seeder/master";
import pLimit from "p-limit"; import pLimit from "p-limit";
async function masterUserRole() { async function masterUserRole() {
@@ -543,6 +544,26 @@ async function masterInvestasiNewTransaksiStatus() {
console.log("masterInvestasiNewTransaksiStatus success"); 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 = [ const listSeederQueue = [
masterUserRole, masterUserRole,
seederUser, seederUser,
@@ -570,6 +591,7 @@ const listSeederQueue = [
seederNomorAdmin, seederNomorAdmin,
masterKategoriApp, masterKategoriApp,
masterInvestasiNewTransaksiStatus, masterInvestasiNewTransaksiStatus,
masterStatusTransaksi,
]; ];
const limit = pLimit(1); 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

@@ -0,0 +1,16 @@
const apiGetDonasiStatusCountDashboard = async ({ name }:
{ name: "Publish" | "Review" | "Reject" }) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(`api/admin/donasi/dashboard/${name}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
}
});
return await response.json().catch(() => null);
};

View File

@@ -2,7 +2,16 @@
import { RouterAdminEvent } from "@/app/lib/router_admin/router_admin_event"; import { RouterAdminEvent } from "@/app/lib/router_admin/router_admin_event";
import {
apiGetEventRiwayatCount,
apiGetEventStatusCountDashboard,
apiGetEventTipeAcara,
} from "@/app/dev/admin/event/_lib/api_fecth_admin_event";
import global_limit from "@/app/lib/limit";
import { AccentColor, MainColor } from "@/app_modules/_global/color"; import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { AdminColor } from "@/app_modules/_global/color/color_pallet";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import { clientLogger } from "@/util/clientLogger";
import { import {
Flex, Flex,
Paper, Paper,
@@ -10,81 +19,192 @@ import {
Stack, Stack,
Text, Text,
ThemeIcon, ThemeIcon,
Title Title,
} from "@mantine/core"; } from "@mantine/core";
import { IconAlertTriangle, IconBookmark, IconBriefcase, IconHistory, IconUpload } from "@tabler/icons-react"; import { useShallowEffect } from "@mantine/hooks";
import {
IconAlertTriangle,
IconBookmark,
IconBriefcase,
IconHistory,
IconUpload,
} from "@tabler/icons-react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react";
import ComponentAdminGlobal_HeaderTamplate from "../../_admin_global/header_tamplate"; import ComponentAdminGlobal_HeaderTamplate from "../../_admin_global/header_tamplate";
import { AdminColor } from "@/app_modules/_global/color/color_pallet";
export default function AdminEvent_Main({ export default function AdminEvent_Main() {
countPublish,
countReview,
countDraft,
countReject,
countTipeAcara,
countRiwayat,
}: {
countPublish: number;
countReview: number;
countDraft: number;
countReject: number;
countTipeAcara: number;
countRiwayat: number
}) {
const router = useRouter(); const router = useRouter();
const [countPublish, setCountPublish] = useState<number | null>(null);
const [countReview, setCountReview] = useState<number | null>(null);
const [countReject, setCountReject] = useState<number | null>(null);
const [countTipeAcara, setCountTipeAcara] = useState<number | null>(null);
const [countRiwayat, setCountRiwayat] = useState<number | null>(null);
useShallowEffect(() => {
handlerLoadData();
}, []);
async function handlerLoadData() {
try {
const listLoadData = [
global_limit(() => onLoadCountPublish()),
global_limit(() => onLoadCountReview()),
global_limit(() => onLoadCountReject()),
global_limit(() => onLoadCountRiwayat()),
global_limit(() => onLoadCountTipeAcara()),
];
const result = await Promise.all(listLoadData);
} catch (error) {
clientLogger.error("Error handler load data", error);
}
}
async function onLoadCountPublish() {
try {
const respone = await apiGetEventStatusCountDashboard({
name: "Publish",
});
if (respone) {
setCountPublish(respone.data);
}
} catch (error) {
clientLogger.error("Error get count publish", error);
}
}
async function onLoadCountReview() {
try {
const respone = await apiGetEventStatusCountDashboard({
name: "Review",
});
if (respone) {
setCountReview(respone.data);
}
} catch (error) {
clientLogger.error("Error get count review", error);
}
}
async function onLoadCountReject() {
try {
const respone = await apiGetEventStatusCountDashboard({
name: "Reject",
});
if (respone) {
setCountReject(respone.data);
}
} catch (error) {
clientLogger.error("Error get count reject", error);
}
}
async function onLoadCountRiwayat() {
try {
const respone = await apiGetEventRiwayatCount();
if (respone) {
setCountRiwayat(respone.data);
}
} catch (error) {
clientLogger.error("Error get count riwayat", error);
}
}
async function onLoadCountTipeAcara() {
try {
const respone = await apiGetEventTipeAcara();
if (respone) {
setCountTipeAcara(respone.data);
}
} catch (error) {
clientLogger.error("Error get count tipe acara", error);
}
}
const listStatus = [ const listStatus = [
{ {
id: 1, id: 1,
name: "Publish", name: "Publish",
jumlah: countPublish, jumlah:
countPublish == null ? (
<CustomSkeleton height={40} width={40} />
) : countPublish ? (
countPublish
) : (
"-"
),
path: RouterAdminEvent.table_publish, path: RouterAdminEvent.table_publish,
color: MainColor.green, color: MainColor.green,
icon: <IconUpload size={18} color="#4CAF4F"/>, icon: <IconUpload size={18} color="#4CAF4F" />,
}, },
{ {
id: 2, id: 2,
name: "Review", name: "Review",
jumlah: countReview, jumlah:
countReview == null ? (
<CustomSkeleton height={40} width={40} />
) : countReview ? (
countReview
) : (
"-"
),
path: RouterAdminEvent.table_review, path: RouterAdminEvent.table_review,
color: MainColor.orange, color: MainColor.orange,
icon: <IconBookmark size={18} color="#FF7043"/> icon: <IconBookmark size={18} color="#FF7043" />,
}, },
// {
// id: 3,
// name: "Draft",
// jumlah: countDraft,
// path: "",
// color: "yellow",
// },
{ {
id: 3, id: 3,
name: "Reject", name: "Reject",
jumlah: countReject, jumlah:
countReject == null ? (
<CustomSkeleton height={40} width={40} />
) : countReject ? (
countReject
) : (
"-"
),
path: RouterAdminEvent.table_reject, path: RouterAdminEvent.table_reject,
color: MainColor.red, color: MainColor.red,
icon: <IconAlertTriangle size={18} color="#FF4B4C" /> icon: <IconAlertTriangle size={18} color="#FF4B4C" />,
}, },
{ {
id: 4, id: 4,
name: "Riwayat Event", name: "Riwayat Event",
jumlah: countRiwayat, jumlah:
countRiwayat == null ? (
<CustomSkeleton height={40} width={40} />
) : countRiwayat ? (
countRiwayat
) : (
"-"
),
path: RouterAdminEvent.table_publish, path: RouterAdminEvent.table_publish,
color: AccentColor.softblue, color: AccentColor.softblue,
icon: <IconHistory size={18} color="#007CBA"/> icon: <IconHistory size={18} color="#007CBA" />,
}, },
]; ];
const listBox2 = [ const listBox2 = [
{ {
id: 1, id: 1,
name: "Tipe Acara", name: "Tipe Acara",
jumlah: countTipeAcara, jumlah:
countTipeAcara == null ? (
<CustomSkeleton height={40} width={40} />
) : countTipeAcara ? (
countTipeAcara
) : (
"-"
),
path: RouterAdminEvent.table_publish, path: RouterAdminEvent.table_publish,
color: "#A888E2", color: "#A888E2",
icon: <IconBriefcase size={18} color="#A888E2" /> icon: <IconBriefcase size={18} color="#A888E2" />,
}, },
]; ];
@@ -109,19 +229,23 @@ export default function AdminEvent_Main({
shadow="md" shadow="md"
radius="md" radius="md"
p="md" p="md"
// sx={{ borderColor: e.color, borderStyle: "solid" }} // sx={{ borderColor: e.color, borderStyle: "solid" }}
> >
<Stack spacing={0}> <Stack spacing={0}>
<Text fw={"bold"} color={AccentColor.white}>{e.name}</Text> <Text fw={"bold"} color={AccentColor.white}>
{e.name}
</Text>
<Flex align={"center"} justify={"space-between"}> <Flex align={"center"} justify={"space-between"}>
<Title c={AccentColor.white}>{e.jumlah}</Title> <Title c={AccentColor.white}>{e.jumlah}</Title>
<ThemeIcon radius={"xl"} size={"md"} color={AccentColor.white}> <ThemeIcon
radius={"xl"}
size={"md"}
color={AccentColor.white}
>
{e.icon} {e.icon}
</ThemeIcon> </ThemeIcon>
</Flex> </Flex>
</Stack> </Stack>
</Paper> </Paper>
))} ))}
</SimpleGrid> </SimpleGrid>
@@ -141,17 +265,19 @@ export default function AdminEvent_Main({
shadow="md" shadow="md"
radius="md" radius="md"
p="md" p="md"
// sx={{ borderColor: e.color, borderStyle: "solid" }} // sx={{ borderColor: e.color, borderStyle: "solid" }}
> >
<Stack spacing={0}> <Stack spacing={0}>
<Text fw={"bold"} color={AccentColor.white}>{e.name}</Text> <Text fw={"bold"} color={AccentColor.white}>
<Flex align={"center"} justify={"space-between"}> {e.name}
<Title c={AccentColor.white}>{e.jumlah}</Title> </Text>
<ThemeIcon radius={"xl"} size={"md"} bg={AccentColor.white}> <Flex align={"center"} justify={"space-between"}>
{e.icon} <Title c={AccentColor.white}>{e.jumlah}</Title>
</ThemeIcon> <ThemeIcon radius={"xl"} size={"md"} bg={AccentColor.white}>
</Flex> {e.icon}
</Stack> </ThemeIcon>
</Flex>
</Stack>
</Paper> </Paper>
))} ))}
</SimpleGrid> </SimpleGrid>

View File

@@ -0,0 +1,22 @@
const apiGetInvestasiCountDashboard = async ({ name }:
{ name: "Publish" | "Review" | "Reject" }) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(`/api/admin/investasi/dashboard/${name}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
})
return await response.json().catch(() => null);
};
export default apiGetInvestasiCountDashboard;

View File

@@ -46,49 +46,129 @@ import TablePublikasiProgresInvestasi from "./table_publikasi_progres";
import ComponentAdminGlobal_HeaderTamplate from "../../_admin_global/header_tamplate"; import ComponentAdminGlobal_HeaderTamplate from "../../_admin_global/header_tamplate";
import { AccentColor, MainColor } from "@/app_modules/_global/color"; import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { AdminColor } from "@/app_modules/_global/color/color_pallet"; import { AdminColor } from "@/app_modules/_global/color/color_pallet";
import { clientLogger } from "@/util/clientLogger";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import global_limit from "@/app/lib/limit";
import { useShallowEffect } from "@mantine/hooks";
import apiGetInvestasiCountDashboard from "../_lib/api_fetch_count_status";
export default function Admin_Investasi({ export default function Admin_Investasi({
listInvestasi, listInvestasi,
countDraft,
countReview,
countPublish,
countReject,
totalInvestasiByUser, totalInvestasiByUser,
publishProgres, publishProgres,
}: { }: {
listInvestasi: MODEL_INVESTASI[]; listInvestasi: MODEL_INVESTASI[];
countDraft: number | any;
countReview: number | any;
countPublish: number | any;
countReject: number | any;
totalInvestasiByUser: any[]; totalInvestasiByUser: any[];
publishProgres: any[]; publishProgres: any[];
}) { }) {
const [investasi, setInvestasi] = useState(listInvestasi); const [investasi, setInvestasi] = useState(listInvestasi);
const router = useRouter(); const router = useRouter();
const [countPublish, setCountPublish] = useState<number | null>(null);
const [countReview, setCountReview] = useState<number | null>(null);
const [countReject, setCountReject] = useState<number | null>(null);
useShallowEffect(() => {
handlerLoadData();
}, [])
async function handlerLoadData() {
try {
const listLoadData = [
global_limit(() => onLoadCountPublish()),
global_limit(() => onLoadCountReview()),
global_limit(() => onLoadCountReject()),
];
const result = await Promise.all(listLoadData);
} catch (error) {
clientLogger.error("Error handler load data", error);
}
}
async function onLoadCountPublish() {
try {
const response = await apiGetInvestasiCountDashboard({
name: "Publish",
});
console.log("Response Publish", response);
if (response) {
setCountPublish(response.data);
}
} catch (error) {
clientLogger.error("Error get count publish", error);
}
}
async function onLoadCountReview() {
try {
const response = await apiGetInvestasiCountDashboard({
name: "Review",
});
if (response) {
setCountReview(response.data);
}
} catch (error) {
clientLogger.error("Error get count review", error);
}
}
async function onLoadCountReject() {
try {
const response = await apiGetInvestasiCountDashboard({
name: "Reject",
});
if (response) {
setCountReject(response.data);
}
} catch (error) {
clientLogger.error("Error get count reject", error);
}
}
const listBox = [ const listBox = [
{ {
id: 1, id: 1,
name: "Publish", name: "Publish",
jumlah: countPublish, jumlah:
link: RouterAdminInvestasi_OLD.table_status_publish, countPublish == null ? (
<CustomSkeleton height={40} width={40} />
) : countPublish ? (
countPublish
) : (
"-"
),
path: RouterAdminInvestasi_OLD.table_status_publish,
color: MainColor.green, color: MainColor.green,
icon: <IconUpload size={18} color="#4CAF4F" />, icon: <IconUpload size={18} color="#4CAF4F" />,
}, },
{ {
id: 2, id: 2,
name: "Review", name: "Review",
jumlah: countReview, jumlah: countReview == null ? (
link: RouterAdminInvestasi_OLD.table_status_review, <CustomSkeleton height={40} width={40} />
) : countReview ? (
countReview
) : (
"-"
),
path: RouterAdminInvestasi_OLD.table_status_review,
color: MainColor.orange, color: MainColor.orange,
icon: <IconBookmark size={18} color="#FF7043" /> icon: <IconBookmark size={18} color="#FF7043" />
}, },
{ {
id: 3, id: 3,
name: "Reject", name: "Reject",
jumlah: countReject, jumlah: countReject == null ? (
link: RouterAdminInvestasi_OLD.table_status_reject, <CustomSkeleton height={40} width={40} />
) : countReject ? (
countReject
) : (
"-"
),
path: RouterAdminInvestasi_OLD.table_status_reject,
color: MainColor.red, color: MainColor.red,
icon: <IconAlertTriangle size={18} color="#FF4B4C" /> icon: <IconAlertTriangle size={18} color="#FF4B4C" />

View File

@@ -10,6 +10,7 @@ import { apiGetCountPortofolio, apiGetCountUserActive } from "../lib/api_fetch_m
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { clientLogger } from "@/util/clientLogger"; import { clientLogger } from "@/util/clientLogger";
import MainDashboardSkeleton from "../../_admin_global/_component/skeleton/main_dashboard_skeleton"; import MainDashboardSkeleton from "../../_admin_global/_component/skeleton/main_dashboard_skeleton";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
export default function AdminMain() { export default function AdminMain() {
const [countUser, setCountUser] = useState<number | null>(null); const [countUser, setCountUser] = useState<number | null>(null);
@@ -34,7 +35,7 @@ export default function AdminMain() {
clientLogger.error("Error get count user data", error); clientLogger.error("Error get count user data", error);
} }
} }
async function onLoadDataPortofolio() { async function onLoadDataPortofolio() {
try { try {
const response = await apiGetCountPortofolio(); const response = await apiGetCountPortofolio();
@@ -52,14 +53,26 @@ export default function AdminMain() {
{ {
id: 1, id: 1,
name: "User", name: "User",
jumlah: countUser, jumlah:
countUser == null ? (<CustomSkeleton height={40} width={40} />
) : countUser ? (
countUser
) : (
"-"
),
link: "", link: "",
icon: <IconUsers size={18} color="#0066CCFF" /> icon: <IconUsers size={18} color="#0066CCFF" />
}, },
{ {
id: 2, id: 2,
name: "Portofolio", name: "Portofolio",
jumlah: countPortofolio, jumlah:
countPortofolio == null ? (<CustomSkeleton height={40} width={40} />
) : countPortofolio ? (
countPortofolio
) : (
"-"
),
link: "", link: "",
icon: <IconFileText size={18} color={"#B6A22EFF"} /> icon: <IconFileText size={18} color={"#B6A22EFF"} />
}, },
@@ -68,35 +81,31 @@ export default function AdminMain() {
return ( return (
<> <>
{!countUser && !countPortofolio ? ( <Stack spacing={"sm"}>
<MainDashboardSkeleton /> <ComponentAdminGlobal_HeaderTamplate name="Main Dashboard" />
) : ( {/* <Title c={AdminColor.white}>Main Dashboard</Title>
<Stack spacing={"sm"}>
<ComponentAdminGlobal_HeaderTamplate name="Main Dashboard" />
{/* <Title c={AdminColor.white}>Main Dashboard</Title>
<Divider c={AdminColor.dividerWhite} mb={"md"} size={"xs"} /> */} <Divider c={AdminColor.dividerWhite} mb={"md"} size={"xs"} /> */}
<Grid> <Grid>
{listBox.map((e) => ( {listBox.map((e) => (
<Grid.Col md={4} lg={4} key={e.id}> <Grid.Col md={4} lg={4} key={e.id}>
<Paper style={{ borderColor: "transparent" }} bg={AdminColor.softBlue} withBorder shadow="md" radius="md" p="md"> <Paper style={{ borderColor: "transparent" }} bg={AdminColor.softBlue} withBorder shadow="md" radius="md" p="md">
<Stack spacing={0}> <Stack spacing={0}>
<Text fw={"bold"} c={MainColor.white}>{e.name}</Text> <Text fw={"bold"} c={MainColor.white}>{e.name}</Text>
<Flex align={"center"} justify={"space-between"}> <Flex align={"center"} justify={"space-between"}>
<Title c={MainColor.white}>{e.jumlah}</Title> <Title c={MainColor.white}>{e.jumlah}</Title>
<ThemeIcon radius={"xl"} size={"md"} color={AccentColor.white}>{e.icon}</ThemeIcon> <ThemeIcon radius={"xl"} size={"md"} color={AccentColor.white}>{e.icon}</ThemeIcon>
</Flex> </Flex>
</Stack> </Stack>
</Paper> </Paper>
</Grid.Col>
))}
<Grid.Col md={4} lg={4}>
{/* <PieChart /> */}
</Grid.Col> </Grid.Col>
</Grid> ))}
</Stack>
)} <Grid.Col md={4} lg={4}>
{/* <PieChart /> */}
</Grid.Col>
</Grid>
</Stack>
</> </>
); );
} }

View File

@@ -1,10 +1,23 @@
'use client'; "use client";
import { AccentColor, MainColor } from '@/app_modules/_global/color';
import { ActionIcon, Button, Grid, Group, Paper, Stack, Text, Title } from '@mantine/core'; import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { IconCamera } from '@tabler/icons-react'; import { Button, Grid, Group, Paper, Stack, Text, Title } from "@mantine/core";
import React from 'react'; 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 ( return (
<> <>
<Stack spacing={"lg"} py={"md"}> <Stack spacing={"lg"} py={"md"}>
@@ -54,17 +67,19 @@ function Event_Invoice() {
> >
<Grid> <Grid>
<Grid.Col span={8}> <Grid.Col span={8}>
<Group position='left' align='center' h={"100%"}> <Group position="left" align="center" h={"100%"}>
<Title order={4} color={MainColor.yellow}> <Title order={4} color={MainColor.yellow}>
9065456754325643 9065456754325643
</Title> </Title>
</Group> </Group>
</Grid.Col> </Grid.Col>
<Grid.Col span={4}> <Grid.Col span={4}>
<Group position='right'> <Group position="right">
<Button radius={"xl"} <Button
radius={"xl"}
style={{ backgroundColor: MainColor.yellow }} style={{ backgroundColor: MainColor.yellow }}
c={MainColor.darkblue}> c={MainColor.darkblue}
>
Salin Salin
</Button> </Button>
</Group> </Group>
@@ -101,15 +116,19 @@ function Event_Invoice() {
> >
<Grid> <Grid>
<Grid.Col span={8}> <Grid.Col span={8}>
<Group position='left' align='center' h={"100%"}> <Group position="left" align="center" h={"100%"}>
<Title order={4} color={MainColor.yellow}> <Title order={4} color={MainColor.yellow}>
Rp. 100.000 Rp. 100.000
</Title> </Title>
</Group> </Group>
</Grid.Col> </Grid.Col>
<Grid.Col span={4}> <Grid.Col span={4}>
<Group position='right'> <Group position="right">
<Button radius={"xl"} style={{ backgroundColor: MainColor.yellow }} c={MainColor.darkblue}> <Button
radius={"xl"}
style={{ backgroundColor: MainColor.yellow }}
c={MainColor.darkblue}
>
Salin Salin
</Button> </Button>
</Group> </Group>
@@ -131,15 +150,22 @@ function Event_Invoice() {
}} }}
> >
<Stack spacing={"sm"}> <Stack spacing={"sm"}>
<Group position='center'> <Group position="center">
<Button leftIcon={<IconCamera />} radius={"xl"} style={{ backgroundColor: MainColor.yellow }} c={MainColor.darkblue}> <Button
leftIcon={<IconCamera />}
radius={"xl"}
style={{ backgroundColor: MainColor.yellow }}
c={MainColor.darkblue}
>
Upload Upload
</Button> </Button>
</Group> </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> </Stack>
</Paper> </Paper>
<Button radius={"xl"} bg={MainColor.yellow} color='yellow' c="black"> <Button radius={"xl"} bg={MainColor.yellow} color="yellow" c="black">
Saya Sudah Transfer Saya Sudah Transfer
</Button> </Button>
</Stack> </Stack>

View File

@@ -1,84 +1,130 @@
'use client'; "use client";
import { AccentColor, MainColor } from '@/app_modules/_global/color'; import { RouterEvent } from "@/app/lib/router_hipmi/router_event";
import { MODEL_MASTER_BANK } from '@/app_modules/investasi/_lib/interface'; import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { Button, Paper, Radio, Stack, Title } from '@mantine/core'; import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data";
import { useRouter } from 'next/navigation'; import { apiGetMasterBank } from "@/app_modules/_global/lib/api_master";
import React, { useState } from 'react'; import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import {
const bank = [ gs_event_bank_id,
{ gs_nominal_sponsor,
id: 1, } from "@/app_modules/event/global_state";
namaBank: "BRI", import { MODEL_MASTER_BANK } from "@/app_modules/investasi/_lib/interface";
}, import { clientLogger } from "@/util/clientLogger";
{ import { Button, Paper, Radio, Stack, Title } from "@mantine/core";
id: 2, import { useShallowEffect } from "@mantine/hooks";
namaBank: "BCA", import { useAtom } from "jotai";
}, import _ from "lodash";
{ import { useParams, useRouter } from "next/navigation";
id: 3, import { useState } from "react";
namaBank: "BNI",
},
{
id: 4,
namaBank: "BSI",
}
]
function Event_MetodePembayaran() { function Event_MetodePembayaran() {
const params = useParams<{ id: string }>();
const [pilihBank, setPilihBank] = useState(""); const [pilihBank, setPilihBank] = useState("");
const router = useRouter(); 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 ( return (
<> <>
<Stack> {_.isEmpty(data) ? (
<Radio.Group <ComponentGlobal_IsEmptyData />
value={pilihBank} ) : (
onChange={setPilihBank} <Stack>
withAsterisk <Radio.Group
color='yellow' value={pilihBank}
> onChange={setPilihBank}
{bank.map((e) => ( withAsterisk
<Paper color="yellow"
key={e.id} >
style={{ {data.map((e) => (
backgroundColor: AccentColor.blue, <Paper
border: `2px solid ${AccentColor.darkblue}`, key={e.id}
padding: "15px", style={{
cursor: "pointer", backgroundColor: AccentColor.blue,
borderRadius: "10px", border: `2px solid ${AccentColor.darkblue}`,
color: "white", padding: "15px",
marginBottom: "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 Pilih
styles={{ </Button>
radio: { </Stack>
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>
</> </>
); );
} }
export default Event_MetodePembayaran; export default Event_MetodePembayaran;

View File

@@ -1,5 +1,7 @@
"use client"; "use client";
import { RouterEvent } from "@/app/lib/router_hipmi/router_event";
import { AccentColor, MainColor } from "@/app_modules/_global/color"; import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { gs_nominal_sponsor } from "@/app_modules/event/global_state";
import { import {
Box, Box,
Button, Button,
@@ -9,6 +11,7 @@ import {
Text, Text,
TextInput, TextInput,
Title, Title,
Loader,
} from "@mantine/core"; } from "@mantine/core";
import { import {
IconChevronRight, IconChevronRight,
@@ -17,35 +20,42 @@ import {
IconMoodSmileDizzy, IconMoodSmileDizzy,
IconMoodXd, IconMoodXd,
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import { useAtom } from "jotai";
import { useParams, useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import React from "react"; import { useState } from "react";
const listNominal = [ const listNominal = [
{ {
id: 1, id: 1,
jumlah: " 25.000", value: 25000,
icon: <IconMoodSmile />, icon: <IconMoodSmile />,
}, },
{ {
id: 2, id: 2,
jumlah: " 50.000", value: 50000,
icon: <IconMoodSmileBeam />, icon: <IconMoodSmileBeam />,
}, },
{ {
id: 3, id: 3,
jumlah: " 75.000", value: 75000,
icon: <IconMoodSmileDizzy />, icon: <IconMoodSmileDizzy />,
}, },
{ {
id: 4, id: 4,
jumlah: " 100.000", value: 100000,
icon: <IconMoodXd />, icon: <IconMoodXd />,
}, },
]; ];
function Event_PilihNominalSponsor() { function Event_PilihNominalSponsor() {
const params = useParams<{ id: string }>(); const params = useParams<{ id: string }>();
const router = useRouter(); 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 ( return (
<> <>
<Stack> <Stack>
@@ -54,6 +64,7 @@ function Event_PilihNominalSponsor() {
<Paper <Paper
key={e.id} key={e.id}
style={{ style={{
transition: "all 0.3s ease-in-out",
backgroundColor: AccentColor.blue, backgroundColor: AccentColor.blue,
border: `2px solid ${AccentColor.darkblue}`, border: `2px solid ${AccentColor.darkblue}`,
padding: "15px", padding: "15px",
@@ -62,13 +73,32 @@ function Event_PilihNominalSponsor() {
color: "white", color: "white",
marginBottom: "15px", 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 position="apart">
<Group> <Group>
{e.icon} {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> </Group>
<IconChevronRight /> {isLoadingPaper && e.id === chooseId ? (
<Loader size={20} color="yellow" />
) : (
<IconChevronRight />
)}
</Group> </Group>
</Paper> </Paper>
))} ))}
@@ -89,21 +119,41 @@ function Event_PilihNominalSponsor() {
icon={<Text fw={"bold"}>Rp.</Text>} icon={<Text fw={"bold"}>Rp.</Text>}
placeholder="0" placeholder="0"
min={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> </Stack>
</Paper> </Paper>
<Button <Button
style={{ transition: "0.5s" }} disabled={valueNominal <= 0}
loaderPosition="center"
loading={isLoading}
style={{ transition: " all 0.3s ease-in-out" }}
radius={"xl"} radius={"xl"}
bg={MainColor.yellow} bg={MainColor.yellow}
color="yellow" color="yellow"
c={"black"} c={"black"}
onClick={() => onClick={() => {
router.push("/dev/event/detail/sponsor/metode_pembayaran") setLoading(true);
} setFixNominal(valueNominal);
router.push(RouterEvent.metode_pembayaran({ id: params.id }));
}}
> >
Lanjutan Pembayaran Lanjutan Pembayaran
</Button> </Button>

View File

@@ -1,13 +1,24 @@
import { atom } from "jotai";
import { atomWithStorage } from "jotai/utils"; import { atomWithStorage } from "jotai/utils";
/** /**
* @param index | 0 - 3 | 0: Beranda, 1: Status, 2: Kontibusi, 3: Riwayat * @param index | 0 - 3 | 0: Beranda, 1: Status, 2: Kontibusi, 3: Riwayat
* @type number * @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" * @param status | "Publish", "Review", "Draft", "Reject"
* @type string * @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_kategori_app from "./master_kategori_app.json";
import master_nama_bank from "./master_nama_bank.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_kategori_app };
export { master_nama_bank }; 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,15 @@ const middlewareConfig: MiddlewareConfig = {
"/api/auth/*", "/api/auth/*",
"/api/origin-url", "/api/origin-url",
"/api/event/*", "/api/event/*",
"/api/master/*",
// "/api/image/*", // "/api/image/*",
// "/api/user/*", // "/api/user/*",
// "/api/new/*", // "/api/new/*",
// ADMIN API
// "/api/admin/event/*",
// "/api/admin/investasi/*",
// Akses awal // Akses awal
"/api/get-cookie", "/api/get-cookie",
"/api/user/activation", "/api/user/activation",