From a6389174d7a4bfc2356b524698d7adffcd49ca28 Mon Sep 17 00:00:00 2001 From: Bagasbanuna02 Date: Fri, 3 Oct 2025 14:09:31 +0800 Subject: [PATCH] git add . && git commit -m --- .../investment/[id]/(news)/[news]/index.tsx | 86 ++++++++++++++---- .../investment/[id]/(news)/add-news.tsx | 88 +++++++++++++++++-- .../investment/[id]/(news)/list-of-news.tsx | 76 ++++++++++++---- .../investment/[id]/(news)/recap-of-news.tsx | 64 +++++++++++--- components/_ShareComponent/PdfViewer.tsx | 21 +++-- screens/Invesment/ButtonInvestasiSection.tsx | 3 +- service/api-client/api-investment.ts | 52 +++++++++-- 7 files changed, 323 insertions(+), 67 deletions(-) diff --git a/app/(application)/(user)/investment/[id]/(news)/[news]/index.tsx b/app/(application)/(user)/investment/[id]/(news)/[news]/index.tsx index 9656df9..50d6920 100644 --- a/app/(application)/(user)/investment/[id]/(news)/[news]/index.tsx +++ b/app/(application)/(user)/investment/[id]/(news)/[news]/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { AlertDefaultSystem, BackButton, @@ -8,37 +9,71 @@ import { MenuDrawerDynamicGrid, StackCustom, TextCustom, - ViewWrapper + ViewWrapper, } from "@/components"; import { IconTrash } from "@/components/_Icon/IconTrash"; -import { router, Stack, useLocalSearchParams } from "expo-router"; -import { useState } from "react"; +import { useAuth } from "@/hooks/use-auth"; +import { + apiInvestmentDeleteNews, + apiInvestmentGetNews, +} from "@/service/api-client/api-investment"; +import { + router, + Stack, + useFocusEffect, + useLocalSearchParams, +} from "expo-router"; +import { useCallback, useState } from "react"; +import Toast from "react-native-toast-message"; export default function InvestmentNews() { - const { id, news } = useLocalSearchParams(); + const { user } = useAuth(); + const { news } = useLocalSearchParams(); + const id = news as string; const [openDrawer, setOpenDrawer] = useState(false); + const [data, setData] = useState(null); + + useFocusEffect( + useCallback(() => { + onLoadData(); + }, [id]) + ); + + const onLoadData = async () => { + try { + const response = await apiInvestmentGetNews({ + id: id, + category: "one-news", + }); + + setData(response.data); + } catch (error) { + console.log("[ERROR]", error); + } + }; + return ( <> , - headerRight: () => setOpenDrawer(true)} />, + headerRight: () => + user?.id === data?.authorId && ( + setOpenDrawer(true)} /> + ), }} /> - + {data && data?.imageId && ( + + )} - Judul Berita {news} Terbaru - - - Lorem ipsum dolor sit amet consectetur adipisicing elit. Laborum - fuga mollitia laboriosam voluptatibus quos molestias, illo fugiat - esse repellat, ad officia earum numquam? Aliquid corrupti quam - tempora cum harum est! + {(data && data?.title) || "-"} + {(data && data?.deskripsi) || "-"} @@ -52,7 +87,7 @@ export default function InvestmentNews() { data={[ { label: "Hapus Berita", - path: `/investment/${id}/add-news`, + path: ``, icon: , color: "red", }, @@ -63,9 +98,26 @@ export default function InvestmentNews() { message: "Apakah Anda yakin ingin menghapus berita ini?", textLeft: "Batal", textRight: "Hapus", - onPressRight: () => { - router.back(); - setOpenDrawer(false); + onPressRight: async () => { + try { + const response = await apiInvestmentDeleteNews({ id }); + + if (response.success) { + Toast.show({ + type: "success", + text1: "Berita berhasil dihapus", + }); + router.back(); + setOpenDrawer(false); + } else { + Toast.show({ + type: "error", + text1: "Gagal menghapus berita", + }); + } + } catch (error) { + console.log("[ERROR]", error); + } }, }); }} diff --git a/app/(application)/(user)/investment/[id]/(news)/add-news.tsx b/app/(application)/(user)/investment/[id]/(news)/add-news.tsx index 1046f89..a8ed1d9 100644 --- a/app/(application)/(user)/investment/[id]/(news)/add-news.tsx +++ b/app/(application)/(user)/investment/[id]/(news)/add-news.tsx @@ -9,17 +9,89 @@ import { TextInputCustom, ViewWrapper, } from "@/components"; -import { router } from "expo-router"; +import DIRECTORY_ID from "@/constants/directory-id"; +import { apiInvestmentCreateNews } from "@/service/api-client/api-investment"; +import { uploadFileService } from "@/service/upload-service"; +import pickFile, { IFileData } from "@/utils/pickFile"; +import { router, useLocalSearchParams } from "expo-router"; +import { useState } from "react"; +import Toast from "react-native-toast-message"; export default function InvestmentAddNews() { + const { id } = useLocalSearchParams(); + const [image, setImage] = useState(null); + const [data, setData] = useState({ + title: "", + deskripsi: "", + }); + const [isLoading, setIsLoading] = useState(false); + + const handlerSubmit = async () => { + let imageId = ""; + + if (!data.title || !data.deskripsi) { + Toast.show({ + type: "error", + text1: "Judul dan deskripsi harus diisi", + }); + return; + } + + try { + setIsLoading(true); + if (image) { + const uploadImage = await uploadFileService({ + dirId: DIRECTORY_ID.investasi_berita, + imageUri: image.uri, + }); + + imageId = uploadImage.data.id; + } + + const newData = { + id: id as string, + title: data.title, + deskripsi: data.deskripsi, + imageId: imageId, + }; + + const response = await apiInvestmentCreateNews({ + id: id as string, + data: newData, + }); + + if (response.success) { + Toast.show({ + type: "success", + text1: "Berita berhasil disimpan", + }); + router.back(); + } else { + Toast.show({ + type: "error", + text1: "Gagal menyimpan berita", + }); + } + } catch (error) { + console.log("[ERROR]", error); + } finally { + setIsLoading(false); + } + }; + return ( - + { - router.push("/(application)/(image)/take-picture/123"); + pickFile({ + allowedType: "image", + setImageUri(file) { + setImage(file); + }, + }); }} icon="upload" > @@ -30,6 +102,8 @@ export default function InvestmentAddNews() { label="Judul Berita" placeholder="Masukan judul berita" required + value={data.title} + onChangeText={(value) => setData({ ...data, title: value })} /> setData({ ...data, deskripsi: value })} /> - { - router.back(); - }} - > + Simpan diff --git a/app/(application)/(user)/investment/[id]/(news)/list-of-news.tsx b/app/(application)/(user)/investment/[id]/(news)/list-of-news.tsx index aa0ddb8..8dd03cc 100644 --- a/app/(application)/(user)/investment/[id]/(news)/list-of-news.tsx +++ b/app/(application)/(user)/investment/[id]/(news)/list-of-news.tsx @@ -1,18 +1,51 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { - BackButton, - BaseBox, - DrawerCustom, - MenuDrawerDynamicGrid, - TextCustom, - ViewWrapper + BackButton, + BaseBox, + DrawerCustom, + LoaderCustom, + MenuDrawerDynamicGrid, + TextCustom, + ViewWrapper, } from "@/components"; import { IconPlus } from "@/components/_Icon"; -import { router, Stack, useLocalSearchParams } from "expo-router"; -import { useState } from "react"; +import { apiInvestmentGetNews } from "@/service/api-client/api-investment"; +import { + router, + Stack, + useFocusEffect, + useLocalSearchParams, +} from "expo-router"; +import _ from "lodash"; +import { useCallback, useState } from "react"; export default function InvestmentListOfNews() { const { id } = useLocalSearchParams(); const [openDrawer, setOpenDrawer] = useState(false); + const [list, setList] = useState(null); + const [loadList, setLoadList] = useState(false); + + useFocusEffect( + useCallback(() => { + onLoadList(); + }, [id]) + ); + + const onLoadList = async () => { + try { + setLoadList(true); + const response = await apiInvestmentGetNews({ + id: id as string, + category: "all-news", + }); + + setList(response.data); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoadList(false); + } + }; return ( <> setOpenDrawer(true)} />, }} /> + - {Array.from({ length: 15 }).map((_, index) => ( - - Berita Terbaru {index + 1} - - ))} + {loadList ? ( + + ) : _.isEmpty(list) ? ( + + Tidak ada data + + ) : ( + list?.map((item: any, index: number) => ( + + {item.title} + + )) + )} (null); + const [loadList, setLoadList] = useState(false); + + useFocusEffect( + useCallback(() => { + onLoadList(); + }, [id]) + ); + + const onLoadList = async () => { + try { + setLoadList(true); + const response = await apiInvestmentGetNews({ + id: id as string, + category: "all-news", + }); + + setList(response.data); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoadList(false); + } + }; + return ( <> - {Array.from({ length: 15 }).map((_, index) => ( - - Berita Terbaru {index + 1} - - ))} + {loadList ? ( + + ) : _.isEmpty(list) ? ( + + Tidak ada data + + ) : ( + list?.map((item: any, index: number) => ( + + {item.title} + + )) + )} = ({ uri }) => { const [loading, setLoading] = useState(true); + // ✅ Bungkus dengan Google Docs Viewer + const viewerUrl = `https://docs.google.com/gview?embedded=true&url=${encodeURIComponent( + uri + )}`; + + const selectedDivice = Platform.OS === "ios" ? uri : viewerUrl; + return ( <> {loading && ( @@ -18,7 +25,9 @@ const PdfViewer: React.FC = ({ uri }) => { )} setLoading(false)} onError={(syntheticEvent) => { @@ -26,10 +35,10 @@ const PdfViewer: React.FC = ({ uri }) => { console.warn("WebView error:", nativeEvent); setLoading(false); }} - scalesPageToFit={true} - javaScriptEnabled={true} - domStorageEnabled={true} - originWhitelist={["*"]} + // scalesPageToFit={true} + // javaScriptEnabled={true} + // domStorageEnabled={true} + // originWhitelist={["*"]} /> ); diff --git a/screens/Invesment/ButtonInvestasiSection.tsx b/screens/Invesment/ButtonInvestasiSection.tsx index 3b42b5d..355fb5d 100644 --- a/screens/Invesment/ButtonInvestasiSection.tsx +++ b/screens/Invesment/ButtonInvestasiSection.tsx @@ -8,11 +8,10 @@ export default function Investment_ButtonInvestasiSection({ id: string; isMine: boolean; }) { - console.log("[IS MINE]", isMine); return ( <> {isMine ? ( - Investasi Ini Milik Anda + Investasi ini milik Anda ) : ( { diff --git a/service/api-client/api-investment.ts b/service/api-client/api-investment.ts index 661a7da..edd856d 100644 --- a/service/api-client/api-investment.ts +++ b/service/api-client/api-investment.ts @@ -145,12 +145,9 @@ export async function apiInvestmentCreateInvoice({ data: any; }) { try { - const response = await apiConfig.post( - `/mobile/investment/${id}/invoice`, - { - data: data, - } - ); + const response = await apiConfig.post(`/mobile/investment/${id}/invoice`, { + data: data, + }); return response.data; } catch (error) { throw error; @@ -201,3 +198,46 @@ export async function apiInvestmentUpdateInvoice({ throw error; } } + +export async function apiInvestmentCreateNews({ + id, + data, +}: { + id: string; + data: any; +}) { + try { + const response = await apiConfig.post(`/mobile/investment/${id}/news`, { + data: data, + }); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiInvestmentGetNews({ + id, + category, +}: { + id: string; + category: "all-news" | "one-news"; +}) { + try { + const response = await apiConfig.get( + `/mobile/investment/${id}/news?category=${category}` + ); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiInvestmentDeleteNews({ id }: { id: string }) { + try { + const response = await apiConfig.delete(`/mobile/investment/${id}/news`); + return response.data; + } catch (error) { + throw error; + } +}