fix admin event

- detail event publish
This commit is contained in:
2025-03-25 15:05:33 +08:00
parent c9eabe5a30
commit db3994142f
12 changed files with 376 additions and 240 deletions

View File

@@ -2,14 +2,15 @@ import backendLogger from "@/util/backendLogger";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import prisma from "@/lib/prisma"; import prisma from "@/lib/prisma";
export async function GET(req: Request, export async function GET(
{ params }: { params: { id: string } }) { req: Request,
{ params }: { params: { id: string } }
) {
try { try {
const { id } = params; const { id } = params;
const data = await prisma.event.findUnique({ const data = await prisma.event.findUnique({
where: { where: {
id: id id: id,
}, },
include: { include: {
Author: { Author: {
@@ -19,33 +20,36 @@ export async function GET(req: Request,
Profile: { Profile: {
select: { select: {
name: true, name: true,
alamat: true alamat: true,
} },
} },
} },
}, },
EventMaster_TipeAcara: { EventMaster_TipeAcara: {
select: { select: {
name: true name: true,
} },
} },
} EventMaster_Status: true,
}) },
return NextResponse.json({ });
return NextResponse.json(
{
success: true, success: true,
message: "Success get data event detail", message: "Success get data event detail",
data: data, data: data,
}, },
{ status: 200 } { status: 200 }
) );
} catch (error) { } catch (error) {
backendLogger.error("Error get data event detail >>", error); backendLogger.error("Error get data event detail >>", error);
return NextResponse.json({ return NextResponse.json(
{
success: false, success: false,
message: "Error get data event detail", message: "Error get data event detail",
reason: (error as Error).message reason: (error as Error).message,
}, },
{ status: 500 } { status: 500 }
) );
} }
} }

View File

@@ -0,0 +1,11 @@
import { AdminEvent_UiNewDetail } from "@/app_modules/admin/event/_ui/ui_new_detail";
async function Page() {
return (
<>
<AdminEvent_UiNewDetail />
</>
);
}
export default Page;

View File

@@ -0,0 +1,74 @@
import { MODEL_EVENT } from "@/app_modules/event/_lib/interface";
import { Badge, Grid, Stack, Text } from "@mantine/core";
import moment from "moment";
import "moment/locale/id";
import { Admin_ComponentBoxStyle } from "../../_admin_global/_component/comp_admin_boxstyle";
function AdminEvent_ComponentDetailData({
data,
}: {
data: MODEL_EVENT | null;
}) {
const listData = [
{
label: "Nama",
value: data?.Author.Profile.name,
},
{
label: "Username",
value: data?.Author.username,
},
{
label: "Nomor",
value: `+ ${data?.Author.nomor}`,
},
{
label: "Status",
value: <Badge>{data?.EventMaster_Status.name}</Badge>,
},
{
label: "Judul",
value: data?.title,
},
{
label: "Lokasi",
value: data?.lokasi,
},
{
label: "Tipe acara",
value: data?.EventMaster_TipeAcara.name,
},
{
label: "Tanggal & Waktu mulai",
value: moment(data?.tanggal).format("LLLL"),
},
{
label: "Tanggal & Waktu selesai",
value: moment(data?.tanggalSelesai).format("LLLL"),
},
{
label: "Deskripsi",
value: data?.deskripsi,
},
];
return (
<>
{listData.map((item, index) => (
<Grid key={index}>
<Grid.Col span={3}>
<Text fw={"bold"}>{item.label}</Text>
</Grid.Col>
<Grid.Col span={1}>
<Text>:</Text>
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{item.value}</Text>
</Grid.Col>
</Grid>
))}
</>
);
}
export default AdminEvent_ComponentDetailData;

View File

