From ba878d4d08aa73cad05245dfdc5a5f5c3bce2591 Mon Sep 17 00:00:00 2001 From: Bagasbanuna02 Date: Mon, 6 Oct 2025 16:00:20 +0800 Subject: [PATCH] Donasi Fix: tampilan status dan detail status sudah terintegrasi API - create dan buntton status sudah terintegrasi ### No Issue --- app/(application)/(user)/_layout.tsx | 2 +- .../(user)/donation/(tabs)/status.tsx | 60 ++++++-- .../(user)/donation/[id]/[status]/detail.tsx | 47 +++++- .../(user)/donation/[id]/detail-story.tsx | 39 +++-- .../(user)/donation/create-story.tsx | 77 +++++++--- app/(application)/(user)/donation/create.tsx | 8 +- screens/Donation/BoxStatus.tsx | 23 +-- screens/Donation/ButtonStatusSection.tsx | 136 +++++++++++++++--- screens/Donation/ComponentBoxDetailData.tsx | 16 ++- screens/Donation/ComponentStoryFunrising.tsx | 9 +- service/api-client/api-donation.ts | 74 +++++++++- 11 files changed, 395 insertions(+), 96 deletions(-) diff --git a/app/(application)/(user)/_layout.tsx b/app/(application)/(user)/_layout.tsx index d55655f..8019694 100644 --- a/app/(application)/(user)/_layout.tsx +++ b/app/(application)/(user)/_layout.tsx @@ -186,7 +186,7 @@ export default function UserLayout() { name="crowdfunding/index" options={{ title: "Crowdfunding", - headerLeft: () => , + headerLeft: () => , }} /> diff --git a/app/(application)/(user)/donation/(tabs)/status.tsx b/app/(application)/(user)/donation/(tabs)/status.tsx index 0bd0bfd..a10575d 100644 --- a/app/(application)/(user)/donation/(tabs)/status.tsx +++ b/app/(application)/(user)/donation/(tabs)/status.tsx @@ -1,12 +1,48 @@ -import { ScrollableCustom, ViewWrapper } from "@/components"; +/* eslint-disable react-hooks/exhaustive-deps */ +import { + LoaderCustom, + ScrollableCustom, + TextCustom, + ViewWrapper, +} from "@/components"; +import { useAuth } from "@/hooks/use-auth"; import { dummyMasterStatus } from "@/lib/dummy-data/_master/status"; import Donasi_BoxStatus from "@/screens/Donation/BoxStatus"; -import { useState } from "react"; +import { apiDonationGetByStatus } from "@/service/api-client/api-donation"; +import { useFocusEffect } from "expo-router"; +import _ from "lodash"; +import { useCallback, useState } from "react"; export default function DonationStatus() { + const { user } = useAuth(); const [activeCategory, setActiveCategory] = useState( "publish" ); + const [listData, setListData] = useState(null); + const [loadList, setLoadList] = useState(false); + + useFocusEffect( + useCallback(() => { + onLoadList(); + }, [activeCategory]) + ); + + const onLoadList = async () => { + try { + setLoadList(true); + const response = await apiDonationGetByStatus({ + authorId: user?.id as string, + status: activeCategory as string, + }); + + setListData(response.data); + } catch (error) { + console.log("[ERROR]", error); + setListData(null); + } finally { + setLoadList(false); + } + }; const handlePress = (item: any) => { setActiveCategory(item.value); @@ -26,13 +62,19 @@ export default function DonationStatus() { ); return ( - {Array.from({ length: 10 }).map((_, index) => ( - - ))} + {loadList ? ( + + ) : _.isEmpty(listData) ? ( + Tidak ada data {activeCategory} + ) : ( + listData?.map((item: any, index: number) => ( + + )) + )} ); } diff --git a/app/(application)/(user)/donation/[id]/[status]/detail.tsx b/app/(application)/(user)/donation/[id]/[status]/detail.tsx index f483fe7..ca9a775 100644 --- a/app/(application)/(user)/donation/[id]/[status]/detail.tsx +++ b/app/(application)/(user)/donation/[id]/[status]/detail.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { BackButton, DotButton, @@ -14,16 +15,43 @@ import Donation_ButtonStatusSection from "@/screens/Donation/ButtonStatusSection import Donation_ComponentBoxDetailData from "@/screens/Donation/ComponentBoxDetailData"; import Donation_ComponentStoryFunrising from "@/screens/Donation/ComponentStoryFunrising"; import Donation_ProgressSection from "@/screens/Donation/ProgressSection"; +import { apiDonationGetOne } from "@/service/api-client/api-donation"; import { FontAwesome6 } from "@expo/vector-icons"; -import { router, Stack, useLocalSearchParams } from "expo-router"; +import { + router, + Stack, + useFocusEffect, + useLocalSearchParams, +} from "expo-router"; import _ from "lodash"; -import { useState } from "react"; +import { useCallback, useState } from "react"; export default function DonasiDetailStatus() { const { id, status } = useLocalSearchParams(); const [openDrawer, setOpenDrawer] = useState(false); const [openDrawerPublish, setOpenDrawerPublish] = useState(false); + const [data, setData] = useState(); + + useFocusEffect( + useCallback(() => { + onLoadData(); + }, [id]) + ); + + const onLoadData = async () => { + try { + const response = await apiDonationGetOne({ + id: id as string, + category: "permanent", + }); + + setData(response.data); + } catch (error) { + console.log("[ERROR]", error); + } + }; + const handlePress = (item: IMenuDrawerItem) => { console.log("PATH ", item.path); router.navigate(item.path as any); @@ -46,13 +74,22 @@ export default function DonasiDetailStatus() { /> + status === "publish" && ( + + ) } /> - + - + diff --git a/app/(application)/(user)/donation/[id]/detail-story.tsx b/app/(application)/(user)/donation/[id]/detail-story.tsx index 93bf712..051a15c 100644 --- a/app/(application)/(user)/donation/[id]/detail-story.tsx +++ b/app/(application)/(user)/donation/[id]/detail-story.tsx @@ -1,27 +1,42 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { DummyLandscapeImage, StackCustom, TextCustom, ViewWrapper, } from "@/components"; -import { useLocalSearchParams } from "expo-router"; +import { apiDonationGetOne } from "@/service/api-client/api-donation"; +import { useFocusEffect, useLocalSearchParams } from "expo-router"; +import { useCallback, useState } from "react"; export default function DonationDetailStory() { const { id } = useLocalSearchParams(); + const [data, setData] = useState(); + + useFocusEffect( + useCallback(() => { + onLoadData(); + }, [id]) + ); + + const onLoadData = async () => { + try { + const response = await apiDonationGetOne({ + id: id as string, + category: "permanent", + }); + + setData(response.data.CeritaDonasi); + } catch (error) { + console.log("[ERROR]", error); + } + }; return ( - - Lorem {id} ipsum dolor, sit amet consectetur adipisicing elit. Fuga - quasi nam nesciunt nisi corporis alias modi, pariatur sit totam rem - fugiat ex similique magni, aliquam maiores officiis iure at adipisci. - - - - Lorem {id} ipsum dolor, sit amet consectetur adipisicing elit. Fuga - quasi nam nesciunt nisi corporis alias modi, pariatur sit totam rem - fugiat ex similique magni, aliquam maiores officiis iure at adipisci. - + {data?.pembukaan || "-"} + + {data?.cerita || "-"} ); diff --git a/app/(application)/(user)/donation/create-story.tsx b/app/(application)/(user)/donation/create-story.tsx index 432b32d..35c3148 100644 --- a/app/(application)/(user)/donation/create-story.tsx +++ b/app/(application)/(user)/donation/create-story.tsx @@ -12,8 +12,12 @@ import { } from "@/components"; import DIRECTORY_ID from "@/constants/directory-id"; import { useAuth } from "@/hooks/use-auth"; -import { apiDonationGetOne } from "@/service/api-client/api-donation"; +import { + apiDonationCreate, + apiDonationGetOne, +} from "@/service/api-client/api-donation"; import { uploadFileService } from "@/service/upload-service"; +import pickFile from "@/utils/pickFile"; import { router, useLocalSearchParams } from "expo-router"; import _ from "lodash"; import { useEffect, useState } from "react"; @@ -22,7 +26,6 @@ import Toast from "react-native-toast-message"; export default function DonationCreateStory() { const { user } = useAuth(); const { id } = useLocalSearchParams(); - console.log("[ID]", id); const [temporary, setTemporary] = useState(); const [data, setData] = useState({ pembukaan: "", @@ -30,7 +33,8 @@ export default function DonationCreateStory() { namaBank: "", rekening: "", }); - const [imageDonasi, setImageDonasi] = useState(null); + const [imageStory, setImageStory] = useState(null); + const [isLoading, setLoading] = useState(false); useEffect(() => { onLoadData(); @@ -38,11 +42,12 @@ export default function DonationCreateStory() { const onLoadData = async () => { try { - // const response = await apiDonationGetOne({ - // id: id as string, - // category: "temporary", - // }); - // console.log("[RES GET ONE]", JSON.stringify(response, null, 2)); + const response = await apiDonationGetOne({ + id: id as string, + category: "temporary", + }); + + setTemporary(response.data); } catch (error) { console.log("[ERROR]", error); } @@ -58,28 +63,51 @@ export default function DonationCreateStory() { } try { + setLoading(true); const responseUploadImageDonasi = await uploadFileService({ - imageUri: imageDonasi, + imageUri: imageStory, dirId: DIRECTORY_ID.donasi_cerita_image, }); const newData = { - id: temporary?.id, + // Data Donasi + temporaryId: temporary?.id, + authorId: user?.id, title: temporary?.title, target: temporary?.target, donasiMaster_KategoriId: temporary?.donasiMaster_KategoriId, donasiMaster_DurasiId: temporary?.donasiMaster_DurasiId, - authorId: user?.id, + imageId: temporary?.imageId, + // Data Bank namaBank: data.namaBank, rekening: data.rekening, - imageId: temporary?.imageId, - CeritaDonasi: { - pembukaan: data.pembukaan, - cerita: data.cerita, - }, + // Data Cerita + imageCeritaId: responseUploadImageDonasi.data.id, + pembukaan: data.pembukaan, + cerita: data.cerita, }; + + const response = await apiDonationCreate({ + data: newData, + category: "permanent", + }); + + if (!response.success) { + Toast.show({ + type: "error", + text1: "Gagal membuat donasi", + }); + } + + Toast.show({ + type: "success", + text1: "Donasi berhasil disimpan", + }); + router.replace("/donation/status"); } catch (error) { console.log("[ERROR]", error); + } finally { + setLoading(false); } }; @@ -106,10 +134,15 @@ export default function DonationCreateStory() { onChangeText={(value) => setData({ ...data, cerita: value })} /> - + { - router.push("/(application)/(image)/take-picture/123"); + pickFile({ + allowedType: "image", + setImageUri: ({ uri }) => { + setImageStory(uri); + }, + }); }} icon="upload" > @@ -122,17 +155,23 @@ export default function DonationCreateStory() { label="Nama Bank" placeholder="Masukkan nama bank" required + value={data.namaBank} + onChangeText={(value) => setData({ ...data, namaBank: value })} /> setData({ ...data, rekening: value })} /> { - router.replace(`/donation/(tabs)/status`); + handlerSubmit(); }} > Simpan diff --git a/app/(application)/(user)/donation/create.tsx b/app/(application)/(user)/donation/create.tsx index 0a06436..860de52 100644 --- a/app/(application)/(user)/donation/create.tsx +++ b/app/(application)/(user)/donation/create.tsx @@ -11,8 +11,6 @@ import { ViewWrapper, } from "@/components"; import DIRECTORY_ID from "@/constants/directory-id"; -import { dummyDonasiDurasi } from "@/lib/dummy-data/donasi/durasi"; -import { dummyDonasiKategori } from "@/lib/dummy-data/donasi/kategori"; import { apiDonationCreate } from "@/service/api-client/api-donation"; import { apiMasterDonation } from "@/service/api-client/api-master"; import { uploadFileService } from "@/service/upload-service"; @@ -110,8 +108,6 @@ export default function DonationCreate() { category: "temporary", }); - console.log("[RESPONSE]", JSON.stringify(response, null, 2)); - if (!response.success) { Toast.show({ type: "error", @@ -210,8 +206,8 @@ export default function DonationCreate() { { - // handlerSubmit(); - router.push(`/donation/create-story?id=${"dasdsadsa"}`); + handlerSubmit(); + // router.push(`/donation/create-story?id=${"dasdsadsa"}`); }} > Selanjutnya diff --git a/screens/Donation/BoxStatus.tsx b/screens/Donation/BoxStatus.tsx index 74e0ccb..071549a 100644 --- a/screens/Donation/BoxStatus.tsx +++ b/screens/Donation/BoxStatus.tsx @@ -5,13 +5,14 @@ import { StackCustom, TextCustom, } from "@/components"; +import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay"; import { View } from "react-native"; export default function Donasi_BoxStatus({ - id, + data, status, }: { - id: string; + data: any; status: string; }) { return ( @@ -19,26 +20,30 @@ export default function Donasi_BoxStatus({ - + - - Judul Donasi: {status} Lorem ipsum dolor sit amet consectetur - adipisicing elit. - + {data.title || "-"} Target Dana - Rp. 7.500.000 + Rp. + {data && data?.target + ? formatCurrencyDisplay(data.target) + : "-"} diff --git a/screens/Donation/ButtonStatusSection.tsx b/screens/Donation/ButtonStatusSection.tsx index f8d40b2..db3fdf7 100644 --- a/screens/Donation/ButtonStatusSection.tsx +++ b/screens/Donation/ButtonStatusSection.tsx @@ -1,20 +1,54 @@ import { AlertDefaultSystem, ButtonCustom, Grid } from "@/components"; +import { + apiDonationDelete, + apiDonationUpdateStatus, +} from "@/service/api-client/api-donation"; import { router } from "expo-router"; +import { useState } from "react"; +import Toast from "react-native-toast-message"; export default function Donation_ButtonStatusSection({ + id, status, }: { + id: string; status: string; }) { - const handleBatalkanReview = () => { + const [isLoading, setLoading] = useState(false); + const [isLoadingDelete, setLoadingDelete] = useState(false); + const handleBatalkanReview = async () => { AlertDefaultSystem({ title: "Batalkan Review", message: "Apakah Anda yakin ingin batalkan review ini?", textLeft: "Batal", textRight: "Ya", - onPressRight: () => { - console.log("Hapus"); - router.back(); + onPressRight: async () => { + try { + setLoading(true); + const response = await apiDonationUpdateStatus({ + id: id, + status: "draft", + }); + + if (!response.success) { + Toast.show({ + type: "info", + text1: response.message, + }); + return; + } + + Toast.show({ + type: "success", + text1: response.message, + }); + + router.back(); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoading(false); + } }, }); }; @@ -25,9 +59,33 @@ export default function Donation_ButtonStatusSection({ message: "Apakah Anda yakin ingin ajukan review ini?", textLeft: "Batal", textRight: "Ya", - onPressRight: () => { - console.log("Hapus"); - router.back(); + onPressRight: async () => { + try { + setLoading(true); + const response = await apiDonationUpdateStatus({ + id: id, + status: "review", + }); + + if (!response.success) { + Toast.show({ + type: "info", + text1: response.message, + }); + return; + } + + Toast.show({ + type: "success", + text1: response.message, + }); + + router.back(); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoading(false); + } }, }); }; @@ -38,9 +96,33 @@ export default function Donation_ButtonStatusSection({ message: "Apakah Anda yakin ingin edit kembali ini?", textLeft: "Batal", textRight: "Ya", - onPressRight: () => { - console.log("Hapus"); - router.back(); + onPressRight: async () => { + try { + setLoading(true); + const response = await apiDonationUpdateStatus({ + id: id, + status: "draft", + }); + + if (!response.success) { + Toast.show({ + type: "info", + text1: response.message, + }); + return; + } + + Toast.show({ + type: "success", + text1: response.message, + }); + + router.back(); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoading(false); + } }, }); }; @@ -51,9 +133,30 @@ export default function Donation_ButtonStatusSection({ message: "Apakah Anda yakin ingin menghapus data ini?", textLeft: "Batal", textRight: "Hapus", - onPressRight: () => { - console.log("Hapus"); - router.back(); + onPressRight: async () => { + try { + setLoadingDelete(true); + const response = await apiDonationDelete({ id: id }); + + if (!response.success) { + Toast.show({ + type: "info", + text1: response.message, + }); + return; + } + + Toast.show({ + type: "success", + text1: response.message, + }); + + router.back(); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoadingDelete(false); + } }, }); }; @@ -62,6 +165,7 @@ export default function Donation_ButtonStatusSection({ return ( <> + Batalkan Review ); @@ -88,7 +192,7 @@ export default function Donation_ButtonStatusSection({ <> - + Ajukan Review @@ -104,7 +208,7 @@ export default function Donation_ButtonStatusSection({ <> - + Edit Kembali diff --git a/screens/Donation/ComponentBoxDetailData.tsx b/screens/Donation/ComponentBoxDetailData.tsx index de28e70..f4026e7 100644 --- a/screens/Donation/ComponentBoxDetailData.tsx +++ b/screens/Donation/ComponentBoxDetailData.tsx @@ -5,25 +5,29 @@ import { TextCustom, Grid, } from "@/components"; +import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay"; import React from "react"; import { View } from "react-native"; export default function Donation_ComponentBoxDetailData({ bottomSection, + data, }: { bottomSection?: React.ReactNode; + data: any; }) { return ( <> - + - Judul Donasi: Lorem, ipsum dolor sit amet consectetur adipisicing - elit. + {data?.title || "-"} + + + Durasi: {data?.DonasiMaster_Durasi?.name || "-"} - Durasi: 30 hari @@ -31,7 +35,7 @@ export default function Donation_ComponentBoxDetailData({ Target Dana - Rp. 7.500.000 + Rp. {formatCurrencyDisplay(data?.target) || "-"} @@ -39,7 +43,7 @@ export default function Donation_ComponentBoxDetailData({ Kategori - Kegiatan Sosial + {data?.DonasiMaster_Ketegori?.name || "-"} diff --git a/screens/Donation/ComponentStoryFunrising.tsx b/screens/Donation/ComponentStoryFunrising.tsx index 6eb9856..11d154e 100644 --- a/screens/Donation/ComponentStoryFunrising.tsx +++ b/screens/Donation/ComponentStoryFunrising.tsx @@ -5,8 +5,10 @@ import { Ionicons } from "@expo/vector-icons"; export default function Donation_ComponentStoryFunrising({ id, + dataStory, }: { id: string; + dataStory: any; }) { return ( <> @@ -29,12 +31,7 @@ export default function Donation_ComponentStoryFunrising({ /> - - Lorem ipsum dolor sit amet consectetur adipisicing elit. Totam, - iusto porro quae optio accusantium amet minima deleniti temporibus - cum voluptatem vel veniam doloribus blanditiis sapiente deserunt - distinctio eaque aliquid laboriosam? - + {dataStory?.pembukaan || "-"} diff --git a/service/api-client/api-donation.ts b/service/api-client/api-donation.ts index 15a33ec..b6777a1 100644 --- a/service/api-client/api-donation.ts +++ b/service/api-client/api-donation.ts @@ -1,22 +1,82 @@ import { apiConfig } from "../api-config"; -export async function apiDonationCreate({ data , category}: { data: any , category: "temporary" | "permanent"}) { +export async function apiDonationCreate({ + data, + category, +}: { + data: any; + category: "temporary" | "permanent"; +}) { try { - const response = await apiConfig.post(`/mobile/donation?category=${category}`, { - data: data, - }); + const response = await apiConfig.post( + `/mobile/donation?category=${category}`, + { + data: data, + } + ); return response.data; } catch (error) { throw error; } } -export async function apiDonationGetOne({ id, category }: { id: string , category: "temporary" | "permanent"}) { +export async function apiDonationGetOne({ + id, + category, +}: { + id: string; + category: "temporary" | "permanent"; +}) { try { - const response = await apiConfig.get(`/mobile/donation/${id}?category=${category}`); + const response = await apiConfig.get( + `/mobile/donation/${id}?category=${category}` + ); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiDonationGetByStatus({ + authorId, + status, +}: { + authorId: string; + status: string; +}) { + const authorQuery = `/${authorId}`; + const statusQuery = `/${status}`; + + try { + const response = await apiConfig.get( + `/mobile/donation${authorQuery}${statusQuery}` + ); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiDonationUpdateStatus({ + id, + status, +}: { + id: string; + status: "draft" | "review" | "publish" | "reject"; +}) { + try { + const response = await apiConfig.put(`/mobile/donation/${id}/${status}`); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiDonationDelete({ id }: { id: string }) { + try { + const response = await apiConfig.delete(`/mobile/donation/${id}`); return response.data; } catch (error) { throw error; } } - \ No newline at end of file