fix event admin

This commit is contained in:
2025-02-03 12:34:13 +08:00
parent 795bda6914
commit b03f242af4
13 changed files with 331 additions and 160 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -28,7 +28,7 @@
"@mantine/next": "^6.0.17",
"@mantine/notifications": "^6.0.17",
"@mantine/tiptap": "^7.5.3",
"@prisma/client": "^5.0.0",
"@prisma/client": "^6.3.0",
"@react-pdf/renderer": "^3.4.4",
"@tabler/icons-react": "^2.38.0",
"@tiptap/extension-highlight": "^2.2.3",
@@ -72,7 +72,7 @@
"p-limit": "^6.2.0",
"pdfjs-dist": "^4.6.82",
"postcss": "8.4.27",
"prisma": "^5.19.1",
"prisma": "^6.3.0",
"react": "18.2.0",
"react-countdown": "^2.3.5",
"react-dom": "18.2.0",
@@ -90,6 +90,7 @@
"react-toastify": "^9.1.3",
"sharp": "^0.33.5",
"socket.io-client": "^4.7.2",
"swr": "^2.3.0",
"tailwindcss": "3.3.3",
"ts-node": "^10.9.2",
"typescript": "5.1.6",

View File

@@ -2,8 +2,9 @@
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
engineType = "binary"
provider = "prisma-client-js"
engineType = "binary"
binaryTargets = ["native"]
}
datasource db {

View File

@@ -85,7 +85,6 @@ export async function GET(
},
});
await prisma.$disconnect();
return NextResponse.json({
success: true,
message: "Success create sponsor",
@@ -93,7 +92,6 @@ export async function GET(
});
} catch (error) {
backendLogger.error("Error get sponsor event", error);
await prisma.$disconnect();
return NextResponse.json(
{
success: false,
@@ -102,5 +100,7 @@ export async function GET(
},
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
}

View File

@@ -0,0 +1,39 @@
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.eventMaster_TipeAcara.findMany({
orderBy: {
id: "asc",
},
});
return NextResponse.json({
success: true,
message: "Success get tipe acara",
data: data,
});
} catch (error) {
backendLogger.error("Error get tipe acara", error);
return NextResponse.json(
{
success: false,
message: "Failed get tipe acara ",
reason: (error as Error).message,
},
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
}

View File

@@ -1,33 +1,55 @@
import { decrypt } from "@/app/auth/_lib/decrypt";
import { prisma } from "@/app/lib";
import { cookies } from 'next/headers'
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
export const dynamic = "force-dynamic";
export async function GET(req: NextRequest) {
const token = req.headers.get('Authorization')?.split(' ')[1];
try {
const token = req.headers.get("Authorization")?.split(" ")[1];
const decripted = await decrypt({
token: token!,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!
})
token: token!,
encodedKey: process.env.NEXT_PUBLIC_BASE_TOKEN_KEY!,
});
if (!decripted) {
return NextResponse.json({
success: false,
message: "Unauthorized"
}, { status: 401 })
await prisma.$disconnect();
return NextResponse.json(
{
success: false,
message: "Unauthorized",
},
{ status: 401 }
);
}
const user = await prisma.user.findUnique({
where: {
id: decripted.id
}
})
where: {
id: decripted.id,
},
});
// Disconnect after successful query
await prisma.$disconnect();
return NextResponse.json({
success: true,
message: "Berhasil mendapatkan data",
data: user
})
}
success: true,
message: "Berhasil mendapatkan data",
data: user,
});
} catch (error) {
// Ensure connection is closed even if error occurs
await prisma.$disconnect();
console.error("Error in user validation:", error);
return NextResponse.json(
{
success: false,
message: "Terjadi kesalahan pada server",
},
{ status: 500 }
);
}
}

View File