@@ -0,0 +1,67 @@
import { MODEL_EVENT } from "@/app_modules/event/_lib/interface";
import { Button, Grid, Stack, Text } from "@mantine/core";
import { Admin_ComponentBoxStyle } from "../../_admin_global/_component/comp_admin_boxstyle";
import AdminEvent_ComponentDetailData from "./comp_detail_data";
import QRCode from "react-qr-code";
function AdminEvent_ComponentDetailPublish({ data }: { data: MODEL_EVENT }) {
const handleDownloadQR = () => {
const svg: any = document.getElementById(data.id);
const svgData = new XMLSerializer().serializeToString(svg);
const canvas = document.createElement("canvas");
const ctx: any = canvas.getContext("2d");
const img = new Image();
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const pngFile = canvas.toDataURL("image/png");
const downloadLink = document.createElement("a");
downloadLink.download = `QRCode ${data.title}`;
downloadLink.href = `${pngFile}`;
downloadLink.click();
};
img.src = `data:image/svg+xml;base64,${btoa(svgData)}`;
};
const donwloadButton = () => {
return (
<>
<Grid>
<Grid.Col span={3}>
<Text fw={"bold"}>QR Code</Text>
</Grid.Col>
<Grid.Col span={1}>
<Text>:</Text>
</Grid.Col>
<Grid.Col span={"auto"}>
{/* <Button onClick={handleDownloadQR}>Download QR</Button> */}
<QRCode
id={data.id}
style={{ height: 100, width: 100 }}
value={`${origin}/dev/event/konfirmasi/${data.id}`}
/>
</Grid.Col>
</Grid>
</>
);
};
return (
<>
<Grid>
<Grid.Col span={9}>
<Admin_ComponentBoxStyle>
<Stack>
<AdminEvent_ComponentDetailData data={data} />
{donwloadButton()}
</Stack>
</Admin_ComponentBoxStyle>
</Grid.Col>
</Grid>
{/* <ComponentEvent_DetailDataEvent data={data} /> */}
</>
);
}
export default AdminEvent_ComponentDetailPublish;

View File

@@ -1,74 +0,0 @@
import { AdminColor } from '@/app_modules/_global/color/color_pallet';
import CustomSkeleton from '@/app_modules/components/CustomSkeleton';
import { MODEL_EVENT } from '@/app_modules/event/_lib/interface';
import { Grid, Paper, Stack, Text, Title } from '@mantine/core';
import React from 'react';
function ComponentEvent_DetailDataAuthor({ data }: { data: MODEL_EVENT | null }) {
return (
<>
{/* {!data ? (
<CustomSkeleton height={"40vh"} width={"100%"} />
) : (
)} */}
<Paper bg={AdminColor.softBlue} p={"lg"}>
<Stack c={AdminColor.white}>
<Title order={3}>Data User</Title>
<Stack spacing={"xs"}>
<Grid>
<Grid.Col span={6}>
<Text fw={"bold"}>Nama:</Text>
</Grid.Col>
<Grid.Col span={6}>
{data ?
<Text>{data?.Author?.Profile?.name}</Text>
:
<CustomSkeleton height={30} width={"100%"} />
}
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={6}>
<Text fw={"bold"}>Username:</Text>
</Grid.Col>
<Grid.Col span={6}>
{data ?
<Text>{data?.Author?.username}</Text>
:
<CustomSkeleton height={30} width={"100%"} />
}
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={6}>
<Text fw={"bold"}>Nomor:</Text>
</Grid.Col>
<Grid.Col span={6}>
{data ?
<Text>{data?.Author?.nomor}</Text>
:
<CustomSkeleton height={30} width={"100%"} />
}
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={6}>
<Text fw={"bold"}>Alamat:</Text>
</Grid.Col>
<Grid.Col span={6}>
{data ?
<Text>{data?.Author?.Profile?.alamat}</Text>
:
<CustomSkeleton height={30} width={"100%"} />
}
</Grid.Col>
</Grid>
</Stack>
</Stack>
</Paper >
</>
);
}
export default ComponentEvent_DetailDataAuthor;

View File

