From 821a211f581ee41ce7095e34a5784412bf6ab38e Mon Sep 17 00:00:00 2001 From: Bagasbanuna02 Date: Mon, 22 Sep 2025 17:31:40 +0800 Subject: [PATCH] Collaboration Fix: - Integrasi API: Beranda, create, list partisipan, check sudah berpartisipasi ? ### No Issue --- app/(application)/(user)/_layout.tsx | 8 +- .../(user)/collaboration/(tabs)/index.tsx | 53 ++++- .../[id]/create-pacticipants.tsx | 80 +++++++ .../(user)/collaboration/[id]/index.tsx | 93 ++++++-- .../[id]/list-of-participants.tsx | 116 +++++----- .../(user)/collaboration/create.tsx | 202 ++++++++++++++---- .../AvataraAndOtherHeaderComponent.tsx | 3 +- screens/Collaboration/BoxDetailSection.tsx | 43 ++-- screens/Collaboration/BoxPublishSection.tsx | 29 +-- service/api-client/api-collaboration.ts | 71 ++++++ service/api-client/api-master.ts | 11 +- 11 files changed, 554 insertions(+), 155 deletions(-) create mode 100644 app/(application)/(user)/collaboration/[id]/create-pacticipants.tsx create mode 100644 service/api-client/api-collaboration.ts diff --git a/app/(application)/(user)/_layout.tsx b/app/(application)/(user)/_layout.tsx index 0ffb400..fa5a2b0 100644 --- a/app/(application)/(user)/_layout.tsx +++ b/app/(application)/(user)/_layout.tsx @@ -125,7 +125,6 @@ export default function UserLayout() { headerLeft: () => , }} /> - , }} /> + , + }} + /> {/* ========== End Collaboration Section ========= */} diff --git a/app/(application)/(user)/collaboration/(tabs)/index.tsx b/app/(application)/(user)/collaboration/(tabs)/index.tsx index 037bf40..1a96457 100644 --- a/app/(application)/(user)/collaboration/(tabs)/index.tsx +++ b/app/(application)/(user)/collaboration/(tabs)/index.tsx @@ -1,8 +1,37 @@ -import { FloatingButton, ViewWrapper } from "@/components"; +import { + FloatingButton, + LoaderCustom, + TextCustom, + ViewWrapper, +} from "@/components"; import Collaboration_BoxPublishSection from "@/screens/Collaboration/BoxPublishSection"; -import { router } from "expo-router"; +import { apiCollaborationGetAll } from "@/service/api-client/api-collaboration"; +import { router, useFocusEffect } from "expo-router"; +import _ from "lodash"; +import { useCallback, useState } from "react"; export default function CollaborationBeranda() { + const [listData, setListData] = useState(); + const [loadingGetData, setLoadingGetData] = useState(false); + + useFocusEffect( + useCallback(() => { + onLoadData(); + }, []) + ); + + const onLoadData = async () => { + try { + setLoadingGetData(true); + const response = await apiCollaborationGetAll(); + + setListData(response.data); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoadingGetData(false); + } + }; return ( <> } > - {Array.from({ length: 10 }).map((_, index) => ( - - ))} + {loadingGetData ? ( + + ) : _.isEmpty(listData) ? ( + Tidak ada data + ) : ( + listData?.map((item: any, index: number) => ( + + )) + )} ); diff --git a/app/(application)/(user)/collaboration/[id]/create-pacticipants.tsx b/app/(application)/(user)/collaboration/[id]/create-pacticipants.tsx new file mode 100644 index 0000000..c7727dc --- /dev/null +++ b/app/(application)/(user)/collaboration/[id]/create-pacticipants.tsx @@ -0,0 +1,80 @@ +import { + AlertDefaultSystem, + ButtonCustom, + TextAreaCustom, + ViewWrapper, +} from "@/components"; +import { useAuth } from "@/hooks/use-auth"; +import { apiCollaborationCreatePartisipasi } from "@/service/api-client/api-collaboration"; +import { router, useLocalSearchParams } from "expo-router"; +import { useState } from "react"; +import Toast from "react-native-toast-message"; + +export default function CollaborationCreatePartisipans() { + const { user } = useAuth(); + const { id } = useLocalSearchParams(); + const [description, setDescription] = useState(""); + const [isLoading, setLoading] = useState(false); + + const handlerSubmitParticipans = async () => { + try { + setLoading(true); + const response = await apiCollaborationCreatePartisipasi({ + id: id as string, + data: { + authorId: user?.id, + description, + }, + }); + + if (response.success) { + Toast.show({ + type: "success", + text1: "Data berhasil disimpan", + }); + router.replace(`/collaboration/${id}/list-of-participants`); + } else { + Toast.show({ + type: "error", + text1: "Gagal menyimpan data", + }); + } + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoading(false); + } + }; + + return ( + + + + { + AlertDefaultSystem({ + title: "Simpan data deskripsi", + message: "Apakah anda sudah yakin ingin menyimpan data ini ?", + textLeft: "Batal", + textRight: "Simpan", + onPressRight: () => { + handlerSubmitParticipans(); + }, + }); + }} + > + Simpan + + + ); +} diff --git a/app/(application)/(user)/collaboration/[id]/index.tsx b/app/(application)/(user)/collaboration/[id]/index.tsx index 8a1082b..5c5f4c4 100644 --- a/app/(application)/(user)/collaboration/[id]/index.tsx +++ b/app/(application)/(user)/collaboration/[id]/index.tsx @@ -1,22 +1,73 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import { - AlertDefaultSystem, BackButton, ButtonCustom, DotButton, DrawerCustom, + LoaderCustom, MenuDrawerDynamicGrid, - TextAreaCustom, ViewWrapper, } from "@/components"; +import { useAuth } from "@/hooks/use-auth"; import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection"; +import { + apiCollaborationGetOne, + apiCollaborationGetParticipants, +} from "@/service/api-client/api-collaboration"; import { Ionicons } from "@expo/vector-icons"; -import { router, Stack, useLocalSearchParams } from "expo-router"; -import { useState } from "react"; +import { + router, + Stack, + useFocusEffect, + useLocalSearchParams, +} from "expo-router"; +import { useCallback, useState } from "react"; export default function CollaborationDetail() { + const { user } = useAuth(); const { id } = useLocalSearchParams(); - const [openDrawerPartisipasi, setOpenDrawerPartisipasi] = useState(false); + const [data, setData] = useState(); const [openDrawerMenu, setOpenDrawerMenu] = useState(false); + const [isParticipant, setIsParticipant] = useState(false); + const [loadingIsParticipant, setLoadingIsParticipant] = useState(false); + + useFocusEffect( + useCallback(() => { + onLoadData(); + onLoadParticipants(); + }, [id]) + ); + + const onLoadData = async () => { + try { + const response = await apiCollaborationGetOne({ id: id as string }); + if (response.success) { + setData(response.data); + } + } catch (error) { + console.log("[ERROR]", error); + } + }; + + const onLoadParticipants = async () => { + try { + setLoadingIsParticipant(true); + const response = await apiCollaborationGetParticipants({ + category: "check-participant", + id: id as string, + authorId: user?.id, + }); + + if (response.success) { + setIsParticipant(response.data); + } + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoadingIsParticipant(false); + } + }; + return ( <> - + {!data && !isParticipant ? ( + + ) : ( + <> + - setOpenDrawerPartisipasi(true)}> - Partisipasi - + { + router.push(`/collaboration/${id}/create-pacticipants`); + // setOpenDrawerPartisipasi(true); + }} + > + {isParticipant ? "Anda telah berpartisipasi" : "Partisipasi"} + + + )} {/* Drawer Partisipasi */} - setOpenDrawerPartisipasi(false)} height={300} @@ -48,6 +111,8 @@ export default function CollaborationDetail() { required showCount maxLength={500} + value={description} + onChangeText={setDescription} /> router.replace(`/collaboration/(tabs)/group`), + onPressRight: () => { + handlerSubmitParticipans(); + }, }); }} > Simpan - + */} {/* Drawer Menu */} setOpenDrawerMenu(false)} - height={250} + height={"auto"} > (); + const [loadingGetData, setLoadingGetData] = useState(false); + const [description, setDescription] = useState(""); + + useEffect(() => { + onLoadData(); + }, [id]); + + const onLoadData = async () => { + try { + setLoadingGetData(true); + const response = await apiCollaborationGetParticipants({ + category: "list", + id: id as string, + }); + + if (response.success) { + setListData(response.data); + } + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoadingGetData(false); + } + }; + const [openDrawer, setOpenDrawer] = useState(false); return ( <> - {Array.from({ length: 10 }).map((_, index) => ( - - setOpenDrawer(true)} - /> - } - /> - - ))} + {loadingGetData ? ( + + ) : _.isEmpty(listData) ? ( + Tidak ada data + ) : ( + listData?.map((item: any, index: number) => ( + + { + setDescription(item?.deskripsi_diri); + setOpenDrawer(true); + }} + /> + } + /> + + )) + )} {/* Drawer */} @@ -44,34 +85,7 @@ export default function CollaborationListOfParticipants() { Deskripsi diri - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua.Lorem - ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua.Lorem - ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua.Lorem - ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut iqua.Lorem ipsum dolor sit amet, - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua.Lorem ipsum dolor sit amet, - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua.Lorem ipsum dolor sit amet, - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua.Lorem ipsum dolor sit amet, - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua.Lorem ipsum dolor sit amet, - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua.Lorem ipsum dolor sit amet, - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua.Lorem ipsum dolor sit amet, - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua.Lorem ipsum dolor sit amet, - consectetur adipiscing elit, sed do eiusmod tempor incididunt ut - labore et dolore magna aliqua. - + {description} diff --git a/app/(application)/(user)/collaboration/create.tsx b/app/(application)/(user)/collaboration/create.tsx index 3670778..beb24e5 100644 --- a/app/(application)/(user)/collaboration/create.tsx +++ b/app/(application)/(user)/collaboration/create.tsx @@ -1,53 +1,175 @@ import { - ButtonCustom, - SelectCustom, - StackCustom, - TextAreaCustom, - TextInputCustom, - ViewWrapper + ButtonCustom, + LoaderCustom, + SelectCustom, + StackCustom, + TextAreaCustom, + TextInputCustom, + ViewWrapper, } from "@/components"; +import { useAuth } from "@/hooks/use-auth"; +import { apiCollaborationCreate } from "@/service/api-client/api-collaboration"; +import { apiMasterCollaborationType } from "@/service/api-client/api-master"; import { router } from "expo-router"; +import React, { useEffect, useState } from "react"; +import Toast from "react-native-toast-message"; + +interface CollaborationCreateProps { + title?: string; + lokasi?: string; + purpose?: string; + benefit?: string; + projectCollaborationMaster_IndustriId?: string; + userId?: string; +} export default function CollaborationCreate() { + const { user } = useAuth(); + const [listMaster, setListMaster] = useState([]); + const [loadingMaster, setLoadingMaster] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [data, setData] = React.useState({ + title: "", + lokasi: "", + purpose: "", + benefit: "", + projectCollaborationMaster_IndustriId: "", + userId: "", + }); + + useEffect(() => { + onLoadMaster(); + }, []); + + async function onLoadMaster() { + try { + setLoadingMaster(true); + const response = await apiMasterCollaborationType(); + setListMaster(response.data); + } catch (error) { + console.log("[ERROR]", error); + } finally { + setLoadingMaster(false); + } + } + + const handlerSubmit = async () => { + if ( + !data?.title || + !data?.lokasi || + !data?.purpose || + !data?.benefit || + !data?.projectCollaborationMaster_IndustriId + ) { + Toast.show({ + type: "error", + text1: "Gagal", + text2: "Harap isi semua data", + }); + return; + } + + const newData: CollaborationCreateProps = { + title: data?.title, + lokasi: data?.lokasi, + purpose: data?.purpose, + benefit: data?.benefit, + projectCollaborationMaster_IndustriId: + data?.projectCollaborationMaster_IndustriId, + userId: user?.id, + }; + + try { + setIsLoading(true); + console.log("[DATA]>>", newData); + + const response = await apiCollaborationCreate({ data: newData }); + if (response.success) { + Toast.show({ + type: "success", + text1: "Berhasil", + text2: response.message, + }); + router.back(); + } else { + Toast.show({ + type: "error", + text1: "Gagal", + text2: response.message, + }); + } + } catch (error) { + console.log("[ERROR]", error); + } finally { + setIsLoading(false); + } + }; + return ( - - - - console.log(value)} - /> + {loadingMaster ? ( + + ) : ( + + setData({ ...data, title: value })} + /> - + setData({ ...data, lokasi: value })} + /> - + ({ + label: item.name, + value: item.id, + }))} + value={data?.projectCollaborationMaster_IndustriId} + onChange={(value: any) => { + console.log(value); + setData({ + ...data, + projectCollaborationMaster_IndustriId: value, + }); + }} + /> - { - console.log("Simpan proyek"); - router.back(); - }} - /> - + setData({ ...data, purpose: value })} + /> + + setData({ ...data, benefit: value })} + /> + + handlerSubmit()} + /> + + )} ); } diff --git a/components/_ShareComponent/AvataraAndOtherHeaderComponent.tsx b/components/_ShareComponent/AvataraAndOtherHeaderComponent.tsx index 9d61fdb..ff780ca 100644 --- a/components/_ShareComponent/AvataraAndOtherHeaderComponent.tsx +++ b/components/_ShareComponent/AvataraAndOtherHeaderComponent.tsx @@ -1,3 +1,4 @@ +import { AccentColor } from "@/constants/color-palet"; import Divider from "../Divider/Divider"; import Grid from "../Grid/GridCustom"; import AvatarComp from "../Image/AvatarComp"; @@ -39,7 +40,7 @@ const AvatarUsernameAndOtherComponent = ({ )} - {withBottomLine && } + {withBottomLine && } ); }; diff --git a/screens/Collaboration/BoxDetailSection.tsx b/screens/Collaboration/BoxDetailSection.tsx index 7840f11..5656e99 100644 --- a/screens/Collaboration/BoxDetailSection.tsx +++ b/screens/Collaboration/BoxDetailSection.tsx @@ -1,22 +1,33 @@ import { - AvatarUsernameAndOtherComponent, - BoxWithHeaderSection, - Grid, - StackCustom, - TextCustom + AvatarUsernameAndOtherComponent, + BoxWithHeaderSection, + Grid, + Spacing, + StackCustom, + TextCustom, } from "@/components"; -export default function Collaboration_BoxDetailSection({ id }: { id: string }) { +export default function Collaboration_BoxDetailSection({ + data, +}: { + data: any; +}) { return ( <> + + - - Judul Proyek {id} + {data?.title || ""} - {listData.map((item, index) => ( + {listData(data).map((item, index) => ( {item.title} @@ -32,23 +43,21 @@ export default function Collaboration_BoxDetailSection({ id }: { id: string }) { ); } -const listData = [ +const listData = (data: any) => [ { title: "Industri", - value: "Pilihan Industri", + value: data?.ProjectCollaborationMaster_Industri?.name || "-", }, { - title: "Deskripsi", - value: "Deskripsi Proyek", + title: "Lokasi", + value: data?.lokasi || "-", }, { title: "Tujuan Proyek", - value: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + value: data?.purpose || "-", }, { title: "Keuntungan Proyek", - value: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + value: data?.benefit || "-", }, ]; diff --git a/screens/Collaboration/BoxPublishSection.tsx b/screens/Collaboration/BoxPublishSection.tsx index 7694b18..2f63a93 100644 --- a/screens/Collaboration/BoxPublishSection.tsx +++ b/screens/Collaboration/BoxPublishSection.tsx @@ -7,24 +7,12 @@ import { import { Href } from "expo-router"; function Collaboration_BoxPublishSection({ - id, - title, - username, - description, href, - - // Avatar - sourceAvatar, + data, rightComponentAvatar, }: { - id: string; - title?: string; - username?: string; - description?: string; href: Href; - - // Avatar - sourceAvatar?: string; + data: any; rightComponentAvatar?: React.ReactNode; }) { return ( @@ -32,21 +20,18 @@ function Collaboration_BoxPublishSection({ - {title || "Lorem ipsum dolor sit"} - - - {description || - "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro sed doloremque tempora soluta. Dolorem ex quidem ipsum tempora, ipsa, obcaecati quia suscipit numquam, voluptates commodi porro impedit natus quos doloremque!"} + {data?.title || "-"} + {data?.purpose || "-"} {/* 2 Partisipan */} diff --git a/service/api-client/api-collaboration.ts b/service/api-client/api-collaboration.ts new file mode 100644 index 0000000..82d13ef --- /dev/null +++ b/service/api-client/api-collaboration.ts @@ -0,0 +1,71 @@ +import { apiConfig } from "../api-config"; + +export async function apiCollaborationCreate({ data }: { data: any }) { + try { + const response = await apiConfig.post(`/mobile/collaboration`, { + data: data, + }); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiCollaborationGetAll() { + try { + const response = await apiConfig.get(`/mobile/collaboration`); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiCollaborationGetOne({ id }: { id: string }) { + try { + const response = await apiConfig.get(`/mobile/collaboration/${id}`); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiCollaborationCreatePartisipasi({ + id, + data, + +}: { + id: string; + data: any; +}) { + try { + const response = await apiConfig.post( + `/mobile/collaboration/${id}/participants`, + { + data: data, + } + ); + return response.data; + } catch (error) { + throw error; + } +} + +export async function apiCollaborationGetParticipants({ + id, + category, + authorId, +}: { + id: string; + category: "list" | "check-participant"; + authorId?: string; +}) { + try { + const authorQuery = authorId ? `&authorId=${authorId}` : ""; + const response = await apiConfig.get( + `/mobile/collaboration/${id}/participants?category=${category}${authorQuery}` + ); + return response.data; + } catch (error) { + throw error; + } +} diff --git a/service/api-client/api-master.ts b/service/api-client/api-master.ts index 7e80cb8..073cbc3 100644 --- a/service/api-client/api-master.ts +++ b/service/api-client/api-master.ts @@ -28,4 +28,13 @@ export async function apiMasterEventType() { } catch (error) { throw error; } -} \ No newline at end of file +} + +export async function apiMasterCollaborationType() { + try { + const response = await apiConfig.get(`/mobile/master/collaboration-industry`); + return response.data; + } catch (error) { + throw error; + } +}