@@ -4,6 +4,7 @@ export {
apiGetAdminEventRiwayatCount as apiGetEventRiwayatCount,
apiGetAdminEventByStatus as apiGetDataEventByStatus,
apiGetAdminEventRiwayat,
apiGetAdminEventTipeAcara,
};
const apiGetAdminEventStatusCountDashboard = async ({
@@ -114,3 +115,20 @@ const apiGetAdminEventRiwayat = async ({
return await response.json().catch(() => null);
};
const apiGetAdminEventTipeAcara = 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/event/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,8 +1,6 @@
import { AdminEvent_Riwayat } from "@/app_modules/admin/event";
import { adminEvent_funGetListAllRiwayat } from "@/app_modules/admin/event/fun/get/get_list_all_riwayat";
export default async function Page() {
// const listRiwayat = await adminEvent_funGetListAllRiwayat({ page: 1 });
return (
<>

View File

@@ -2,11 +2,11 @@ import { AdminEvent_DetailTipeAcara } from "@/app_modules/admin/event";
import { AdminEvent_getListTipeAcara } from "@/app_modules/admin/event/fun/get/get_list_tipe_acara";
export default async function Page() {
const listTipe = await AdminEvent_getListTipeAcara()
// const listTipe = await AdminEvent_getListTipeAcara()
return (
<>
<AdminEvent_DetailTipeAcara listTipe={listTipe}/>
<AdminEvent_DetailTipeAcara />
</>
);
}

View File

@@ -0,0 +1,30 @@
"use client";
import { Stack } from "@mantine/core";
import useSwr from "swr";
const fether = (url: string) =>
fetch("https://jsonplaceholder.typicode.com" + url, {
cache: "force-cache",
next: {
revalidate: 60,
},
}).then((res) => res.json());
export default function LoadDataContoh() {
const { data, isLoading, error, mutate, isValidating } = useSwr(
"/posts/1",
fether,
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
refreshInterval: 1000,
}
);
return (
<Stack>
{isLoading && <div>Loading...</div>}
LoadDataContoh
{JSON.stringify(data, null, 2)}
</Stack>
);
}

View File

@@ -0,0 +1,9 @@
async function getDataExample() {
const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
next: {
revalidate: 60,
},
});
return res.json();
}

View File

@@ -1,14 +1,51 @@
"use client";
import { useHookstate } from "@hookstate/core";
import { Button, Stack } from "@mantine/core";
import { Suspense } from "react";
import LoadDataContoh from "./LoadDataContoh";
const listMenu = [
{
name: "Dashboard",
url: "/dashboard",
icon: "dashboard",
},
{
name: "Event",
url: "/event",
icon: "event",
},
{
name: "Donasi",
url: "/donasi",
icon: "donasi",
},
];
export default function Page() {
const fether = async (url: string) =>
fetch("https://jsonplaceholder.typicode.com" + url, {
next: {
revalidate: 2,
},
}).then(async (res) => {
const data = await res.json();
// console.log(data);
return data;
});
export default async function Page() {
const data = await fether("/posts/1");
return (
<Stack>
<Button onClick={() => {}}>tekan</Button>
</Stack>
<div>
{listMenu.map((item) => {
return (
<div key={item.name}>
<a href={item.url}>{item.name}</a>
</div>
);
})}
{/* <LoadDataContoh /> */}
<Suspense fallback={<div>Loading...</div>}>
{JSON.stringify(data, null, 2)}
</Suspense>
</div>
);
}

View File

@@ -17,7 +17,7 @@ import {
TextInput,
Title,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
import { IconCirclePlus, IconEditCircle, IconTrash } from "@tabler/icons-react";
import { useState } from "react";
import ComponentAdminGlobal_HeaderTamplate from "../../_admin_global/header_tamplate";
@@ -25,29 +25,23 @@ import { AdminEvent_funCreateTipeAcara } from "../fun/create/fun_create_tipe_aca
import { AdminEvent_funEditActivationTipeAcaraById } from "../fun/edit/fun_edit_activation_tipe_acara";
import { AdminEvent_funEditTipeAcara } from "../fun/edit/fun_edit_tipe_acara";
import { AdminEvent_getListTipeAcara } from "../fun/get/get_list_tipe_acara";
import { apiGetAdminEventTipeAcara } from "@/app/dev/admin/event/_lib/api_fecth_admin_event";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import { clientLogger } from "@/util/clientLogger";
export default function AdminEvent_DetailTipeAcara({
listTipe,
}: {
listTipe: any;
}) {
export default function AdminEvent_DetailTipeAcara() {
return (
<>
<Stack>
<ComponentAdminGlobal_HeaderTamplate name="Event" />
<DetailTipeAcara listTipe={listTipe} />
<DetailTipeAcara />
</Stack>
</>
);
}
function DetailTipeAcara({
listTipe,
}: {
listTipe: MODEL_DEFAULT_MASTER_OLD[];
}) {
const [tipe, setTipe] = useState(listTipe);
function DetailTipeAcara() {
const [tipe, setTipe] = useState<MODEL_DEFAULT_MASTER_OLD[] | null>(null);
const [name, setName] = useState("");
const [openEditor, setOpenEditor] = useState(false);
const [edit, setEdit] = useState<MODEL_DEFAULT_MASTER_OLD | null>(null);
@@ -58,6 +52,21 @@ function DetailTipeAcara({
});
const [openCreate, setOpenCreate] = useState(false);
useShallowEffect(() => {
onLoadData();
}, []);
async function onLoadData() {
try {
const respone = await apiGetAdminEventTipeAcara();
if (respone) {
setTipe(respone.data);
}
} catch (error) {
clientLogger.error("Error get tipe acara", error);
}
}
return (
<>
<Modal opened={opened} onClose={close} centered withCloseButton={false}>
@@ -101,135 +110,142 @@ function DetailTipeAcara({
</Button>
</Group>
<SimpleGrid
cols={2}
spacing="lg"
breakpoints={[
{ maxWidth: "62rem", cols: 4, spacing: "lg" },
{ maxWidth: "48rem", cols: 2, spacing: "sm" },
{ maxWidth: "36rem", cols: 1, spacing: "sm" },
]}
>
<div>
<Paper p={"md"} shadow="lg" withBorder>
<Stack>
<Title order={3}>Tipe Acara Yang Tersedia </Title>
<Stack px={"md"}>
{tipe.map((e, i) => (
<Stack key={e.id} spacing={"xs"}>
<Group position="apart">
<Text>{e.name}</Text>
<Group>
<ActionIcon
variant="transparent"
onClick={() => {
setOpenEditor(true);
setOpenCreate(false);
setEdit(e);
}}
>
<IconEditCircle color="green" />
</ActionIcon>{" "}
<ActionIcon
variant="transparent"
onClick={() => {
open();
setHapusTipe({
...hapusTipe,
id: e.id,
name: e.name,
});
}}
>
<IconTrash color="red" />
</ActionIcon>
</Group>
</Group>
<Divider />
</Stack>
))}
</Stack>
</Stack>
</Paper>
</div>
{openCreate ? (
{!tipe ? (
<CustomSkeleton height={400} width={"60%"} />
) : (
<SimpleGrid
cols={2}
spacing="lg"
breakpoints={[
{ maxWidth: "62rem", cols: 4, spacing: "lg" },
{ maxWidth: "48rem", cols: 2, spacing: "sm" },
{ maxWidth: "36rem", cols: 1, spacing: "sm" },
]}
>
<div>
<Paper p={"sm"} shadow="lg" withBorder>
<Paper p={"md"} shadow="lg" withBorder>
<Stack>
<TextInput
value={name ? name : ""}
label="Masukan Tipe"
placeholder="Contoh: Seminar, Workshop, dll."
onChange={(val) => {
setName(val.currentTarget.value);
}}
/>
<Group position="right">
<Button radius={"xl"} onClick={() => setOpenCreate(false)}>
Batal
</Button>
<Button
disabled={!name}
style={{
transition: "all 0.5s ease",
}}
color="green"
radius={"xl"}
onClick={() => onSave(name, setName, setTipe)}
>
Simpan
</Button>
</Group>
<Title order={3}>Tipe Acara Yang Tersedia </Title>
<Stack px={"md"}>
{tipe.map((e, i) => (
<Stack key={e.id} spacing={"xs"}>
<Group position="apart">
<Text>{e.name}</Text>
<Group>
<ActionIcon
variant="transparent"
onClick={() => {
setOpenEditor(true);
setOpenCreate(false);
setEdit(e);
}}
>
<IconEditCircle color="green" />
</ActionIcon>{" "}
<ActionIcon
variant="transparent"
onClick={() => {
open();
setHapusTipe({
...hapusTipe,
id: e.id,
name: e.name,
});
}}
>
<IconTrash color="red" />
</ActionIcon>
</Group>
</Group>
<Divider />
</Stack>
))}
</Stack>
</Stack>
</Paper>
</div>
) : (
""
)}
<div>
{openEditor ? (
<Paper p={"sm"} shadow="lg" withBorder>
<Stack>
<TextInput
value={edit?.name ? edit?.name : ""}
label="Edit Tipe"
placeholder="Contoh: Ramah Tamah, dll"
onChange={(val) => {
setEdit({
...(edit as any),
namaBank: val.target.value,
});
}}
/>
<Group position="right">
<Group position="apart">
<Button radius={"xl"} onClick={() => setOpenEditor(false)}>
{openCreate ? (
<div>
<Paper p={"sm"} shadow="lg" withBorder>
<Stack>
<TextInput
value={name ? name : ""}
label="Masukan Tipe"
placeholder="Contoh: Seminar, Workshop, dll."
onChange={(val) => {
setName(val.currentTarget.value);
}}
/>
<Group position="right">
<Button radius={"xl"} onClick={() => setOpenCreate(false)}>
Batal
</Button>
<Button
disabled={!edit?.name}
disabled={!name}
style={{
transition: "all 0.5s ease",
}}
radius={"xl"}
color="green"
onClick={() =>
onUpdate(edit?.id, edit?.name, setTipe, setOpenEditor)
}
radius={"xl"}
onClick={() => onSave(name, setName, setTipe)}
>
Update
Simpan
</Button>
</Group>
</Group>
</Stack>
</Paper>
</Stack>
</Paper>
</div>
) : (
""
)}
</div>
</SimpleGrid>
<div>
{openEditor ? (
<Paper p={"sm"} shadow="lg" withBorder>
<Stack>
<TextInput
value={edit?.name ? edit?.name : ""}
label="Edit Tipe"
placeholder="Contoh: Ramah Tamah, dll"
onChange={(val) => {
setEdit({
...(edit as any),
namaBank: val.target.value,
});
}}
/>
<Group position="right">
<Group position="apart">
<Button
radius={"xl"}
onClick={() => setOpenEditor(false)}
>
Batal
</Button>
<Button
disabled={!edit?.name}
style={{
transition: "all 0.5s ease",
}}
radius={"xl"}
color="green"
onClick={() =>
onUpdate(edit?.id, edit?.name, setTipe, setOpenEditor)
}
>
Update
</Button>
</Group>
</Group>
</Stack>
</Paper>
) : (
""
)}
</div>
</SimpleGrid>
)}
</>
);
}