@@ -0,0 +1,68 @@
"use client";
import { MODEL_EVENT } from "@/app_modules/event/_lib/interface";
import { clientLogger } from "@/util/clientLogger";
import { SimpleGrid, Stack } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { useParams } from "next/navigation";
import { useState } from "react";
import AdminGlobal_ComponentBackButton from "../../_admin_global/back_button";
import ComponentAdminGlobal_HeaderTamplate from "../../_admin_global/header_tamplate";
import { apiGetAdminDetailEventById } from "../_lib/api_fecth_admin_event";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import ComponentAdminGlobal_IsEmptyData from "../../_admin_global/is_empty_data";
import { AdminEvent_ViewDetailPublish } from "../_view/view_detail_publish";
export function AdminEvent_UiNewDetail() {
const params = useParams<{ id: string }>();
const [loading, setLoading] = useState(true);
const [data, setData] = useState<MODEL_EVENT | null>();
useShallowEffect(() => {
getDetailData();
}, []);
async function getDetailData() {
try {
setLoading(true);
const response = await apiGetAdminDetailEventById({
id: params.id,
});
if (response?.success && response?.data) {
console.log("res >>", response.data);
setData(response.data);
} else {
console.error("Invalid data format received:", response);
setData(null);
}
} catch (error) {
clientLogger.error("Error get data table detail publish", error);
setData(null);
}
}
return (
<>
<Stack>
<ComponentAdminGlobal_HeaderTamplate name="Detail event" />
<AdminGlobal_ComponentBackButton />
{data === undefined ? (
<SimpleGrid cols={2}>
<CustomSkeleton h={500} />
</SimpleGrid>
) : !data ? (
<ComponentAdminGlobal_IsEmptyData />
) : data.EventMaster_Status.name === "Publish" ? (
<AdminEvent_ViewDetailPublish data={data}/>
) : data.EventMaster_Status.name === "Review" ? (
"Detail Review"
) : data.EventMaster_Status.name === "Reject" ? (
"Detail Reject"
) : (
""
)}
</Stack>
</>
);
}

View File

