Merge pull request #258 from bipproduction/Nico/30-jan-25

Nico/30 jan 25
This commit is contained in:
Bagasbanuna02
2025-01-30 17:52:40 +08:00
committed by GitHub
15 changed files with 494 additions and 40 deletions

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,46 @@
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.investasi.count({
where: {
MasterStatusInvestasi: {
name: fixStatus
},
}
})
return NextResponse.json({
success: true,
message: "Success get data investasi dashboard",
data: fixData,
},
{ status: 200 }
)
} catch (error) {
backendLogger.error("Error get data investasi dashboard >>", error);
return NextResponse.json({
success: false,
message: "Error get data investasi dashboard",
reason: (error as Error).message
},
{ status: 500 }
)
} finally {
await prisma.$disconnect();
}
}

View File

@@ -0,0 +1,31 @@
import { prisma } from "@/app/lib";
import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
try {
const data = await prisma.portofolio.count({
where: {
active: true
}
});
return NextResponse.json({
success: true,
message: "Data portofolio",
data: data
},
{ status: 200 }
);
} catch (error) {
backendLogger.error("Error Get Count Portofolio Main Dashboard")
return NextResponse.json({
success: false,
message: "Error Get Count Portofolio Main Dashboard",
data: null
},
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
}

View File

@@ -0,0 +1,42 @@
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 data = await prisma.user.count({
where: {
active: true
},
})
return NextResponse.json({
success: true,
message: "Data user",
data: data
},
{ status: 200 }
)
} catch (error) {
backendLogger.error("Error Get Count User Main Dashboard")
return NextResponse.json({
success: false,
message: "Gagal mendapatkan data",
reason: (error as Error).message
},
{ status: 500 }
)
} finally {
await prisma.$disconnect();
}
}

View File

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

View File

@@ -3,12 +3,12 @@ import { AdminMainDashboard_CountPOrtofolio } from "@/app_modules/admin/main_das
import { AdminMainDashboard_CountUser } from "@/app_modules/admin/main_dashboard/fun/count/fun_count_user";
export default async function Page() {
const countUser = await AdminMainDashboard_CountUser();
const countPorto = await AdminMainDashboard_CountPOrtofolio();
// const countUser = await AdminMainDashboard_CountUser();
// const countPorto = await AdminMainDashboard_CountPOrtofolio();
// await new Promise((a, b) => {
// setTimeout(a, 4000);
// });
return <AdminMain countUser={countUser} countPorto={countPorto} />;
return <AdminMain/>;
}

View File

@@ -0,0 +1,34 @@
import { Skeleton, SkeletonProps, createStyles } from '@mantine/core';
interface CustomSkeletonProps extends SkeletonProps {
isLoading?: boolean;
className?: string;
}
const useStyles = createStyles((theme) => ({
skeleton: {
'&::before': {
backgroundColor: "#1F5B9E",
},
'&::after': {
backgroundColor: "#0F3055",
},
},
}));
const CustomSkeletonAdmin: React.FC<CustomSkeletonProps> = ({
isLoading = true,
className,
...props
}) => {
const { classes, cx } = useStyles();
return (
<Skeleton
className={cx(classes.skeleton, className)}
visible={isLoading}
{...props}
/>
);
};
export default CustomSkeletonAdmin;

View File

@@ -0,0 +1,53 @@
import { MainColor, AccentColor } from '@/app_modules/_global/color';
import { AdminColor } from '@/app_modules/_global/color/color_pallet';
import { Flex, Grid, Paper, Stack, Text, ThemeIcon, Title } from '@mantine/core';
import React from 'react';
import CustomSkeletonAdmin from './customSkeletonAdmin';
import ComponentAdminGlobal_HeaderTamplate from '../../header_tamplate';
import { IconFileText, IconUsers } from '@tabler/icons-react';
function MainDashboardSkeleton() {
const listBox = [
{
id: 1,
name: "User",
jumlah: "",
link: "",
icon: <IconUsers size={18} color="#0066CCFF" />
},
{
id: 2,
name: "Portofolio",
jumlah: "countPortofolio",
link: "",
icon: <IconFileText size={18} color={"#B6A22EFF"} />
},
];
return (
<>
<Stack spacing={"sm"}>
<ComponentAdminGlobal_HeaderTamplate name="Main Dashboard" />
<Grid>
{listBox.map((e) => (
<Grid.Col md={4} lg={4} key={e.id}>
<Paper style={{ borderColor: "transparent" }} bg={AdminColor.softBlue} withBorder shadow="md" radius="md" p="md">
<Stack spacing={0}>
<Text fw={"bold"} c={MainColor.white}>{e.name}</Text>
<Flex align={"center"} justify={"space-between"}>
<CustomSkeletonAdmin w={40} h={50} />
<ThemeIcon radius={"xl"} size={"md"} color={AccentColor.white}>{e.icon}</ThemeIcon>
</Flex>
</Stack>
</Paper>
</Grid.Col>
))}
<Grid.Col md={4} lg={4}>
{/* <PieChart /> */}
</Grid.Col>
</Grid>
</Stack>
</>
);
}
export default MainDashboardSkeleton;

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

