Collaboration

Add:
- (user)/collaboration/[id]/select-of-participants

Fix:
- Integrasi ke api di bagian beranda , partisipan dan group

### No Issue
This commit is contained in:
2025-09-23 17:41:03 +08:00
parent 821a211f58
commit 99f058a92f
16 changed files with 905 additions and 190 deletions

View File

@@ -118,13 +118,13 @@ export default function UserLayout() {
headerLeft: () => <BackButton />, headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen {/* <Stack.Screen
name="collaboration/[id]/detail-participant" name="collaboration/[id]/detail-participant"
options={{ options={{
title: "Partisipasi Proyek", title: "Partisipasi Proyek",
headerLeft: () => <BackButton />, headerLeft: () => <BackButton />,
}} }}
/> /> */}
<Stack.Screen <Stack.Screen
name="collaboration/[id]/edit" name="collaboration/[id]/edit"
options={{ options={{
@@ -139,6 +139,13 @@ export default function UserLayout() {
headerLeft: () => <BackButton />, headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen
name="collaboration/[id]/select-of-participants"
options={{
title: "Pilih Partisipan",
headerLeft: () => <BackButton />,
}}
/>
{/* ========== End Collaboration Section ========= */} {/* ========== End Collaboration Section ========= */}

View File

@@ -1,38 +1,98 @@
import { BaseBox, Grid, TextCustom } from "@/components"; /* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
import {
BaseBox,
Grid,
LoaderCustom,
StackCustom,
TextCustom,
} from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper"; import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth";
import { apiCollaborationGetAll } from "@/service/api-client/api-collaboration";
import { Feather } from "@expo/vector-icons"; import { Feather } from "@expo/vector-icons";
import { useFocusEffect } from "expo-router";
import _ from "lodash";
import { useState, useCallback } from "react";
export default function CollaborationGroup() { export default function CollaborationGroup() {
const { user } = useAuth();
const [listData, setListData] = useState<any[]>();
const [loadingGetData, setLoadingGetData] = useState(false);
useFocusEffect(
useCallback(() => {
onLoadData();
}, [user?.id])
);
const onLoadData = async () => {
try {
setLoadingGetData(true);
const response = await apiCollaborationGetAll({
category: "group",
authorId: user?.id,
});
console.log("[RES >>]", JSON.stringify(response.data, null, 2));
if (response.success) {
setListData(response.data);
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingGetData(false);
}
};
return ( return (
<ViewWrapper hideFooter> <ViewWrapper hideFooter>
{Array.from({ length: 10 }).map((_, index) => ( {loadingGetData ? (
<BaseBox <LoaderCustom />
key={index} ) : _.isEmpty(listData) ? (
paddingBlock={5} <TextCustom align="center">Tidak ada data</TextCustom>
href={`/collaboration/${index}/${generateProjectName()}/room-chat`} ) : (
> <StackCustom>
<Grid> {listData?.map((item: any, index: any) => (
<Grid.Col span={10}> <BaseBox
<TextCustom bold>{generateProjectName()}</TextCustom> key={index}
<TextCustom size="small">2 Anggota</TextCustom> paddingBlock={5}
</Grid.Col> href={`/collaboration/${item?.ProjectCollaboration_RoomChat?.id}/${item?.ProjectCollaboration_RoomChat?.name}/room-chat`}
<Grid.Col
span={2}
style={{ alignItems: "flex-end", justifyContent: "center" }}
> >
<Feather name="chevron-right" size={20} color={MainColor.white} /> <Grid>
</Grid.Col> <Grid.Col span={10}>
</Grid> <TextCustom bold>
</BaseBox> {item?.ProjectCollaboration_RoomChat?.name}
))} </TextCustom>
<TextCustom size="small">
{
item?.ProjectCollaboration_RoomChat
?.ProjectCollaboration_AnggotaRoomChat?.length
}{" "}
Anggota
</TextCustom>
</Grid.Col>
<Grid.Col
span={2}
style={{ alignItems: "flex-end", justifyContent: "center" }}
>
<Feather
name="chevron-right"
size={20}
color={MainColor.white}
/>
</Grid.Col>
</Grid>
</BaseBox>
))}
</StackCustom>
)}
</ViewWrapper> </ViewWrapper>
); );
} }
function generateProjectName() { function generateProjectName() {
const adjectives = [ const adjectives = [
"Blue", "Blue",
@@ -65,4 +125,4 @@ function generateProjectName() {
const randomNoun = nouns[Math.floor(Math.random() * nouns.length)]; const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];
return randomAdjective + randomNoun; return randomAdjective + randomNoun;
} }

View File

@@ -23,7 +23,9 @@ export default function CollaborationBeranda() {
const onLoadData = async () => { const onLoadData = async () => {
try { try {
setLoadingGetData(true); setLoadingGetData(true);
const response = await apiCollaborationGetAll(); const response = await apiCollaborationGetAll({
category: "beranda",
});
setListData(response.data); setListData(response.data);
} catch (error) { } catch (error) {
@@ -32,6 +34,7 @@ export default function CollaborationBeranda() {
setLoadingGetData(false); setLoadingGetData(false);
} }
}; };
return ( return (
<> <>
<ViewWrapper <ViewWrapper

View File

@@ -1,15 +1,46 @@
import { ButtonCustom, Spacing } from "@/components"; /* eslint-disable react-hooks/exhaustive-deps */
import { ButtonCustom, LoaderCustom, Spacing, TextCustom } from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper"; import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { AccentColor, MainColor } from "@/constants/color-palet"; import { AccentColor, MainColor } from "@/constants/color-palet";
import { useAuth } from "@/hooks/use-auth";
import Collaboration_BoxPublishSection from "@/screens/Collaboration/BoxPublishSection"; import Collaboration_BoxPublishSection from "@/screens/Collaboration/BoxPublishSection";
import { useState } from "react"; import { apiCollaborationGetAll } from "@/service/api-client/api-collaboration";
import { useFocusEffect } from "expo-router";
import _ from "lodash";
import { useCallback, useState } from "react";
import { View } from "react-native"; import { View } from "react-native";
export default function CollaborationParticipans() { export default function CollaborationParticipans() {
const [activeCategory, setActiveCategory] = useState<string | null>( const [activeCategory, setActiveCategory] = useState<
"participant" "participant" | "my-project"
>("participant");
const { user } = useAuth();
const [listData, setListData] = useState<any[]>();
const [loadingGetData, setLoadingGetData] = useState(false);
useFocusEffect(
useCallback(() => {
onLoadData();
}, [activeCategory])
); );
const onLoadData = async () => {
try {
setLoadingGetData(true);
const response = await apiCollaborationGetAll({
category:
activeCategory === "participant" ? "participant" : "my-project",
authorId: user?.id,
});
setListData(response.data);
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingGetData(false);
}
};
const handlePress = (item: any) => { const handlePress = (item: any) => {
setActiveCategory(item); setActiveCategory(item);
// tambahkan logika lain seperti filter dsb. // tambahkan logika lain seperti filter dsb.
@@ -41,13 +72,13 @@ export default function CollaborationParticipans() {
<Spacing width={"2%"} /> <Spacing width={"2%"} />
<ButtonCustom <ButtonCustom
backgroundColor={ backgroundColor={
activeCategory === "main" ? MainColor.yellow : AccentColor.blue activeCategory === "my-project" ? MainColor.yellow : AccentColor.blue
} }
textColor={ textColor={
activeCategory === "main" ? MainColor.black : MainColor.white activeCategory === "my-project" ? MainColor.black : MainColor.white
} }
style={{ width: "49%" }} style={{ width: "49%" }}
onPress={() => handlePress("main")} onPress={() => handlePress("my-project")}
> >
Proyek Saya Proyek Saya
</ButtonCustom> </ButtonCustom>
@@ -56,22 +87,27 @@ export default function CollaborationParticipans() {
return ( return (
<ViewWrapper hideFooter headerComponent={headerComponent}> <ViewWrapper hideFooter headerComponent={headerComponent}>
{Array.from({ length: 10 }).map((_, index) => ( {loadingGetData ? (
<Collaboration_BoxPublishSection <LoaderCustom />
key={index.toString()} ) : _.isEmpty(listData) ? (
id={index.toString()} <TextCustom align="center">Tidak ada data</TextCustom>
username={` ${ ) : activeCategory === "participant" ? (
activeCategory === "participant" listData?.map((item: any, index: number) => (
? "Partisipasi Proyek" <Collaboration_BoxPublishSection
: "Proyek Saya" key={index.toString()}
}`} data={item?.ProjectCollaboration}
href={ href={`/collaboration/${item?.ProjectCollaboration?.id}/detail-participant`}
activeCategory === "participant" />
? `/collaboration/${index}/detail-participant` ))
: `/collaboration/${index}/detail-project-main` ) : (
} listData?.map((item: any, index: number) => (
/> <Collaboration_BoxPublishSection
))} key={index.toString()}
data={item}
href={`/collaboration/${item?.id}/detail-project-main`}
/>
))
)}
</ViewWrapper> </ViewWrapper>
); );
} }

View File

@@ -1,17 +1,41 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
import { import {
AvatarUsernameAndOtherComponent, AvatarUsernameAndOtherComponent,
BackButton, BackButton,
BaseBox,
BoxWithHeaderSection, BoxWithHeaderSection,
Grid, Grid,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import { Stack, useLocalSearchParams } from "expo-router"; import { apiCollaborationGroup } from "@/service/api-client/api-collaboration";
import { Stack, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useState, useCallback } from "react";
export default function CollaborationRoomInfo() { export default function CollaborationRoomInfo() {
const { id, detail } = useLocalSearchParams(); const { id, detail } = useLocalSearchParams();
const [data, setData] = useState<any>();
useFocusEffect(
useCallback(() => {
onLoadData();
}, [id])
);
const onLoadData = async () => {
try {
const response = await apiCollaborationGroup({ id: id as string });
if (response.success) {
setData(response.data);
}
} catch (error) {
console.log("[ERROR]", error);
}
};
return ( return (
<> <>
<Stack.Screen <Stack.Screen
@@ -24,7 +48,7 @@ export default function CollaborationRoomInfo() {
<ViewWrapper> <ViewWrapper>
<BoxWithHeaderSection> <BoxWithHeaderSection>
<StackCustom> <StackCustom>
{listData.map((item, index) => ( {listData({ data }).map((item, index) => (
<Grid key={index}> <Grid key={index}>
<Grid.Col span={4}> <Grid.Col span={4}>
<TextCustom bold>{item.title}</TextCustom> <TextCustom bold>{item.title}</TextCustom>
@@ -37,37 +61,42 @@ export default function CollaborationRoomInfo() {
</StackCustom> </StackCustom>
</BoxWithHeaderSection> </BoxWithHeaderSection>
<BoxWithHeaderSection> <BaseBox>
{Array.from({ length: 10 }).map((_, index) => ( <StackCustom gap={10}>
<AvatarUsernameAndOtherComponent key={index} avatarHref={`/profile/${index}`} /> {data?.ProjectCollaboration_AnggotaRoomChat?.map(
))} (item: any, index: number) => (
</BoxWithHeaderSection> <AvatarUsernameAndOtherComponent
key={index}
avatarHref={`/profile/${item?.User?.Profile?.id}`}
name={item?.User?.username}
avatar={item?.User?.Profile?.imageId}
/>
)
)}
</StackCustom>
</BaseBox>
</ViewWrapper> </ViewWrapper>
</> </>
); );
} }
const listData = [ const listData = ({ data }: { data: any }) => [
{ {
title: "Judul Proyek", title: "Judul Proyek",
value: "Judul Proyek", value: data?.ProjectCollaboration?.title || "-",
}, },
{ {
title: "Industri", title: "Industri",
value: "Pilihan Industri", value:
}, data?.ProjectCollaboration?.ProjectCollaborationMaster_Industri?.name ||
{ "-",
title: "Deskripsi",
value: "Deskripsi Proyek",
}, },
{ {
title: "Tujuan Proyek", title: "Tujuan Proyek",
value: value: data?.ProjectCollaboration?.purpose || "-",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
}, },
{ {
title: "Keuntungan Proyek", title: "Keuntungan Proyek",
value: value: data?.ProjectCollaboration?.benefit || "-",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
}, },
]; ];

View File

@@ -1,3 +1,4 @@
import { import {
BackButton, BackButton,
BoxButtonOnFooter, BoxButtonOnFooter,
@@ -15,6 +16,7 @@ import { StyleSheet, TouchableOpacity, View } from "react-native";
export default function CollaborationRoomChat() { export default function CollaborationRoomChat() {
const { id, detail } = useLocalSearchParams(); const { id, detail } = useLocalSearchParams();
const inputChat = () => { const inputChat = () => {
return ( return (
<> <>

View File

@@ -1,26 +1,54 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { import {
AvatarUsernameAndOtherComponent, BackButton,
BaseBox, DotButton,
DrawerCustom, DrawerCustom,
StackCustom, MenuDrawerDynamicGrid,
TextCustom, ViewWrapper
ViewWrapper,
} from "@/components"; } from "@/components";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection"; import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection";
import { MaterialIcons } from "@expo/vector-icons"; import { apiCollaborationGetOne } from "@/service/api-client/api-collaboration";
import { useLocalSearchParams } from "expo-router"; import { Ionicons } from "@expo/vector-icons";
import { useState } from "react"; import { router, Stack, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react";
export default function CollaborationDetailParticipant() { export default function CollaborationDetailParticipant() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const [openDrawerParticipant, setOpenDrawerParticipant] = useState(false); const [openDrawerParticipant, setOpenDrawerParticipant] = useState(false);
const [data, setData] = useState<any>();
useFocusEffect(
useCallback(() => {
onLoadData();
}, [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);
}
};
return ( return (
<> <>
<Stack.Screen
options={{
title: "Detail Proyek",
headerLeft: () => <BackButton />,
headerRight: () => (
<DotButton onPress={() => setOpenDrawerParticipant(true)} />
),
}}
/>
<ViewWrapper> <ViewWrapper>
<Collaboration_BoxDetailSection id={id as string} /> <Collaboration_BoxDetailSection data={data} />
<BaseBox style={{ height: 500 }}> {/* <BaseBox style={{ height: 500 }}>
<TextCustom align="center" bold size="large"> <TextCustom align="center" bold size="large">
Partisipan Partisipan
</TextCustom> </TextCustom>
@@ -39,13 +67,33 @@ export default function CollaborationDetailParticipant() {
} }
/> />
))} ))}
</BaseBox> </BaseBox> */}
</ViewWrapper> </ViewWrapper>
<DrawerCustom <DrawerCustom
isVisible={openDrawerParticipant} isVisible={openDrawerParticipant}
closeDrawer={() => setOpenDrawerParticipant(false)} closeDrawer={() => setOpenDrawerParticipant(false)}
height={"auto"} height={"auto"}
>
<MenuDrawerDynamicGrid
data={[
{
icon: <Ionicons name="people" size={24} color="white" />,
label: "Daftar Partisipan",
path: `/collaboration/${id}/list-of-participants`,
},
]}
onPressItem={(item) => {
router.push(item.path as any);
setOpenDrawerParticipant(false);
}}
/>
</DrawerCustom>
{/* <DrawerCustom
isVisible={openDrawerParticipant}
closeDrawer={() => setOpenDrawerParticipant(false)}
height={"auto"}
> >
<StackCustom> <StackCustom>
<TextCustom bold>Deskripsi Diri</TextCustom> <TextCustom bold>Deskripsi Diri</TextCustom>
@@ -56,7 +104,7 @@ export default function CollaborationDetailParticipant() {
Temporibus iusto soluta necessitatibus. Temporibus iusto soluta necessitatibus.
</TextCustom> </TextCustom>
</StackCustom> </StackCustom>
</DrawerCustom> </DrawerCustom> */}
</> </>
); );
} }

View File

@@ -1,30 +1,65 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { import {
AlertDefaultSystem,
BackButton, BackButton,
ButtonCustom,
DotButton, DotButton,
DrawerCustom, DrawerCustom,
LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
Spacing, Spacing,
StackCustom, ViewWrapper
TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { IconEdit } from "@/components/_Icon"; import { IconEdit } from "@/components/_Icon";
import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection"; import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection";
import Collaboration_MainParticipanSelectedSection from "@/screens/Collaboration/ProjectMainSelectedSection"; import {
import { router, Stack, useLocalSearchParams } from "expo-router"; apiCollaborationGetOne
import { useState } from "react"; } from "@/service/api-client/api-collaboration";
import { MaterialIcons } from "@expo/vector-icons";
import {
router,
Stack,
useFocusEffect,
useLocalSearchParams,
} from "expo-router";
import { useCallback, useState } from "react";
export default function CollaborationDetailProjectMain() { export default function CollaborationDetailProjectMain() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const [openDrawerParticipant, setOpenDrawerParticipant] = useState(false); const [data, setData] = useState<any>();
const [selected, setSelected] = useState<(string | number)[]>([]); const [loadingGetData, setLoadingGetData] = useState(false);
const handleEdit = () => { useFocusEffect(
console.log("Edit collaboration"); useCallback(() => {
router.push("/(application)/(user)/collaboration/(id)/edit"); handlerLoadData();
}, [id])
);
const handlerLoadData = async () => {
try {
setLoadingGetData(true);
await onLoadData();
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingGetData(false);
}
};
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 handleSubmit = (item: any) => {
console.log("item :", item);
router.push(item.path);
setOpenDrawer(false);
}; };
return ( return (
@@ -37,34 +72,21 @@ export default function CollaborationDetailProjectMain() {
}} }}
/> />
<ViewWrapper> <ViewWrapper>
<Collaboration_BoxDetailSection id={id as string} /> {loadingGetData ? (
<Collaboration_MainParticipanSelectedSection <LoaderCustom />
selected={selected} ) : (
setSelected={setSelected} <>
setOpenDrawerParticipant={setOpenDrawerParticipant} <Collaboration_BoxDetailSection data={data} />
/> {/* <Collaboration_MainParticipanSelectedSection
selected={selected}
setSelected={setSelected}
setOpenDrawerParticipant={setOpenDrawerParticipant}
listData={listData as any}
/> */}
<ButtonCustom <Spacing />
onPress={() => { </>
AlertDefaultSystem({ )}
title: "Buat Grup",
message:
"Apakah anda yakin ingin membuat grup untuk proyek ini ?",
textLeft: "Tidak",
textRight: "Ya",
onPressLeft: () => {},
onPressRight: () => {
router.navigate(
"/(application)/(user)/collaboration/(tabs)/group"
);
console.log("selected :", selected);
},
});
}}
>
Buat Grup
</ButtonCustom>
<Spacing />
</ViewWrapper> </ViewWrapper>
<DrawerCustom <DrawerCustom
@@ -76,31 +98,20 @@ export default function CollaborationDetailProjectMain() {
data={[ data={[
{ {
label: "Edit", label: "Edit",
path: "/(application)/(user)/collaboration/(tabs)/group", path: `/(application)/(user)/collaboration/${id}/edit`,
icon: <IconEdit />, icon: <IconEdit />,
}, },
{
label: "Pilih Partisipan",
path: `/(application)/(user)/collaboration/${id}/select-of-participants`,
icon: <MaterialIcons name="checklist" size={24} color="white" />,
},
]} ]}
onPressItem={(item) => { onPressItem={(item: any) => {
handleEdit(); handleSubmit(item);
}} }}
/> />
</DrawerCustom> </DrawerCustom>
<DrawerCustom
isVisible={openDrawerParticipant}
closeDrawer={() => setOpenDrawerParticipant(false)}
height={"auto"}
>
<StackCustom>
<TextCustom bold>Deskripsi Diri</TextCustom>
<TextCustom>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Commodi,
itaque adipisci. Voluptas, sed quod! Ad facere labore voluptates,
neque quidem aut reprehenderit ducimus mollitia quisquam temporibus!
Temporibus iusto soluta necessitatibus.
</TextCustom>
</StackCustom>
</DrawerCustom>
</> </>
); );
} }

View File

@@ -1,53 +1,171 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { import {
ButtonCustom, ButtonCustom,
LoaderCustom,
SelectCustom, SelectCustom,
StackCustom, StackCustom,
TextAreaCustom, TextAreaCustom,
TextInputCustom, TextInputCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import { router } from "expo-router"; import {
apiCollaborationEditData,
apiCollaborationGetOne,
} from "@/service/api-client/api-collaboration";
import { apiMasterCollaborationType } from "@/service/api-client/api-master";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react";
import Toast from "react-native-toast-message";
export default function CollaborationEdit() { export default function CollaborationEdit() {
const { id } = useLocalSearchParams();
console.log("id :", id);
const [data, setData] = useState<any>();
const [listMaster, setListMaster] = useState<any[]>([]);
const [loadingData, setLoadingData] = useState(false);
const [isLoading, setIsLoading] = useState(false);
useFocusEffect(
useCallback(() => {
const fetchData = async () => {
try {
setLoadingData(true);
await onLoadData();
await onLoadMaster();
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingData(false);
}
};
fetchData();
}, [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);
}
};
async function onLoadMaster() {
try {
const response = await apiMasterCollaborationType();
setListMaster(response.data);
} catch (error) {
console.log("[ERROR]", error);
}
}
const handlerSubmitUpdate = async () => {
if (
!data?.title ||
!data?.lokasi ||
!data?.projectCollaborationMaster_IndustriId ||
!data?.purpose ||
!data?.benefit
) {
Toast.show({
type: "error",
text1: "Gagal",
text2: "Harap isi semua data",
});
return;
}
try {
setIsLoading(true);
const response = await apiCollaborationEditData({
id: id as string,
data: data,
});
if (response.success) {
Toast.show({
type: "success",
text1: response.message,
});
router.back();
} else {
Toast.show({
type: "error",
text1: response.message,
});
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setIsLoading(false);
}
};
return ( return (
<ViewWrapper> <ViewWrapper>
<StackCustom gap={"xs"}> {loadingData ? (
<TextInputCustom label="Judul" placeholder="Masukan judul" required /> <LoaderCustom />
<TextInputCustom label="Lokasi" placeholder="Masukan lokasi" required /> ) : (
<SelectCustom <StackCustom gap={"xs"}>
label="Pilih Industri" <TextInputCustom
data={[ label="Judul"
{ label: "Industri 1", value: "industri-1" }, placeholder="Masukan judul"
{ label: "Industri 2", value: "industri-2" }, required
{ label: "Industri 3", value: "industri-3" }, value={data?.title}
]} onChangeText={(value) => setData({ ...data, title: value })}
onChange={(value) => console.log(value)} />
/> <TextInputCustom
label="Lokasi"
placeholder="Masukan lokasi"
required
value={data?.lokasi}
onChangeText={(value) => setData({ ...data, lokasi: value })}
/>
<SelectCustom
label="Pilih Industri"
data={listMaster?.map((item: any) => ({
label: item.name,
value: item.id,
}))}
value={data?.projectCollaborationMaster_IndustriId}
onChange={(value) =>
setData({ ...data, projectCollaborationMaster_IndustriId: value })
}
/>
<TextAreaCustom <TextAreaCustom
required required
label="Tujuan Proyek" label="Tujuan Proyek"
placeholder="Masukan tujuan proyek" placeholder="Masukan tujuan proyek"
showCount showCount
maxLength={1000} maxLength={1000}
/> value={data?.purpose}
onChangeText={(value) => setData({ ...data, purpose: value })}
/>
<TextAreaCustom <TextAreaCustom
required required
label="Keuntungan Proyek" label="Keuntungan Proyek"
placeholder="Masukan keuntungan proyek" placeholder="Masukan keuntungan proyek"
showCount showCount
maxLength={1000} maxLength={1000}
/> value={data?.benefit}
onChangeText={(value) => setData({ ...data, benefit: value })}
/>
<ButtonCustom <ButtonCustom
title="Update" isLoading={isLoading}
onPress={() => { title="Update"
console.log("Update proyek"); onPress={() => {
router.back(); handlerSubmitUpdate();
}} }}
/> />
</StackCustom> </StackCustom>
)}
</ViewWrapper> </ViewWrapper>
); );
} }

View File

@@ -4,6 +4,7 @@ import {
ButtonCustom, ButtonCustom,
DotButton, DotButton,
DrawerCustom, DrawerCustom,
InformationBox,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
ViewWrapper, ViewWrapper,
@@ -26,7 +27,7 @@ import { useCallback, useState } from "react";
export default function CollaborationDetail() { export default function CollaborationDetail() {
const { user } = useAuth(); const { user } = useAuth();
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const [data, setData] = useState(); const [data, setData] = useState<any>();
const [openDrawerMenu, setOpenDrawerMenu] = useState(false); const [openDrawerMenu, setOpenDrawerMenu] = useState(false);
const [isParticipant, setIsParticipant] = useState(false); const [isParticipant, setIsParticipant] = useState(false);
const [loadingIsParticipant, setLoadingIsParticipant] = useState(false); const [loadingIsParticipant, setLoadingIsParticipant] = useState(false);
@@ -41,6 +42,7 @@ export default function CollaborationDetail() {
const onLoadData = async () => { const onLoadData = async () => {
try { try {
const response = await apiCollaborationGetOne({ id: id as string }); const response = await apiCollaborationGetOne({ id: id as string });
if (response.success) { if (response.success) {
setData(response.data); setData(response.data);
} }
@@ -84,17 +86,25 @@ export default function CollaborationDetail() {
<LoaderCustom /> <LoaderCustom />
) : ( ) : (
<> <>
{user?.id === data?.Author?.id && (
<InformationBox
text={
"Tombol partisipasi hanya muncul untuk proyek yang tidak anda buat"
}
/>
)}
<Collaboration_BoxDetailSection data={data} /> <Collaboration_BoxDetailSection data={data} />
{user?.id !== data?.Author?.id && (
<ButtonCustom <ButtonCustom
disabled={isParticipant || loadingIsParticipant} disabled={isParticipant || loadingIsParticipant}
onPress={() => { onPress={() => {
router.push(`/collaboration/${id}/create-pacticipants`); router.push(`/collaboration/${id}/create-pacticipants`);
// setOpenDrawerPartisipasi(true); // setOpenDrawerPartisipasi(true);
}} }}
> >
{isParticipant ? "Anda telah berpartisipasi" : "Partisipasi"} {isParticipant ? "Anda telah berpartisipasi" : "Partisipasi"}
</ButtonCustom> </ButtonCustom>
)}
</> </>
)} )}
</ViewWrapper> </ViewWrapper>

View File

@@ -0,0 +1,251 @@
/* eslint-disable react-hooks/exhaustive-deps */
import {
AlertDefaultSystem,
AvatarComp,
BaseBox,
BoxButtonOnFooter,
ButtonCustom,
CheckboxCustom,
CheckboxGroup,
DrawerCustom,
Grid,
LoaderCustom,
Spacing,
StackCustom,
TextAreaCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import ModalCustom from "@/components/Modal/ModalCustom";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { useAuth } from "@/hooks/use-auth";
import {
apiCollaborationCreateGroup,
apiCollaborationGetParticipants,
} from "@/service/api-client/api-collaboration";
import { MaterialIcons } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
import _ from "lodash";
import { useEffect, useState } from "react";
import { ScrollView, View } from "react-native";
import Toast from "react-native-toast-message";
export default function CollaborationSelectOfParticipants() {
const { user } = useAuth();
const { id } = useLocalSearchParams();
const [listData, setListData] = useState<any[]>();
const [loadingGetData, setLoadingGetData] = useState(false);
const [description, setDescription] = useState("");
const [selected, setSelected] = useState<(string | number)[]>([]);
const [openDrawer, setOpenDrawer] = useState(false);
const [nameGroup, setNameGroup] = useState("");
const [openModal, setOpenModal] = useState(false);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
onLoadData();
}, [id]);
const onLoadData = async () => {
try {
setLoadingGetData(true);
const response = await apiCollaborationGetParticipants({
category: "list",
id: id as string,
});
// console.log("response :", JSON.stringify(response.data, null, 2));
if (response.success) {
setListData(response.data);
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingGetData(false);
}
};
const handlerCreateGroup = async () => {
if (_.isEmpty(nameGroup)) {
Toast.show({
type: "error",
text1: "Nama grup tidak boleh kosong",
});
return;
}
try {
setIsLoading(true);
const response = await apiCollaborationCreateGroup({
id: id as string,
data: {
authorId: user?.id,
nameGroup: nameGroup,
listSelect: selected,
},
});
if (response.success) {
Toast.show({
type: "success",
text1: "Grup berhasil dibuat",
});
router.push("/(application)/(user)/collaboration/(tabs)/group");
} else {
Toast.show({
type: "error",
text1: "Gagal membuat grup",
});
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setIsLoading(false);
}
};
const handlerSubmit = () => {
return (
<>
<BoxButtonOnFooter>
<ButtonCustom
disabled={_.isEmpty(selected)}
onPress={() => {
setOpenModal(true);
setNameGroup("");
}}
>
Buat Grup
</ButtonCustom>
</BoxButtonOnFooter>
</>
);
};
return (
<>
<ViewWrapper
footerComponent={_.isEmpty(listData) ? null : handlerSubmit()}
>
{loadingGetData ? (
<LoaderCustom />
) : _.isEmpty(listData) ? (
<TextCustom align="center">Tidak ada partisipan</TextCustom>
) : (
<StackCustom>
<TextCustom size="default" color="red" bold>
*{" "}
<TextCustom size="small" semiBold>
Pilih user yang akan menjadi tim proyek anda
</TextCustom>
</TextCustom>
<CheckboxGroup
value={selected}
onChange={(val: any) => {
console.log("val :", val);
setSelected(val);
}}
>
{listData?.map((item: any, index: any) => (
<View key={index}>
<Grid key={index}>
<Grid.Col
span={2}
style={{ alignItems: "center", justifyContent: "center" }}
>
<CheckboxCustom valueKey={item?.User?.id} />
</Grid.Col>
<Grid.Col span={2} style={{ alignItems: "center" }}>
<AvatarComp
size="base"
fileId={item?.User?.Profile?.imageId}
/>
</Grid.Col>
<Grid.Col span={6} style={{ justifyContent: "center" }}>
<TextCustom bold truncate>
{item?.User?.username}
</TextCustom>
</Grid.Col>
<Grid.Col
span={2}
style={{ alignItems: "center", justifyContent: "center" }}
>
<MaterialIcons
name="notes"
size={ICON_SIZE_SMALL}
color="white"
onPress={() => {
setOpenDrawer(true);
setDescription(item?.deskripsi_diri);
}}
/>
</Grid.Col>
</Grid>
</View>
))}
</CheckboxGroup>
</StackCustom>
)}
</ViewWrapper>
<ModalCustom isVisible={openModal}>
<StackCustom gap={0}>
<TextAreaCustom
placeholder="Nama Grup"
value={nameGroup}
onChangeText={(val) => setNameGroup(val)}
/>
<Grid>
<Grid.Col span={6} style={{ paddingRight: 10 }}>
<ButtonCustom
backgroundColor="gray"
onPress={() => {
setOpenModal(false);
}}
>
Batal
</ButtonCustom>
</Grid.Col>
<Grid.Col span={6} style={{ paddingLeft: 10 }}>
<ButtonCustom
isLoading={isLoading}
disabled={_.isEmpty(nameGroup)}
onPress={() => {
AlertDefaultSystem({
title: "Buat Grup",
message:
"Apakah anda yakin ingin membuat grup untuk proyek ini ?",
textLeft: "Tidak",
textRight: "Ya",
onPressLeft: () => {},
onPressRight: () => {
handlerCreateGroup();
},
});
}}
>
Simpan
</ButtonCustom>
</Grid.Col>
</Grid>
</StackCustom>
</ModalCustom>
{/* Drawer */}
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
>
<StackCustom>
<TextCustom bold>Deskripsi diri</TextCustom>
<BaseBox>
<ScrollView style={{ height: "80%" }}>
<TextCustom>{description}</TextCustom>
</ScrollView>
</BaseBox>
<Spacing />
</StackCustom>
</DrawerCustom>
</>
);
}

View File

@@ -22,6 +22,7 @@ export default function Forumku() {
const [status, setStatus] = useState(""); const [status, setStatus] = useState("");
const [alertStatus, setAlertStatus] = useState(false); const [alertStatus, setAlertStatus] = useState(false);
const [deleteAlert, setDeleteAlert] = useState(false); const [deleteAlert, setDeleteAlert] = useState(false);
return ( return (
<> <>

View File

@@ -0,0 +1,92 @@
import { AccentColor, MainColor } from "@/constants/color-palet";
import { TEXT_SIZE_LARGE } from "@/constants/constans-value";
import React from "react";
import {
Keyboard,
StyleSheet,
TouchableWithoutFeedback,
View,
} from "react-native";
interface AlertCustomProps {
children: React.ReactNode;
isVisible: boolean;
}
export default function ModalCustom({
children,
isVisible,
}: AlertCustomProps) {
if (!isVisible) return null;
return (
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.overlay}>
<View style={styles.alertBox}>
<View style={{ width: "100%" }}>{children}</View>
</View>
</View>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
overlay: {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(0,0,0,0.5)",
justifyContent: "center",
alignItems: "center",
zIndex: 999,
paddingVertical: 20,
},
alertBox: {
width: "90%",
backgroundColor: MainColor.darkblue,
borderColor: AccentColor.blue,
borderWidth: 1,
borderRadius: 10,
padding: 20,
alignItems: "center",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
elevation: 5,
},
alertTitle: {
fontSize: TEXT_SIZE_LARGE,
fontWeight: "bold",
marginBottom: 20,
color: MainColor.white_gray,
},
alertMessage: {
textAlign: "center",
marginBottom: 20,
color: MainColor.white_gray,
},
alertButtons: {
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
},
alertButton: {
flex: 1,
padding: 10,
borderRadius: 50,
marginHorizontal: 5,
alignItems: "center",
},
leftButton: {
backgroundColor: "gray",
},
rightButton: {
backgroundColor: MainColor.green,
},
buttonText: {
color: "white",
fontWeight: "bold",
},
});

View File

@@ -28,7 +28,7 @@ function Collaboration_BoxPublishSection({
/> />
<StackCustom> <StackCustom>
<TextCustom truncate={2} size="large" bold align="center"> <TextCustom truncate size="large" bold align="center">
{data?.title || "-"} {data?.title || "-"}
</TextCustom> </TextCustom>
<TextCustom truncate={2}>{data?.purpose || "-"}</TextCustom> <TextCustom truncate={2}>{data?.purpose || "-"}</TextCustom>

View File

@@ -15,10 +15,12 @@ export default function Collaboration_ProjectMainSelectedSection({
selected, selected,
setSelected, setSelected,
setOpenDrawerParticipant, setOpenDrawerParticipant,
listData,
}: { }: {
selected: (string | number)[]; selected: (string | number)[];
setSelected: (value: (string | number)[]) => void; setSelected: (value: (string | number)[]) => void;
setOpenDrawerParticipant: (value: boolean) => void; setOpenDrawerParticipant: (value: boolean) => void;
listData: any[];
}) { }) {
return ( return (
<BaseBox style={{ height: 500 }}> <BaseBox style={{ height: 500 }}>
@@ -31,7 +33,7 @@ export default function Collaboration_ProjectMainSelectedSection({
</TextCustom> </TextCustom>
<CheckboxGroup value={selected} onChange={setSelected}> <CheckboxGroup value={selected} onChange={setSelected}>
{Array.from({ length: 5 }).map((_, index) => ( {listData?.map((item: any, index: any) => (
<View key={index}> <View key={index}>
<Grid key={index}> <Grid key={index}>
<Grid.Col <Grid.Col

View File

@@ -11,9 +11,18 @@ export async function apiCollaborationCreate({ data }: { data: any }) {
} }
} }
export async function apiCollaborationGetAll() { export async function apiCollaborationGetAll({
category,
authorId,
}: {
category: "beranda" | "participant" | "my-project" | "group";
authorId?: string;
}) {
try { try {
const response = await apiConfig.get(`/mobile/collaboration`); const authorQuery = authorId ? `&authorId=${authorId}` : "";
const response = await apiConfig.get(
`/mobile/collaboration?category=${category}${authorQuery}`
);
return response.data; return response.data;
} catch (error) { } catch (error) {
throw error; throw error;
@@ -32,7 +41,6 @@ export async function apiCollaborationGetOne({ id }: { id: string }) {
export async function apiCollaborationCreatePartisipasi({ export async function apiCollaborationCreatePartisipasi({
id, id,
data, data,
}: { }: {
id: string; id: string;
data: any; data: any;
@@ -69,3 +77,40 @@ export async function apiCollaborationGetParticipants({
throw error; throw error;
} }
} }
export async function apiCollaborationCreateGroup({
id,
data,
}: {
id: string;
data: any;
}) {
try {
const response = await apiConfig.post(`/mobile/collaboration/${id}`, {
data: data,
});
return response.data;
} catch (error) {
throw error;
}
}
export async function apiCollaborationEditData({ id, data }: { id: string; data: any }) {
try {
const response = await apiConfig.put(`/mobile/collaboration/${id}`, {
data: data,
});
return response.data;
} catch (error) {
throw error;
}
}
export async function apiCollaborationGroup({ id }: { id: string }) {
try {
const response = await apiConfig.get(`/mobile/collaboration/${id}/group`);
return response.data;
} catch (error) {
throw error;
}
}