From dee684fb887afc13c0ac04332e637a613a123f9e Mon Sep 17 00:00:00 2001 From: amel Date: Wed, 7 May 2025 14:30:55 +0800 Subject: [PATCH] upd: diskusi umum - tambah diskusi umum - tambah member pada diskusi umum No Issues --- .../discussion/add-member/[id].tsx | 163 ++++++++++++++++++ app/(application)/discussion/create.tsx | 98 +++++++++-- app/(application)/discussion/index.tsx | 3 +- app/(application)/discussion/member/[id].tsx | 5 +- components/inputSearch.tsx | 3 +- components/modalSelect.tsx | 48 ++++-- lib/api.ts | 12 ++ 7 files changed, 296 insertions(+), 36 deletions(-) create mode 100644 app/(application)/discussion/add-member/[id].tsx diff --git a/app/(application)/discussion/add-member/[id].tsx b/app/(application)/discussion/add-member/[id].tsx new file mode 100644 index 0000000..2770a41 --- /dev/null +++ b/app/(application)/discussion/add-member/[id].tsx @@ -0,0 +1,163 @@ +import ButtonBackHeader from "@/components/buttonBackHeader"; +import ButtonSaveHeader from "@/components/buttonSaveHeader"; +import ImageUser from "@/components/imageNew"; +import ImageWithLabel from "@/components/imageWithLabel"; +import InputSearch from "@/components/inputSearch"; +import Styles from "@/constants/Styles"; +import { apiAddMemberDiscussionGeneral, apiGetDiscussionGeneralOne, apiGetUser } from "@/lib/api"; +import { setUpdateDiscussionGeneralDetail } from "@/lib/discussionGeneralDetail"; +import { useAuthSession } from "@/providers/AuthProvider"; +import { AntDesign } from "@expo/vector-icons"; +import { router, Stack, useLocalSearchParams } from "expo-router"; +import { useEffect, useState } from "react"; +import { Pressable, SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native"; +import { useDispatch, useSelector } from "react-redux"; + +type Props = { + idUser: string, + name: string, + img: string +} + +export default function AddMemberDiscussionDetail() { + const dispatch = useDispatch() + const update = useSelector((state: any) => state.discussionGeneralDetailUpdate) + const { token, decryptToken } = useAuthSession() + const { id } = useLocalSearchParams<{ id: string }>() + const [dataOld, setDataOld] = useState([]) + const [data, setData] = useState([]) + const [idGroup, setIdGroup] = useState('') + const [selectMember, setSelectMember] = useState([]) + const [search, setSearch] = useState('') + + async function handleLoad() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetDiscussionGeneralOne({ id: id, user: hasil, cat: 'anggota' }) + setDataOld(response.data) + const responseGroup = await apiGetDiscussionGeneralOne({ id: id, user: hasil, cat: 'detail' }) + setIdGroup(responseGroup.data.idGroup) + } catch (error) { + console.error(error) + } + } + + async function handleLoadMember() { + const hasil = await decryptToken(String(token?.current)) + const response = await apiGetUser({ user: hasil, active: "true", search: search, group: String(idGroup) }) + setData(response.data.filter((i: any) => i.idUserRole != 'supadmin')) + } + + + useEffect(() => { + handleLoad() + }, []); + + + useEffect(() => { + handleLoadMember() + }, [search]) + + function onChoose(val: string, label: string, img?: string) { + if (selectMember.some((i: any) => i.idUser == val)) { + setSelectMember(selectMember.filter((i: any) => i.idUser != val)) + } else { + setSelectMember([...selectMember, { idUser: val, name: label, img }]) + } + } + + async function handleAddMember() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiAddMemberDiscussionGeneral({ id: id, data: { user: hasil, member: selectMember } }) + if (response.success) { + ToastAndroid.show('Berhasil menambahkan anggota', ToastAndroid.SHORT) + dispatch(setUpdateDiscussionGeneralDetail(!update)) + router.back() + } + } catch (error) { + console.error(error) + } + } + + + return ( + + { router.back() }} />, + headerTitle: 'Tambah Anggota Diskusi', + headerTitleAlign: 'center', + headerRight: () => ( + 0 ? false : true} + onPress={() => { + handleAddMember() + }} + /> + ) + }} + /> + + + + { + selectMember.length > 0 + ? + + + { + selectMember.map((item: any, index: any) => ( + onChoose(item.idUser, item.name, item.img)} + /> + )) + } + + + + : + Tidak ada member yang dipilih + } + + + { + data.length > 0 ? + data.map((item: any, index: any) => { + const found = dataOld.some((i: any) => i.idUser == item.id) + return ( + { + !found && onChoose(item.id, item.name, item.img) + }} + > + + + + {item.name} + { + found && sudah menjadi anggota + } + + + { + selectMember.some((i: any) => i.idUser == item.id) && + } + + ) + } + ) + : + Tidak ada data + } + + + + ) +} \ No newline at end of file diff --git a/app/(application)/discussion/create.tsx b/app/(application)/discussion/create.tsx index 513c715..c7ba99b 100644 --- a/app/(application)/discussion/create.tsx +++ b/app/(application)/discussion/create.tsx @@ -1,27 +1,32 @@ +import BorderBottomItem from "@/components/borderBottomItem"; import ButtonBackHeader from "@/components/buttonBackHeader"; import ButtonSaveHeader from "@/components/buttonSaveHeader"; import ButtonSelect from "@/components/buttonSelect"; +import ImageUser from "@/components/imageNew"; import { InputForm } from "@/components/inputForm"; import ModalSelect from "@/components/modalSelect"; import SelectForm from "@/components/selectForm"; import Styles from "@/constants/Styles"; +import { apiCreateDiscussionGeneral } from "@/lib/api"; +import { setUpdateDiscussionGeneralDetail } from "@/lib/discussionGeneralDetail"; +import { setMemberChoose } from "@/lib/memberChoose"; +import { useAuthSession } from "@/providers/AuthProvider"; import { router, Stack } from "expo-router"; import { useEffect, useState } from "react"; -import { SafeAreaView, ScrollView, ToastAndroid, View } from "react-native"; +import { SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native"; +import { useDispatch, useSelector } from "react-redux"; -type Props = { - idUser: string; - name: string; - img: string; -}; export default function CreateDiscussionGeneral() { + const { token, decryptToken } = useAuthSession() const [chooseGroup, setChooseGroup] = useState({ val: "", label: "" }); const [valChoose, setValChoose] = useState("") const [valSelect, setValSelect] = useState<"group" | "member">("group"); - const [member, setMember] = useState([]); + const dispatch = useDispatch() const [disableBtn, setDisableBtn] = useState(true); const [isSelect, setSelect] = useState(false); + const entitiesMember = useSelector((state: any) => state.memberChoose) + const update = useSelector((state: any) => state.discussionGeneralDetailUpdate) const [dataForm, setDataForm] = useState({ idGroup: "", title: "", @@ -36,7 +41,7 @@ export default function CreateDiscussionGeneral() { function validationForm(cat: string, val: any, label?: string) { if (cat == "group") { setChooseGroup({ val, label: String(label) }); - setMember([]); + dispatch(setMemberChoose([])) setDataForm({ ...dataForm, idGroup: val }); if (val == "" || val == "null") { setError({ ...error, group: true }); @@ -75,15 +80,36 @@ export default function CreateDiscussionGeneral() { checkForm(); }, [error, dataForm]); + + function handleBack() { + dispatch(setMemberChoose([])) + router.back() + } + + async function handleCreate() { + try { + const hasil = await decryptToken(String(token?.current)) + const response = await apiCreateDiscussionGeneral({ + data: { ...dataForm, user: hasil, member: entitiesMember }, + }) + if (response.success) { + dispatch(setMemberChoose([])) + dispatch(setUpdateDiscussionGeneralDetail(!update)) + ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT) + router.back() + } + } catch (error) { + console.error(error); + } + } + return ( ( { - router.back(); - }} + onPress={() => { handleBack() }} /> ), headerTitle: "Tambah Diskusi", @@ -93,11 +119,12 @@ export default function CreateDiscussionGeneral() { category="create" disable={disableBtn} onPress={() => { - ToastAndroid.show( - "Berhasil menambahkan data", - ToastAndroid.SHORT - ); - router.push("/discussion?active=true"); + entitiesMember.length == 0 + ? ToastAndroid.show( + "Anda belum memilih anggota", + ToastAndroid.SHORT + ) + : handleCreate() }} /> ), @@ -116,12 +143,23 @@ export default function CreateDiscussionGeneral() { setSelect(true); }} /> - + { validationForm("title", val) }} + /> { validationForm("desc", val) }} /> + { + entitiesMember.length > 0 && + + + Anggota + Total {entitiesMember.length} Anggota + + + + { + entitiesMember.map((item: { img: any; name: any; }, index: any) => { + return ( + + } + title={item.name} + /> + ) + }) + } + + + } diff --git a/app/(application)/discussion/index.tsx b/app/(application)/discussion/index.tsx index f4c999e..b811bed 100644 --- a/app/(application)/discussion/index.tsx +++ b/app/(application)/discussion/index.tsx @@ -29,6 +29,7 @@ export default function Discussion() { const [search, setSearch] = useState('') const [nameGroup, setNameGroup] = useState('') const [data, setData] = useState([]) + const update = useSelector((state: any) => state.discussionGeneralDetailUpdate) async function handleLoad() { try { @@ -43,7 +44,7 @@ export default function Discussion() { useEffect(() => { handleLoad() - }, [active, search, group]) + }, [active, search, group, update]) return ( diff --git a/app/(application)/discussion/member/[id].tsx b/app/(application)/discussion/member/[id].tsx index d3c3158..52d5bca 100644 --- a/app/(application)/discussion/member/[id].tsx +++ b/app/(application)/discussion/member/[id].tsx @@ -27,6 +27,7 @@ export default function MemberDiscussionDetail() { const [data, setData] = useState([]) const [isModal, setModal] = useState(false) const [chooseUser, setChooseUser] = useState({ idUser: '', name: '', img: '' }) + const update = useSelector((state: any) => state.discussionGeneralDetailUpdate) async function handleLoad() { try { @@ -41,7 +42,7 @@ export default function MemberDiscussionDetail() { useEffect(() => { handleLoad() - }, []); + }, [update]); async function handleDeleteUser() { try { @@ -56,7 +57,6 @@ export default function MemberDiscussionDetail() { } } - return ( { router.push(`/discussion/add-member/${id}`) }} borderType="none" icon={ diff --git a/components/inputSearch.tsx b/components/inputSearch.tsx index adf43dc..b40100b 100644 --- a/components/inputSearch.tsx +++ b/components/inputSearch.tsx @@ -1,7 +1,7 @@ import { Feather } from "@expo/vector-icons"; import { InputForm } from "./inputForm"; -export default function InputSearch({ onChange, width }: { onChange?: (val: string) => void, width?: number }) { +export default function InputSearch({ onChange, width, value }: { onChange?: (val: string) => void, width?: number, value?: string }) { return ( ) } \ No newline at end of file diff --git a/components/modalSelect.tsx b/components/modalSelect.tsx index 0a06fea..665f8ea 100644 --- a/components/modalSelect.tsx +++ b/components/modalSelect.tsx @@ -3,11 +3,13 @@ import { valueRoleUser } from "@/constants/RoleUser" import Styles from "@/constants/Styles" import { apiGetGroup, apiGetPosition, apiGetUser } from "@/lib/api" import { setEntityFilterGroup } from "@/lib/filterSlice" +import { setMemberChoose } from "@/lib/memberChoose" import { useAuthSession } from "@/providers/AuthProvider" import { AntDesign } from "@expo/vector-icons" import { useEffect, useState } from "react" import { Pressable, ScrollView, Text, View } from "react-native" import { useDispatch, useSelector } from "react-redux" +import { ButtonForm } from "./buttonForm" import DrawerBottom from "./drawerBottom" import ImageUser from "./imageNew" import ImageWithLabel from "./imageWithLabel" @@ -84,7 +86,7 @@ export default function ModalSelect({ open, close, title, category, idParent, on handleLoadMember() } setChooseValue({ ...chooseValue, val: valChoose }) - }, [dispatch, open]); + }, [dispatch, open, search]); function onChoose(val: string, label: string, img?: string) { if (category == "member") { @@ -100,29 +102,37 @@ export default function ModalSelect({ open, close, title, category, idParent, on } } + function handleChooseMember() { + dispatch(setMemberChoose(selectMember)) + close(false) + } + return ( { category == 'member' && <> - + { selectMember.length > 0 ? - - { - selectMember.map((item: any, index: any) => ( - onChoose(item.idUser, item.name, item.img)} - /> - )) - } - + + + { + selectMember.map((item: any, index: any) => ( + onChoose(item.idUser, item.name, item.img)} + /> + )) + } + + + : - Tidak ada member yang dipilih + Tidak ada member yang dipilih } } @@ -171,6 +181,14 @@ export default function ModalSelect({ open, close, title, category, idParent, on + { + category == 'member' && + { handleChooseMember() }} + text="PILIH MEMBER" + disabled={selectMember.length == 0} + /> + } ) } \ No newline at end of file diff --git a/lib/api.ts b/lib/api.ts index a1f5b93..749a9c5 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -191,3 +191,15 @@ export const apiEditDiscussionGeneral = async (data: { user: string, title: stri const response = await api.put(`/mobile/discussion-general/${id}`, data) return response.data; }; + +export const apiCreateDiscussionGeneral = async ({ data }: { data: { idGroup: string, title: string, desc: string, user: string, member: [] } }) => { + const response = await api.post(`/mobile/discussion-general/`, data) + return response.data; +}; + + +export const apiAddMemberDiscussionGeneral = async ({ data, id }: { data: { user: string, member: any[] }, id: string }) => { + const response = await api.post(`/mobile/discussion-general/${id}/member`, data) + return response.data; +}; +