From f23cfe1107231d777b360dc03b123c2675929328 Mon Sep 17 00:00:00 2001 From: Bagasbanuna02 Date: Thu, 30 Oct 2025 15:13:33 +0800 Subject: [PATCH] Integrasi API: Investment & Admin Investment Add: - components/_ShareComponent/NoDataText.tsx - service/api-admin/api-admin-investment.ts Fix: - app/(application)/(user)/investment/(tabs)/index.tsx - app/(application)/admin/investment/[id]/[status]/index.tsx - app/(application)/admin/investment/[id]/reject-input.tsx - app/(application)/admin/investment/[status]/status.tsx - app/(application)/admin/investment/index.tsx - screens/Invesment/DetailDataPublishSection.tsx ### No Issue --- .../(user)/investment/(tabs)/index.tsx | 3 +- .../admin/investment/[id]/[status]/index.tsx | 185 +++++++++++++----- .../admin/investment/[id]/reject-input.tsx | 87 +++++++- .../admin/investment/[status]/status.tsx | 129 ++++++++---- app/(application)/admin/investment/index.tsx | 61 ++++-- components/_ShareComponent/NoDataText.tsx | 9 + .../Invesment/DetailDataPublishSection.tsx | 4 + service/api-admin/api-admin-investment.ts | 54 +++++ 8 files changed, 413 insertions(+), 119 deletions(-) create mode 100644 components/_ShareComponent/NoDataText.tsx create mode 100644 service/api-admin/api-admin-investment.ts diff --git a/app/(application)/(user)/investment/(tabs)/index.tsx b/app/(application)/(user)/investment/(tabs)/index.tsx index e293ce9..2892c93 100644 --- a/app/(application)/(user)/investment/(tabs)/index.tsx +++ b/app/(application)/(user)/investment/(tabs)/index.tsx @@ -8,6 +8,7 @@ import { TextCustom, ViewWrapper, } from "@/components"; +import NoDataText from "@/components/_ShareComponent/NoDataText"; import API_STRORAGE from "@/constants/base-url-api-strorage"; import DUMMY_IMAGE from "@/constants/dummy-image-value"; import { apiInvestmentGetAll } from "@/service/api-client/api-investment"; @@ -52,7 +53,7 @@ export default function InvestmentBursa() { {loadingList ? ( ) : _.isEmpty(list) ? ( - Belum ada data + ) : ( list?.map((item: any, index: number) => ( { - if (status === "publish") { - return MainColor.green; - } else if (status === "review") { - return MainColor.orange; - } else if (status === "reject") { - return MainColor.red; - } else { - return MainColor.placeholder; + const [data, setData] = React.useState(null); + const [isLoading, setLoading] = React.useState(false); + + useFocusEffect( + React.useCallback(() => { + onLoadData(); + }, [id]) + ); + + const onLoadData = async () => { + try { + const response = await apiAdminInvestmentDetailById({ id: id as string }); + console.log("[DATA]", JSON.stringify(response, null, 2)); + if (response.success) { + setData(response.data); + } + } catch (error) { + console.log(error); } }; const listData = [ { label: "Username", - value: `Bagas Banuna ${id}`, + value: (data && data?.author?.username) || "-", }, { label: "Judul", - value: `Donasi Lorem ipsum dolor sit amet, consectetur adipisicing elit.`, + value: (data && data?.title) || "-", }, { label: "Status", - value: ( - - {_.startCase(status as string)} - - ), + value: + data && data?.MasterStatusInvestasi?.name ? ( + + {_.startCase(data?.MasterStatusInvestasi?.name as string)} + + ) : ( + "-" + ), }, { label: "Dana Dibutuhkan", - value: "Rp 10.000.000", + value: `Rp. ${ + (data && data?.targetDana && formatCurrencyDisplay(data?.targetDana)) || + "-" + }`, }, { label: "Harga Perlembar", - value: "Rp 2500", + value: `Rp. ${ + (data && + data?.hargaLembar && + formatCurrencyDisplay(data?.hargaLembar)) || + "-" + }`, }, { label: "Total Lembar", - value: "2490 lembar", + value: + (data && + data?.totalLembar && + formatCurrencyDisplay(data?.totalLembar)) || + "-", }, { label: "ROI", - value: "4 %", + value: `${(data && data?.roi && data?.roi) || 0} %`, }, { label: "Pembagian Deviden", - value: "3 bulan", + value: (data && data?.MasterPembagianDeviden?.name) + " bulan" || "-", }, { label: "Jadwal Pembagian", - value: "Selamanya", + value: (data && data?.MasterPeriodeDeviden?.name) || "-", }, { label: "Pencarian Investor", - value: "30 Hari", + value: (data && data?.MasterPencarianInvestor?.name) + " hari" || "-", }, ]; + const handlerSubmitPublish = async () => { + try { + setLoading(true); + const response = await apiAdminInvestasiUpdateByStatus({ + id: id as string, + status: "publish", + data: data, + }); + + console.log("[RESPONSE]", JSON.stringify(response, null, 2)); + if (!response.success) { + Toast.show({ + type: "error", + text1: "Gagal mempublikasikan data", + }); + return; + } + + Toast.show({ + type: "success", + text1: "Berhasil mempublikasikan data", + }); + router.replace(`/admin/investment/publish/status`); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoading(false); + } + }; + const rightComponent = ( } @@ -126,7 +193,7 @@ export default function AdminInvestmentDetail() { - + {listData.map((item, i) => ( } onPress={() => { - router.push(`/(application)/(file)/${id}`); + router.push( + `/(application)/(file)/${data?.prospektusFileId}` + ); }} > Preview @@ -161,46 +230,66 @@ export default function AdminInvestmentDetail() { label={File Dokumen} value={ - {Array.from({ length: 5 }).map((_, i) => ( - - } - onPress={() => { - router.push(`/(application)/(file)/${id}`); - }} - > - Dokumen {i + 1} - - ))} + {_.isEmpty(data?.DokumenInvestasi) ? ( + - + ) : ( + data?.DokumenInvestasi?.map((item: any, index: number) => { + const titleFix = item?.title?.substring(0, 10) || ""; + + return ( + + } + onPress={() => { + router.push( + `/(application)/(file)/${item?.fileId}` + ); + }} + > + + {titleFix}... + + + ); + }) + )} } /> + {data && + data?.catatan && + (status === "review" || status === "reject") && ( + + )} + {status === "review" && ( { AlertDefaultSystem({ title: "Publish", message: "Apakah anda yakin ingin mempublikasikan data ini?", textLeft: "Batal", textRight: "Ya", - onPressLeft: () => { - router.back(); - }, onPressRight: () => { - router.back(); + handlerSubmitPublish(); }, }); }} onReject={() => { - router.push(`/admin/investment/${id}/reject-input`); + router.push( + `/admin/investment/${id}/reject-input?status=${_.lowerCase( + data?.MasterStatusInvestasi?.name + )}` + ); }} /> )} diff --git a/app/(application)/admin/investment/[id]/reject-input.tsx b/app/(application)/admin/investment/[id]/reject-input.tsx index e974139..c7361e0 100644 --- a/app/(application)/admin/investment/[id]/reject-input.tsx +++ b/app/(application)/admin/investment/[id]/reject-input.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { AlertDefaultSystem, BoxButtonOnFooter, @@ -6,15 +7,83 @@ import { } from "@/components"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; -import { router, useLocalSearchParams } from "expo-router"; -import { useState } from "react"; +import { apiAdminInvestasiUpdateByStatus, apiAdminInvestmentDetailById } from "@/service/api-admin/api-admin-investment"; +import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; +import { useCallback, useState } from "react"; +import Toast from "react-native-toast-message"; export default function AdminInvestmentRejectInput() { - const { id } = useLocalSearchParams(); - const [value, setValue] = useState(id as string); + const { id, status } = useLocalSearchParams(); + console.log("[STATUS]", status); + const [value, setValue] = useState(null); + const [isLoading , setLoading] = useState(false) + + useFocusEffect( + useCallback(() => { + onLoadData(); + }, [id]) + ); + + const onLoadData = async () => { + try { + const response = await apiAdminInvestmentDetailById({ id: id as string }); + console.log("[DATA]", JSON.stringify(response, null, 2)); + if (response.success) { + setValue(response.data?.catatan); + } + } catch (error) { + console.log(error); + } + }; + + const handlerSubmit = async () => { + if (!value) { + Toast.show({ + type: "error", + text1: "Harap masukan alasan penolakan", + }); + return; + } + + try { + setLoading(true) + const response = await apiAdminInvestasiUpdateByStatus({ + id: id as string, + status: "reject", + data: value, + }); + + console.log("[RESPONSE]", JSON.stringify(response, null, 2)); + + if (!response.success) { + Toast.show({ + type: "error", + text1: "Gagal melakukan report", + }); + return; + } + + Toast.show({ + type: "success", + text1: "Berhasil melakukan report", + }); + + if (status === "review") { + router.replace(`/admin/investment/reject/status`); + } else { + router.back(); + } + } catch (error) { + console.error(["ERROR"], error); + } finally { + setLoading(false) + } + }; + const buttonSubmit = ( AlertDefaultSystem({ @@ -22,12 +91,8 @@ export default function AdminInvestmentRejectInput() { message: "Apakah anda yakin ingin menolak data ini?", textLeft: "Batal", textRight: "Ya", - onPressLeft: () => { - router.back(); - }, onPressRight: () => { - console.log("value:", value); - router.replace(`/admin/investment/reject/status`); + handlerSubmit(); }, }) } @@ -39,7 +104,9 @@ export default function AdminInvestmentRejectInput() { <> } + headerComponent={ + + } > (null); + const [loadData, setLoadingData] = React.useState(false); + const [search, setSearch] = React.useState(""); + + useFocusEffect( + useCallback(() => { + onLoadData(); + }, [status, search]) + ); + + const onLoadData = async () => { + try { + setLoadingData(true); + const response = await apiAdminInvestment({ + category: status as "publish" | "review" | "reject", + search, + }); + console.log("[LIST DATA]", JSON.stringify(response, null, 2)); + if (response.success) { + setListData(response.data); + } + } catch (error) { + console.log(error); + setListData([]); + } finally { + setLoadingData(false); + } + }; + const rightComponent = ( ); return ( <> - }> + - } - > - - - - - {Array.from({ length: 10 }).map((_, index) => ( - - } - onPress={() => { - router.push(`/admin/investment/${index}/${status}`); - }} - /> - } - value2={Username username} - value3={ - - Lorem ipsum dolor sit amet consectetur adipisicing elit. - Blanditiis asperiores quidem deleniti architecto eaque et - nostrum, ad consequuntur eveniet quisquam quae voluptatum - ducimus! Dolorem nobis modi officia debitis, beatae mollitia. - - } + - ))} + + + + {loadData ? ( + + ) : _.isEmpty(listData) ? ( + + ) : ( + listData?.map((item: any, index: number) => ( + + } + onPress={() => { + router.push(`/admin/investment/${item.id}/${status}`); + }} + /> + } + value2={{item?.author?.username}} + value3={ + + {item?.title} + + } + /> + )) + )} + ); diff --git a/app/(application)/admin/investment/index.tsx b/app/(application)/admin/investment/index.tsx index 553bfe0..dada5f7 100644 --- a/app/(application)/admin/investment/index.tsx +++ b/app/(application)/admin/investment/index.tsx @@ -7,8 +7,51 @@ import { import AdminComp_BoxDashboard from "@/components/_ShareComponent/Admin/BoxDashboard"; import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage"; import { MainColor } from "@/constants/color-palet"; +import { apiAdminInvestment } from "@/service/api-admin/api-admin-investment"; +import { useFocusEffect } from "expo-router"; +import React, { useCallback } from "react"; export default function AdminInvestment() { + const [data, setData] = React.useState(null); + + useFocusEffect( + useCallback(() => { + onLoadData(); + }, []) + ); + + const onLoadData = async () => { + try { + const response = await apiAdminInvestment({ + category: "dashboard", + }); + console.log(JSON.stringify(response, null, 2)); + if (response.success) { + setData(response.data); + } + } catch (error) { + console.log(error); + } + }; + + const listData = [ + { + label: "Publish", + value: (data && data.publish) || 0, + icon: , + }, + { + label: "Review", + value: (data && data.review) || 0, + icon: , + }, + { + label: "Reject", + value: (data && data.reject) || 0, + icon: , + }, + ]; + return ( <> @@ -23,21 +66,3 @@ export default function AdminInvestment() { ); } - -const listData = [ - { - label: "Publish", - value: 3, - icon: , - }, - { - label: "Review", - value: 5, - icon: , - }, - { - label: "Reject", - value: 8, - icon: , - }, -]; diff --git a/components/_ShareComponent/NoDataText.tsx b/components/_ShareComponent/NoDataText.tsx new file mode 100644 index 0000000..d5b8178 --- /dev/null +++ b/components/_ShareComponent/NoDataText.tsx @@ -0,0 +1,9 @@ +import TextCustom from "../Text/TextCustom"; + +export default function NoDataText({ text }: { text?: string }) { + return ( + + {text ? text : "Belum ada data"} + + ); +} diff --git a/screens/Invesment/DetailDataPublishSection.tsx b/screens/Invesment/DetailDataPublishSection.tsx index cef8fe4..d2d2d57 100644 --- a/screens/Invesment/DetailDataPublishSection.tsx +++ b/screens/Invesment/DetailDataPublishSection.tsx @@ -7,6 +7,7 @@ import React from "react"; import Invesment_BoxDetailDataSection from "./BoxDetailDataSection"; import Invesment_BoxProgressSection from "./BoxProgressSection"; import Investment_ButtonStatusSection from "./ButtonStatusSection"; +import ReportBox from "@/components/Box/ReportBox"; export default function Invesment_DetailDataPublishSection({ status, @@ -23,6 +24,9 @@ export default function Invesment_DetailDataPublishSection({ return ( <> + {data && data?.catatan && (status === "draft" || status === "reject") && ( + + )}