@@ -158,14 +158,6 @@ export function AdminEvent_ViewDetailPeserta() {
</thead> </thead>
<tbody>{renderTableBody()}</tbody> <tbody>{renderTableBody()}</tbody>
</Table> </Table>
{_.isEmpty(data) ? (
<ComponentAdminGlobal_IsEmptyData
text="Tidak ada peserta"
marginTop={100}
/>
) : (
""
)}
</ScrollArea> </ScrollArea>
<Center mt={"xl"}> <Center mt={"xl"}>

View File

@@ -0,0 +1,48 @@
import { MODEL_EVENT } from "@/app_modules/event/_lib/interface";
import { IconCircleCheck } from "@tabler/icons-react";
import { useAtom } from "jotai";
import { gs_admin_event_menu_publish } from "../_lib/global_state";
import { Stack, Group, Button } from "@mantine/core";
import AdminGlobal_ComponentBackButton from "../../_admin_global/back_button";
import AdminEvent_ComponentDetailPublish from "../_component/comp_detail_publish";
import { AdminEvent_ViewDetailPeserta } from "./view_detail_peserta";
export function AdminEvent_ViewDetailPublish({ data }: { data: MODEL_EVENT }) {
const [selectPage, setSelectPage] = useAtom(gs_admin_event_menu_publish);
const listPage = [
{
id: "1",
name: "Detail Event",
icon: <IconCircleCheck />,
},
{
id: "2",
name: "Daftar Peserta",
icon: <IconCircleCheck />,
},
];
return (
<>
<Stack mt={"lg"}>
<Group>
{listPage.map((e) => (
<Button
radius={"xl"}
key={e.id}
color={selectPage == e.id ? "green" : "gray"}
onClick={() => setSelectPage(e.id)}
style={{
transition: "all 0.5s",
}}
>
{e.name}
</Button>
))}
</Group>
{selectPage == "1" && <AdminEvent_ComponentDetailPublish data={data} />}
{selectPage == "2" && <AdminEvent_ViewDetailPeserta />}
</Stack>
</>
);
}

View File

@@ -1,59 +0,0 @@
import { SimpleGrid } from '@mantine/core';
import React, { useState } from 'react';
import ComponentEvent_DetailDataAuthor from '../_component/detail_data_author';
import ComponentEvent_DetailDataEvent from '../_component/detail_data_event';
import { useParams } from 'next/navigation';
import { apiGetAdminDetailEventById } from '../_lib/api_fecth_admin_event';
import { MODEL_EVENT } from '@/app_modules/event/_lib/interface';
import { clientLogger } from '@/util/clientLogger';
import { useShallowEffect } from '@mantine/hooks';
function AdminEvent_ViewDetailData({ }) {
const params = useParams<{ id: string }>();
const [loading, setLoading] = useState(true);
const [data, setData] = useState<MODEL_EVENT | null>(null);
useShallowEffect(() => {
getDetailData();
}, [])
async function getDetailData() {
try {
setLoading(true);
const response = await apiGetAdminDetailEventById({
id: params.id,
})
if (response?.success && response?.data) {
setTimeout(() => {
setData(response.data);
}, 1000)
} else {
console.error("Invalid data format received:", response);
setData(null);
}
} catch (error) {
clientLogger.error("Error get data table detail publish", error);
setData(null);
}
}
return (
<>
<SimpleGrid
cols={2}
breakpoints={[
{ maxWidth: "48rem", cols: 2, spacing: "sm" },
{ maxWidth: "36rem", cols: 1, spacing: "sm" },
]}
>
{/* //Data Author */}
<ComponentEvent_DetailDataAuthor data={data}/>
{/* Data Event */}
<ComponentEvent_DetailDataEvent data={data} />
</SimpleGrid>
</>
);
}
export default AdminEvent_ViewDetailData;

View File

@@ -6,7 +6,7 @@ import { IconCircleCheck } from '@tabler/icons-react';
import { Button, Group, Stack } from '@mantine/core'; import { Button, Group, Stack } from '@mantine/core';
import AdminGlobal_ComponentBackButton from '../../_admin_global/back_button'; import AdminGlobal_ComponentBackButton from '../../_admin_global/back_button';
import { AdminEvent_ViewDetailPeserta } from '../_view'; import { AdminEvent_ViewDetailPeserta } from '../_view';
import AdminEvent_ViewDetailData from '../detail/view_detail_data'; import AdminEvent_ComponentDetailPublish from '../_component/comp_detail_publish';
import AdminEvent_DetailDataSponsor from '../_component/detail_data_sponsor'; import AdminEvent_DetailDataSponsor from '../_component/detail_data_sponsor';
function AdminEvent_DetailPublish() { function AdminEvent_DetailPublish() {
@@ -22,11 +22,11 @@ function AdminEvent_DetailPublish() {
name: "Daftar Peserta", name: "Daftar Peserta",
icon: <IconCircleCheck />, icon: <IconCircleCheck />,
}, },
{ // {
id: "3", // id: "3",
name: "Daftar Sponsor", // name: "Daftar Sponsor",
icon: <IconCircleCheck />, // icon: <IconCircleCheck />,
} // }
] ]
return ( return (
<> <>
@@ -50,14 +50,14 @@ function AdminEvent_DetailPublish() {
))} ))}
</Group> </Group>
{selectPage == "1" ? ( {selectPage == "1" ? (
<AdminEvent_ViewDetailData /> <AdminEvent_ComponentDetailPublish data={{} as any} />
) : null} ) : null}
{selectPage == "2" ? ( {selectPage == "2" ? (
<AdminEvent_ViewDetailPeserta /> <AdminEvent_ViewDetailPeserta />
) : null} ) : null}
{selectPage == "3" ? ( {/* {selectPage == "3" ? (
<AdminEvent_DetailDataSponsor /> <AdminEvent_DetailDataSponsor />
) : null} ) : null} */}
</Stack> </Stack>
</> </>
); );