@@ -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 { AccentColor, MainColor } from "@/app_modules/_global/color";
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({
listInvestasi,
countDraft,
countReview,
countPublish,
countReject,
totalInvestasiByUser,
publishProgres,
}: {
listInvestasi: MODEL_INVESTASI[];
countDraft: number | any;
countReview: number | any;
countPublish: number | any;
countReject: number | any;
totalInvestasiByUser: any[];
publishProgres: any[];
}) {
const [investasi, setInvestasi] = useState(listInvestasi);
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 = [
{
id: 1,
name: "Publish",
jumlah: countPublish,
link: RouterAdminInvestasi_OLD.table_status_publish,
jumlah:
countPublish == null ? (
<CustomSkeleton height={40} width={40} />
) : countPublish ? (
countPublish
) : (
"-"
),
path: RouterAdminInvestasi_OLD.table_status_publish,
color: MainColor.green,
icon: <IconUpload size={18} color="#4CAF4F" />,
},
{
id: 2,
name: "Review",
jumlah: countReview,
link: RouterAdminInvestasi_OLD.table_status_review,
jumlah: countReview == null ? (
<CustomSkeleton height={40} width={40} />
) : countReview ? (
countReview
) : (
"-"
),
path: RouterAdminInvestasi_OLD.table_status_review,
color: MainColor.orange,
icon: <IconBookmark size={18} color="#FF7043" />
},
{
id: 3,
name: "Reject",
jumlah: countReject,
link: RouterAdminInvestasi_OLD.table_status_reject,
jumlah: countReject == null ? (
<CustomSkeleton height={40} width={40} />
) : countReject ? (
countReject
) : (
"-"
),
path: RouterAdminInvestasi_OLD.table_status_reject,
color: MainColor.red,
icon: <IconAlertTriangle size={18} color="#FF4B4C" />

View File

@@ -0,0 +1,30 @@
export const apiGetCountUserActive = 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/main_dashboard/user`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
return await response.json().catch(() => null);
}
export const apiGetCountPortofolio = 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/main_dashboard/portofolio`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
return await response.json().catch(() => null);
}

View File

@@ -4,49 +4,99 @@ import { AccentColor, AdminColor, MainColor } from "@/app_modules/_global/color/
import { Divider, Flex, Grid, Group, Paper, Stack, Text, ThemeIcon, Title } from "@mantine/core";
import { IconFileText, IconUsers } from "@tabler/icons-react";
import ComponentAdminGlobal_HeaderTamplate from "../../_admin_global/header_tamplate";
import { useState } from "react";
import { useShallowEffect } from "@mantine/hooks";
import { apiGetCountPortofolio, apiGetCountUserActive } from "../lib/api_fetch_main_dashboard";
import { NextResponse } from "next/server";
import { clientLogger } from "@/util/clientLogger";
import MainDashboardSkeleton from "../../_admin_global/_component/skeleton/main_dashboard_skeleton";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
export default function AdminMain() {
const [countUser, setCountUser] = useState<number | null>(null);
const [countPortofolio, setCountPortofolio] = useState<number | null>(null);
useShallowEffect(() => {
onLoadDataUser();
onLoadDataPortofolio();
}, []);
async function onLoadDataUser() {
try {
const response = await apiGetCountUserActive();
if (response) {
// console.log(response.data);
// console.log(typeof response.data);
// console.log( response);
setCountUser(response.data);
}
} catch (error) {
clientLogger.error("Error get count user data", error);
}
}
async function onLoadDataPortofolio() {
try {
const response = await apiGetCountPortofolio();
if (response) {
// console.log("Response Portofolio",response);
setCountPortofolio(response.data);
}
} catch (error) {
clientLogger.error("Error get count portofolio data", error);
}
}
export default function AdminMain({
countUser,
countPorto,
}: {
countUser: number;
countPorto: number;
}) {
const listBox = [
{
id: 1,
name: "User",
jumlah: countUser,
jumlah:
countUser == null ? (<CustomSkeleton height={40} width={40} />
) : countUser ? (
countUser
) : (
"-"
),
link: "",
icon: <IconUsers size={18} color="#0066CCFF" />
},
{
id: 2,
name: "Portofolio",
jumlah: countPorto,
jumlah:
countPortofolio == null ? (<CustomSkeleton height={40} width={40} />
) : countPortofolio ? (
countPortofolio
) : (
"-"
),
link: "",
icon: <IconFileText size={18} color={"#B6A22EFF"}/>
icon: <IconFileText size={18} color={"#B6A22EFF"} />
},
];
return (
<>
<Stack spacing={"sm"}>
<ComponentAdminGlobal_HeaderTamplate name="Main Dashboard"/>
<ComponentAdminGlobal_HeaderTamplate name="Main Dashboard" />
{/* <Title c={AdminColor.white}>Main Dashboard</Title>
<Divider c={AdminColor.dividerWhite} mb={"md"} size={"xs"} /> */}
<Grid>
{listBox.map((e) => (
<Grid.Col md={4} lg={4} key={e.id}>
<Paper style={{ borderColor: "transparent"}} bg={AdminColor.softBlue} withBorder shadow="md" radius="md" p="md">
<Stack spacing={0}>
<Paper style={{ borderColor: "transparent" }} bg={AdminColor.softBlue} withBorder shadow="md" radius="md" p="md">
<Stack spacing={0}>
<Text fw={"bold"} c={MainColor.white}>{e.name}</Text>
<Flex align={"center"} justify={"space-between"}>
<Title c={MainColor.white}>{e.jumlah}</Title>
<ThemeIcon radius={"xl"} size={"md"} color={AccentColor.white}>{e.icon}</ThemeIcon>
</Flex>
</Stack>
</Stack>
</Paper>
</Grid.Col>
))}

View File

@@ -1,5 +1,4 @@
import { Skeleton, SkeletonProps, createStyles } from '@mantine/core';
import { AccentColor } from '../_global/color';
interface CustomSkeletonProps extends SkeletonProps {
isLoading?: boolean;

View File

@@ -38,6 +38,7 @@ const middlewareConfig: MiddlewareConfig = {
// "/api/new/*",
// ADMIN API
// "/api/admin/event/*",
// "/api/admin/investasi/*",
// Akses awal