fix: donasi

deskripsi:
src/app/api/donasi/[id]/route.ts
src/app/api/donasi/[id]/temporary-create/route.ts
src/app/dev/(user)/donasi/create/cerita_penggalang/[id]/page.tsx
src/app/dev/(user)/donasi/detail/draft/[id]/page.tsx
src/app/dev/(user)/donasi/detail/review/[id]/page.tsx
src/app_modules/admin/_components_v3/comp_button_user_circle.tsx
src/app_modules/donasi/component/detail_main/cerita_penggalang.tsx
src/app_modules/donasi/create/create_cerita_penggalang.tsx
src/app_modules/donasi/create/create_donasi_new.tsx
src/app_modules/donasi/detail/detail_draft/index.tsx
src/app_modules/donasi/detail/detail_review/index.tsx
src/app_modules/donasi/lib/api_donasi.ts

- Perubahan use server menjadi API

No Issue
This commit is contained in:
2025-06-05 16:21:37 +08:00
parent c10277f026
commit 0e4dda5356
12 changed files with 313 additions and 89 deletions

View File

@@ -0,0 +1,88 @@
import { prisma } from "@/lib";
import { NextResponse } from "next/server";
export const dynamic = "force-dynamic";
// GET ONE DATA DONASI
export async function GET(
request: Request,
context: { params: { id: string } }
) {
try {
let dataFix;
const { id } = context.params;
const { searchParams } = new URL(request.url);
const kategori = searchParams.get("cat");
if (kategori == "semua") {
dataFix = await prisma.donasi.findFirst({
where: {
id: id,
},
include: {
Author: true,
imageDonasi: true,
CeritaDonasi: true,
DonasiMaster_Ketegori: true,
DonasiMaster_Durasi: true,
DonasiMaster_Status: true,
Donasi_Invoice: true,
Donasi_Kabar: true,
Donasi_PencairanDana: true,
},
});
} else if (kategori == "count") {
dataFix = await prisma.donasi_Invoice.count({
where: {
donasiId: id,
donasiMaster_StatusInvoiceId: {
equals: "1",
},
},
});
} else {
let tampil;
if (kategori == "author") {
tampil = {
authorId: true,
Author: {
select: {
username: true,
},
},
};
} else if (kategori == "cerita") {
tampil = {
id: true,
createdAt: true,
CeritaDonasi: {
select: {
cerita: true,
},
},
};
}
dataFix = await prisma.donasi.findFirst({
where: {
id: id,
},
select: tampil,
});
}
return NextResponse.json(
{ success: true, message: "Berhasil mendapatkan data", data: dataFix },
{ status: 200 }
);
} catch (error) {
console.error(error);
return NextResponse.json(
{
success: false,
message: "Gagal mendapatkan data, coba lagi nanti ",
reason: (error as Error).message,
},
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,28 @@
import { NextResponse } from "next/server";
import { prisma } from "@/lib";
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
try {
const { id } = params;
const data = await prisma.donasi_TemporaryCreate.findFirst({
where: {
id: id,
},
});
return NextResponse.json({
success: true,
message: "Data berhasil diambil",
data: data,
});
} catch (error) {
return NextResponse.json({
success: false,
message: "Terjadi kesalahan saat mengambil data",
reason: error as Error,
});
}
}

View File

@@ -1,17 +1,9 @@
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { CreateCeritaPenggalangDonasi } from "@/app_modules/donasi";
import { Donasi_getTemporaryCreate } from "@/app_modules/donasi/fun/get/get_temporary_create";
export default async function Page({ params }: { params: { id: string } }) {
const getTemporaryCreate = await Donasi_getTemporaryCreate(params.id);
const userLoginId = await funGetUserIdByToken();
export default async function Page() {
return (
<>
<CreateCeritaPenggalangDonasi
dataTemporary={getTemporaryCreate as any}
userId={userLoginId as string}
/>
<CreateCeritaPenggalangDonasi />
</>
);
}

View File

@@ -1,14 +1,9 @@
import { DetailDraftDonasi } from "@/app_modules/donasi";
import { Donasi_getOneById } from "@/app_modules/donasi/fun/get/get_one_donasi_by_id";
export default async function Page({ params }: { params: { id: string } }) {
const donasiId = params.id
const dataDonasi = await Donasi_getOneById(donasiId);
export default async function Page() {
return (
<>
<DetailDraftDonasi dataDonasi={dataDonasi as any} />
<DetailDraftDonasi />
</>
);
}

View File

@@ -1,12 +1,9 @@
import { DetailReviewDonasi } from "@/app_modules/donasi";
import { Donasi_getOneById } from "@/app_modules/donasi/fun/get/get_one_donasi_by_id";
export default async function Page({ params }: { params: { id: string } }) {
const dataDonasi = await Donasi_getOneById(params.id);
export default async function Page() {
return (
<>
<DetailReviewDonasi dataDonasi={dataDonasi as any} />
<DetailReviewDonasi />
</>
);
}

View File

@@ -245,7 +245,7 @@ export function Admin_V3_ComponentButtonUserCircle({
color="yellow"
processing
label={<Text c="black" fz={10}>{countNotifikasi}</Text>}
label={<Text c="black" fz={10}>{countNotifikasi ? countNotifikasi : ""}</Text>}
>
<IconBell color="white" />
</Indicator>
@@ -284,7 +284,7 @@ export function Admin_V3_ComponentButtonUserCircle({
<Indicator
color="yellow"
processing
label={<Text c="black" fz={10}>{countNotifikasi}</Text>}
label={<Text c="black" fz={10}>{countNotifikasi ? countNotifikasi : ""}</Text>}
>
<IconBell size={18} color={e.color || "white"} />
</Indicator>

View File

@@ -13,7 +13,6 @@ import {
Box,
} from "@mantine/core";
import { IconCircleChevronRight } from "@tabler/icons-react";
import moment from "moment";
import { useState } from "react";
import {
AccentColor,
@@ -22,6 +21,8 @@ import {
import ComponentGlobal_Loader from "@/app_modules/_global/component/loader";
import { Comp_V3_SetInnerHTMLWithStiker } from "@/app_modules/_global/component/new/comp_V3_set_html_with_stiker";
import { funReplaceHtml } from "@/app_modules/_global/fun/fun_replace_html";
import moment from "moment";
import "moment/locale/id";
export default function ComponentDonasi_CeritaPenggalangMain({
donasi,
@@ -51,9 +52,7 @@ export default function ComponentDonasi_CeritaPenggalangMain({
<Stack>
<Group position="apart">
<Text>
{new Intl.DateTimeFormat("id-ID", { dateStyle: "full" }).format(
donasi?.createdAt
)}
{moment(donasi?.createdAt).format("DD MMM YYYY")}
</Text>
<ActionIcon
variant="transparent"

View File

@@ -1,8 +1,5 @@
"use client";
import { DIRECTORY_ID } from "@/lib";
import { IRealtimeData } from "@/lib/global_state";
import { RouterDonasi } from "@/lib/router_hipmi/router_donasi";
import { MainColor } from "@/app_modules/_global/color/color_pallet";
import {
ComponentGlobal_BoxUploadImage,
@@ -10,11 +7,20 @@ import {
} from "@/app_modules/_global/component";
import ComponentGlobal_BoxInformation from "@/app_modules/_global/component/box_information";
import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown";
import Component_V3_Label_TextInput from "@/app_modules/_global/component/new/comp_V3_label_text_input";
import { Component_V3_TextEditor } from "@/app_modules/_global/component/new/comp_V3_text_editor";
import { funGlobal_UploadToStorage } from "@/app_modules/_global/fun";
import { funReplaceHtml } from "@/app_modules/_global/fun/fun_replace_html";
import { apiNewGetUserIdByToken } from "@/app_modules/_global/lib/api_fetch_global";
import { maxInputLength } from "@/app_modules/_global/lib/maximal_setting";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import notifikasiToAdmin_funCreate from "@/app_modules/notifikasi/fun/create/create_notif_to_admin";
import { DIRECTORY_ID } from "@/lib";
import { IRealtimeData } from "@/lib/global_state";
import { RouterDonasi } from "@/lib/router_hipmi/router_donasi";
import { clientLogger } from "@/util/clientLogger";
import {
AspectRatio,
@@ -22,30 +28,22 @@ import {
Center,
Image,
Stack,
TextInput,
Textarea,
TextInput
} from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks";
import { IconPhoto } from "@tabler/icons-react";
import { useAtom } from "jotai";
import _ from "lodash";
import { useRouter } from "next/navigation";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import { WibuRealtime } from "wibu-pkg";
import { Donasi_funCreate } from "../fun/create/fun_create_donasi";
import { gs_donasi_hot_menu } from "../global_state";
import { apiGetTemporaryCreate } from "../lib/api_donasi";
import { MODEL_DONASI_TEMPORARY } from "../model/interface";
import { Component_V3_TextEditor } from "@/app_modules/_global/component/new/comp_V3_text_editor";
import Component_V3_Label_TextInput from "@/app_modules/_global/component/new/comp_V3_label_text_input";
import { funReplaceHtml } from "@/app_modules/_global/fun/fun_replace_html";
import { maxInputLength } from "@/app_modules/_global/lib/maximal_setting";
export default function CreateCeritaPenggalangDonasi({
dataTemporary,
userId,
}: {
dataTemporary: MODEL_DONASI_TEMPORARY;
userId: string;
}) {
export default function CreateCeritaPenggalangDonasi() {
const { id } = useParams();
const router = useRouter();
const [isLoading, setLoading] = useState(false);
const [donasiHotMenu, setDonasiHotMenu] = useAtom(gs_donasi_hot_menu);
@@ -56,24 +54,58 @@ export default function CreateCeritaPenggalangDonasi({
namaBank: "",
rekening: "",
});
const [temporary, setTemporary] = useState(dataTemporary);
const [temporary, setTemporary] = useState<MODEL_DONASI_TEMPORARY | null>(
null
);
const [file, setFile] = useState<File | null>(null);
const [img, setImg] = useState<any | null>();
const [userLoginId, setUserLoginId] = useState<string | null>(null);
useShallowEffect(() => {
handleGetUserId();
handleGetTemporaryCreate();
}, []);
async function handleGetUserId() {
try {
const response = await apiNewGetUserIdByToken();
if (response) {
setUserLoginId(response.userId);
}
} catch (error) {
console.error("Error get data detail", error);
}
}
async function handleGetTemporaryCreate() {
try {
const response = await apiGetTemporaryCreate({ id: id as string });
if (response && response.success) {
setTemporary(response.data);
} else {
console.log("response temporary create", response.message);
}
} catch (error) {
console.error("Error get temporary create", error);
}
}
async function onCreate() {
if (_.values(data).includes(""))
return ComponentGlobal_NotifikasiPeringatan("Lengkapin Data");
const body = {
id: temporary.id,
title: temporary.title,
target: temporary.target,
donasiMaster_KategoriId: temporary.donasiMaster_KategoriId,
donasiMaster_DurasiId: temporary.donasiMaster_DurasiId,
authorId: userId,
id: temporary?.id,
title: temporary?.title,
target: temporary?.target,
donasiMaster_KategoriId: temporary?.donasiMaster_KategoriId,
donasiMaster_DurasiId: temporary?.donasiMaster_DurasiId,
authorId: userLoginId as string,
namaBank: data.namaBank,
rekening: data.rekening,
imageId: temporary.imageId,
imageId: temporary?.imageId,
CeritaDonasi: {
pembukaan: data.pembukaan,
cerita: data.cerita,
@@ -139,9 +171,12 @@ export default function CreateCeritaPenggalangDonasi({
clientLogger.error("Error create cerita donasi", error);
}
}
if (!temporary) return <CustomSkeleton height={400} />;
return (
<>
<Stack spacing={50} px={"xl"} pb={"md"}>
<Stack spacing={50} px={"sm"} pb={"md"}>
<Stack spacing={"sm"}>
<ComponentGlobal_BoxInformation informasi="Cerita Anda adalah kunci untuk menginspirasi kebaikan. Jelaskan dengan jujur dan jelas tujuan penggalangan dana ini agar calon donatur memahami dampak positif yang dapat mereka wujudkan melalui kontribusi mereka." />

View File

@@ -116,7 +116,7 @@ export default function CreateDonasiNew() {
return (
<>
<Stack spacing={"md"} px={"xl"}>
<Stack spacing={"md"} px={"sm"}>
<ComponentGlobal_BoxInformation informasi="Lengkapi semua data di bawah untuk selanjutnya mengisi cerita penggalangan dana." />
<Select
styles={{

View File

@@ -17,14 +17,39 @@ import ComponentDonasi_DetailDataGalangDana from "../../component/detail_galang_
import ComponentDonasi_CeritaPenggalangMain from "../../component/detail_main/cerita_penggalang";
import { Donasi_funGantiStatus } from "../../fun/update/fun_ganti_status";
import { MODEL_DONASI } from "../../model/interface";
import { apiGetOneDonasiById } from "../../lib/api_donasi";
import { useShallowEffect } from "@mantine/hooks";
import { useParams } from "next/navigation";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
export default function DetailDraftDonasi({
dataDonasi,
}: {
dataDonasi: MODEL_DONASI;
}) {
const [data, setData] = useState(dataDonasi);
export default function DetailDraftDonasi() {
const param = useParams<{ id: string }>();
const [data, setData] = useState({} as MODEL_DONASI);
const [loading, setLoading] = useState(true);
useShallowEffect(() => {
getData();
}, []);
async function getData() {
try {
setLoading(true);
const response = await apiGetOneDonasiById(param.id, "semua");
if (response.success) {
setData(response.data);
}
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
if (loading) {
return <CustomSkeleton height={400} />;
}
return (
<>
<Stack spacing={"xl"} py={"md"}>

View File

@@ -1,36 +1,60 @@
"use client";
import { RouterDonasi } from "@/lib/router_hipmi/router_donasi";
import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { funGetUserIdByToken } from "@/app_modules/_global/fun/get";
import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil";
import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global/notifikasi_peringatan";
import { UIGlobal_Modal } from "@/app_modules/_global/ui";
import CustomSkeleton from "@/app_modules/components/CustomSkeleton";
import notifikasiToAdmin_funCreate from "@/app_modules/notifikasi/fun/create/create_notif_to_admin";
import mqtt_client from "@/util/mqtt_client";
import { IRealtimeData } from "@/lib/global_state";
import { RouterDonasi } from "@/lib/router_hipmi/router_donasi";
import { Button, Stack } from "@mantine/core";
import { useRouter } from "next/navigation";
import { useShallowEffect } from "@mantine/hooks";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import { WibuRealtime } from "wibu-pkg";
import ComponentDonasi_DetailDataGalangDana from "../../component/detail_galang_dana/detail_data_donasi";
import ComponentDonasi_CeritaPenggalangMain from "../../component/detail_main/cerita_penggalang";
import { Donasi_funGantiStatus } from "../../fun/update/fun_ganti_status";
import { MODEL_DONASI } from "../../model/interface";
import { donasi_checkStatus } from "../../fun";
import { WibuRealtime } from "wibu-pkg";
import { IRealtimeData } from "@/lib/global_state";
import { AccentColor, MainColor } from "@/app_modules/_global/color";
import { Donasi_funGantiStatus } from "../../fun/update/fun_ganti_status";
import { apiGetOneDonasiById } from "../../lib/api_donasi";
import { MODEL_DONASI } from "../../model/interface";
export default function DetailReviewDonasi({
dataDonasi,
}: {
dataDonasi: MODEL_DONASI;
}) {
const [donasi, setDonasi] = useState(dataDonasi);
export default function DetailReviewDonasi() {
const param = useParams<{ id: string }>();
const [data, setData] = useState({} as MODEL_DONASI);
const [loading, setLoading] = useState(true);
useShallowEffect(() => {
getData();
}, []);
async function getData() {
try {
setLoading(true);
const response = await apiGetOneDonasiById(param.id, "semua");
if (response.success) {
setData(response.data);
}
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
if (loading) {
return <CustomSkeleton height={400} />;
}
return (
<>
<Stack spacing={"xl"} pb={"md"}>
<ComponentDonasi_DetailDataGalangDana donasi={donasi} />
<ComponentDonasi_CeritaPenggalangMain donasi={donasi} />
<ButtonBatalReview donasi={donasi} />
<ComponentDonasi_DetailDataGalangDana donasi={data} />
<ComponentDonasi_CeritaPenggalangMain donasi={data} />
<ButtonBatalReview donasi={data} />
</Stack>
</>
);
@@ -46,7 +70,6 @@ function ButtonBatalReview({ donasi }: { donasi: MODEL_DONASI }) {
if (check) {
const res = await Donasi_funGantiStatus(donasi.id, "3");
if (res.status === 200) {
const dataNotifikasi: IRealtimeData = {
appId: res.data?.id as any,
status: res.data?.DonasiMaster_Status?.name as any,
@@ -71,10 +94,9 @@ function ButtonBatalReview({ donasi }: { donasi: MODEL_DONASI }) {
pushNotificationTo: "ADMIN",
dataMessage: dataNotifikasi,
});
ComponentGlobal_NotifikasiBerhasil("Berhasil Dibatalkan");
router.push(RouterDonasi.status_galang_dana({ id: "3" }));
}
ComponentGlobal_NotifikasiBerhasil("Berhasil Dibatalkan");
router.push(RouterDonasi.status_galang_dana({ id: "3" }));
} else {
setLoading(false);
ComponentGlobal_NotifikasiPeringatan(res.message);

View File

@@ -47,7 +47,8 @@ export const apiGetOneDonasiById = async (path: string, kategori: string) => {
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) return await token.json().catch(() => null);
const response = await fetch(`/api/new/donasi/${path}?cat=${kategori}`, {
// const response = await fetch(`/api/new/donasi/${path}?cat=${kategori}`, {
const response = await fetch(`/api/donasi/${path}?cat=${kategori}`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
@@ -58,10 +59,8 @@ export const apiGetOneDonasiById = async (path: string, kategori: string) => {
return await response.json().catch(() => null);
};
export const apiGetDonasiCeritaPenggalang = async ({ id }: { id: string }) => {
try {
console.log("id in Fetch>>", id);
// Fetch token from cookie
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) {
@@ -80,13 +79,57 @@ export const apiGetDonasiCeritaPenggalang = async ({ id }: { id: string }) => {
if (!response.ok) {
const errorData = await response.json().catch(() => null);
console.error("Failed to get donasi cerita penggalang", response.statusText, errorData);
throw new Error(errorData?.message || "Failed to get donasi cerita penggalang");
console.error(
"Failed to get donasi cerita penggalang",
response.statusText,
errorData
);
throw new Error(
errorData?.message || "Failed to get donasi cerita penggalang"
);
}
// Return the JSON response
const data = await response.json();
return data;
} catch (error) {
console.error("Error get donasi cerita penggalang", error);
throw error; // Re-throw the error to handle it in the calling function
}
};
export const apiGetTemporaryCreate = async ({ id }: { id: string }) => {
try {
// Fetch token from cookie
const { token } = await fetch("/api/get-cookie").then((res) => res.json());
if (!token) {
console.error("No token found");
return null;
}
const response = await fetch(`/api/donasi/${id}/temporary-create`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
const errorData = await response.json().catch(() => null);
console.error(
"Failed to get donasi cerita penggalang",
response.statusText,
errorData
);
throw new Error(
errorData?.message || "Failed to get donasi cerita penggalang"
);
}
// Return the JSON response
const data = await response.json();
console.log("data fetch>>", data);
return data;
} catch (error) {
console.error("Error get donasi cerita penggalang", error);