View File

@@ -6,6 +6,7 @@ import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import { MODEL_EVENT } from "@/app_modules/event/_lib/interface"; import { MODEL_EVENT } from "@/app_modules/event/_lib/interface";
import { clientLogger } from "@/util/clientLogger"; import { clientLogger } from "@/util/clientLogger";
import { import {
Box,
Button, Button,
Center, Center,
Pagination, Pagination,
@@ -18,13 +19,14 @@ import {
TextInput, TextInput,
} from "@mantine/core"; } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import { IconEyeCheck, IconSearch } from "@tabler/icons-react"; import { IconDownload, IconEyeCheck, IconSearch } from "@tabler/icons-react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import QRCode from "react-qr-code"; import QRCode from "react-qr-code";
import { ComponentAdminGlobal_TitlePage } from "../../_admin_global/_component"; import { ComponentAdminGlobal_TitlePage } from "../../_admin_global/_component";
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"; import { AdminColor } from "@/app_modules/_global/color/color_pallet";
import Admin_DetailButton from "../../_admin_global/_component/button/detail_button";
export default function AdminEvent_TablePublish() { export default function AdminEvent_TablePublish() {
return ( return (
@@ -119,33 +121,31 @@ function TableStatus() {
return data.map((e, i) => ( return data.map((e, i) => (
<tr key={i}> <tr key={i}>
<td> {/* <td>
<Center w={200}> <Center>
<QRCode <QRCode
id={e.id} id={e.id}
style={{ height: 70, width: 70 }} style={{ height: 70, width: 70 }}
value={`${origin}/dev/event/konfirmasi/${e.id}`} value={`${origin}/dev/event/konfirmasi/${e.id}`}
/> />
</Center> </Center>
</td> </td> */}
<td> <td>
<Center w={200}> <Center c={AdminColor.white}>
<Button onClick={() => handleDownloadQR(e.id, e.title)}> <Box w={100}>
Download QR <Text lineClamp={1}>{e?.Author?.username} dasdsasdasdsa sadasd</Text>
</Button> </Box>
</Center> </Center>
</td> </td>
<td> <td>
<Center c={AdminColor.white} w={200}> <Center c={AdminColor.white} >
<Text>{e?.Author?.username}</Text> <Box w={100}>
</Center>
</td>
<td>
<Center c={AdminColor.white} w={200}>
<Text lineClamp={2}>{e.title}</Text> <Text lineClamp={2}>{e.title}</Text>
</Box>
</Center> </Center>
</td> </td>
<td> {/* <td>
<Center c={AdminColor.white} w={200}> <Center c={AdminColor.white} w={200}>
<Text>{e.lokasi}</Text> <Text>{e.lokasi}</Text>
</Center> </Center>
@@ -154,10 +154,10 @@ function TableStatus() {
<Center c={AdminColor.white} w={200}> <Center c={AdminColor.white} w={200}>
<Text>{e.EventMaster_TipeAcara?.name}</Text> <Text>{e.EventMaster_TipeAcara?.name}</Text>
</Center> </Center>
</td> </td> */}
<td> <td>
<Center c={AdminColor.white} w={200}> <Center c={AdminColor.white}>
<Text align="center"> <Text align="center">
{new Intl.DateTimeFormat("id-ID", { {new Intl.DateTimeFormat("id-ID", {
dateStyle: "full", dateStyle: "full",
@@ -172,7 +172,7 @@ function TableStatus() {
</Center> </Center>
</td> </td>
<td> <td>
<Center c={AdminColor.white} w={200}> <Center c={AdminColor.white}>
<Text align="center"> <Text align="center">
{new Intl.DateTimeFormat("id-ID", { {new Intl.DateTimeFormat("id-ID", {
dateStyle: "full", dateStyle: "full",
@@ -187,7 +187,7 @@ function TableStatus() {
</Center> </Center>
</td> </td>
<td> {/* <td>
<Center c={AdminColor.white} w={400}> <Center c={AdminColor.white} w={400}>
<Spoiler <Spoiler
hideLabel="sembunyikan" hideLabel="sembunyikan"
@@ -197,9 +197,9 @@ function TableStatus() {
{e.deskripsi} {e.deskripsi}
</Spoiler> </Spoiler>
</Center> </Center>
</td> </td> */}
<td> {/* <td>
<Button <Button
loaderPosition="center" loaderPosition="center"
loading={loading && e.id === eventId} loading={loading && e.id === eventId}
@@ -214,6 +214,26 @@ function TableStatus() {
> >
Detail Detail
</Button> </Button>
</td> */}
<td>
<Center>
<Button
leftIcon={<IconDownload />}
radius="xl"
onClick={() => handleDownloadQR(e.id, e.title)}
>
Download QR
</Button>
</Center>
</td>
<td>
<Center>
<Admin_DetailButton
path={RouterAdminEvent.new_detail({ id: e.id })}
/>
</Center>
</td> </td>
</tr> </tr>
)); ));
@@ -241,40 +261,25 @@ function TableStatus() {
) : ( ) : (
<Paper p="md" bg={AdminColor.softBlue} h="80vh"> <Paper p="md" bg={AdminColor.softBlue} h="80vh">
<ScrollArea w="100%" h="90%"> <ScrollArea w="100%" h="90%">
<Table <Table verticalSpacing="md" horizontalSpacing="md" p="md">
verticalSpacing="md"
horizontalSpacing="md"
p="md"
w={1500}
>
<thead> <thead>
<tr> <tr>
<th>
<Center c={AdminColor.white}>QR Code</Center>
</th>
<th>
<Center c={AdminColor.white}>Download QR</Center>
</th>
<th> <th>
<Center c={AdminColor.white}>Username</Center> <Center c={AdminColor.white}>Username</Center>
</th> </th>
<th> <th>
<Center c={AdminColor.white}>Judul</Center> <Center c={AdminColor.white}>Judul</Center>
</th> </th>
<th>
<Center c={AdminColor.white}>Lokasi</Center>
</th>
<th>
<Center c={AdminColor.white}>Tipe Acara</Center>
</th>
<th> <th>
<Center c={AdminColor.white}>Tanggal & Waktu Mulai</Center> <Center c={AdminColor.white}>Tanggal & Waktu Mulai</Center>
</th> </th>
<th> <th>
<Center c={AdminColor.white}>Tanggal & Waktu Selesai</Center> <Center c={AdminColor.white}>
Tanggal & Waktu Selesai
</Center>
</th> </th>
<th> <th>
<Center c={AdminColor.white}>Deskripsi</Center> <Center c={AdminColor.white}>QR Code</Center>
</th> </th>
<th> <th>
<Center c={AdminColor.white}>Aksi</Center> <Center c={AdminColor.white}>Aksi</Center>

View File

@@ -3,7 +3,10 @@ export const RouterAdminEvent = {
// detail // detail
detail_peserta: "/dev/admin/event/detail/peserta/", detail_peserta: "/dev/admin/event/detail/peserta/",
detail_publish: "/dev/admin/event/detail/publish/", detail_publish: ({ id }: { id: string }) =>
`/dev/admin/event/detail/publish/${id}`,
new_detail: ({ id }: { id: string }) =>
`/dev/admin/event/${id}`,
detail_sponsor: "/dev/admin/event/detail/detail_sponsor/", detail_sponsor: "/dev/admin/event/detail/detail_sponsor/",
// child // child
@@ -14,7 +17,4 @@ export const RouterAdminEvent = {
table_review: "/dev/admin/event/table/review", table_review: "/dev/admin/event/table/review",
table_publish: "/dev/admin/event/table/publish", table_publish: "/dev/admin/event/table/publish",
table_reject: "/dev/admin/event/table/reject", table_reject: "/dev/admin/event/table/reject",
}; };