From e61fb83bfddfe6421ff49923b1c64324610a5c59 Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Mon, 19 Jan 2026 15:07:14 +0800 Subject: [PATCH 1/2] upd: revisi diskusi divisi Deskripsi: - attachment file pada tambah diskusi divisi - attachment file pada edit diskus divisi - attachment file pada detail diskusi divisi No Issues --- app/(application)/discussion/[id].tsx | 1 + .../discussion/[detail]/edit.tsx | 66 ++++++++++++++++--- .../discussion/[detail]/index.tsx | 17 +++++ .../(fitur-division)/discussion/create.tsx | 18 ++++- lib/api.ts | 28 ++++++-- 5 files changed, 114 insertions(+), 16 deletions(-) diff --git a/app/(application)/discussion/[id].tsx b/app/(application)/discussion/[id].tsx index 0fac982..d478b73 100644 --- a/app/(application)/discussion/[id].tsx +++ b/app/(application)/discussion/[id].tsx @@ -135,6 +135,7 @@ export default function DetailDiscussionGeneral() { handleLoad('detail', false) handleLoad('komentar', false) handleLoad('cek-anggota', false) + handleLoad('file', false) }, [update]); useEffect(() => { diff --git a/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/edit.tsx b/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/edit.tsx index 60d1fe5..bcae0b4 100644 --- a/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/edit.tsx +++ b/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/edit.tsx @@ -27,7 +27,9 @@ export default function DiscussionDivisionEdit() { const [loading, setLoading] = useState(false) const [fileForm, setFileForm] = useState([]) const [isModalFile, setModalFile] = useState(false) - const [indexDelFile, setIndexDelFile] = useState(0) + const [indexDelFile, setIndexDelFile] = useState<{ id: string | number; cat: "newFile" | "oldFile" }>({ id: "", cat: "newFile" }) + const [dataFile, setDataFile] = useState<{ id: string; idStorage: string; name: string; extension: string; delete?: boolean }[]>([]) + async function handleLoad() { try { @@ -37,6 +39,12 @@ export default function DiscussionDivisionEdit() { user: hasil, cat: "data", }); + const response2 = await apiGetDiscussionOne({ + id: detail, + user: hasil, + cat: "file", + }); + setDataFile(response2.data); setData(response.data.desc); } catch (error) { console.error(error); @@ -51,10 +59,26 @@ export default function DiscussionDivisionEdit() { try { setLoading(true) const hasil = await decryptToken(String(token?.current)); - const response = await apiEditDiscussion({ - data: { user: hasil, desc: data }, - id: detail, - }); + const fd = new FormData() + for (let i = 0; i < fileForm.length; i++) { + fd.append(`file${i}`, { + uri: fileForm[i].uri, + type: 'application/octet-stream', + name: fileForm[i].name, + } as any); + } + + fd.append("data", JSON.stringify( + { + user: hasil, desc: data, oldFile: dataFile + } + )) + const response = await apiEditDiscussion(fd, detail); + + // const response = await apiEditDiscussion({ + // data: { user: hasil, desc: data }, + // id: detail, + // }); if (response.success) { Toast.show({ type: 'small', text1: 'Berhasil mengubah data', }) dispatch(setUpdateDiscussion({ ...update, data: !update.data })); @@ -86,8 +110,18 @@ export default function DiscussionDivisionEdit() { - function deleteFile(index: number) { - setFileForm([...fileForm.filter((val, i) => i !== index)]) + function deleteFile(index: number | string, cat: "newFile" | "oldFile" | null) { + if (cat == "newFile") { + setFileForm([...fileForm.filter((val, i) => i !== index)]) + } else { + setDataFile(prev => + prev.map(item => + item.id === index + ? { ...item, delete: true } + : item + ) + ); + } setModalFile(false) } @@ -129,10 +163,22 @@ export default function DiscussionDivisionEdit() { { - fileForm.length > 0 + (fileForm.length > 0 || dataFile.filter((val) => !val.delete).length > 0) && File + { + dataFile.filter((val) => !val.delete).map((item, index) => ( + 1 ? "bottom" : "none"} + icon={} + title={item.name + '.' + item.extension} + titleWeight="normal" + onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }} + /> + )) + } { fileForm.map((item, index) => ( } title={item.name} titleWeight="normal" - onPress={() => { setIndexDelFile(index); setModalFile(true) }} + onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }} /> )) } @@ -156,7 +202,7 @@ export default function DiscussionDivisionEdit() { } title="Hapus" - onPress={() => { deleteFile(indexDelFile) }} + onPress={() => { deleteFile(indexDelFile.id, indexDelFile.cat) }} /> diff --git a/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/index.tsx b/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/index.tsx index 12a3132..c5f0885 100644 --- a/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/index.tsx +++ b/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/index.tsx @@ -56,10 +56,18 @@ type PropsComment = { updatedAt: string; }; +type PropsFile = { + id: string; + idStorage: string; + name: string; + extension: string +} + export default function DiscussionDetail() { const { id, detail } = useLocalSearchParams<{ id: string; detail: string }>(); const [data, setData] = useState(); const [dataComment, setDataComment] = useState([]); + const [fileDiscussion, setFileDiscussion] = useState([]) const { token, decryptToken } = useAuthSession(); const [komentar, setKomentar] = useState(""); const [loadingSend, setLoadingSend] = useState(false); @@ -114,7 +122,15 @@ export default function DiscussionDetail() { user: hasil, cat: "data", }); + + const responseFile = await apiGetDiscussionOne({ + id: detail, + user: hasil, + cat: "file", + }); + setData(response.data); + setFileDiscussion(responseFile.data) setIsCreator(response.data.createdBy == hasil); } catch (error) { console.error(error); @@ -290,6 +306,7 @@ export default function DiscussionDetail() { : { +export const apiGetDiscussionOne = async ({ id, user, cat }: { id: string, user: string, cat: 'data' | 'comment' | 'file' }) => { const response = await api.get(`mobile/discussion/${id}?user=${user}&cat=${cat}`); return response.data; }; @@ -517,8 +517,17 @@ export const apiDeleteDiscussionCommentar = async ({ data, id }: { data: { user: return response.data; }; -export const apiEditDiscussion = async ({ data, id }: { data: { user: string, desc: string }, id: string }) => { - const response = await api.post(`/mobile/discussion/${id}`, data) +// export const apiEditDiscussion = async ({ data, id }: { data: { user: string, desc: string }, id: string }) => { +// const response = await api.post(`/mobile/discussion/${id}`, data) +// return response.data; +// }; + +export const apiEditDiscussion = async (data: FormData, id: string) => { + const response = await api.post(`/mobile/discussion/${id}`, data, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }) return response.data; }; @@ -532,8 +541,17 @@ export const apiOpenCloseDiscussion = async (data: { user: string, status: numbe return response.data }; -export const apiCreateDiscussion = async ({ data }: { data: { user: string, desc: string, idDivision: string } }) => { - const response = await api.post(`/mobile/discussion`, data) +// export const apiCreateDiscussion = async ({ data }: { data: { user: string, desc: string, idDivision: string } }) => { +// const response = await api.post(`/mobile/discussion`, data) +// return response.data; +// }; + +export const apiCreateDiscussion = async (data: FormData) => { + const response = await api.post(`/mobile/discussion`, data, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }) return response.data; }; From 588df062f1a7c2b4b53ff63b541120583c91d402 Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Mon, 19 Jan 2026 16:36:37 +0800 Subject: [PATCH 2/2] upd: loading overlay Deskripsi: - update loading saat aksi tambah dan edit pada fitur pengumuman, diskusi umum dan diskusi divisi No Issues --- app/(application)/announcement/create.tsx | 2 + app/(application)/announcement/edit/[id].tsx | 2 + app/(application)/discussion/create.tsx | 2 + app/(application)/discussion/edit/[id].tsx | 2 + .../discussion/[detail]/edit.tsx | 4 +- .../(fitur-division)/discussion/create.tsx | 4 +- components/loadingOverlay.tsx | 50 +++++++++++++++++++ 7 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 components/loadingOverlay.tsx diff --git a/app/(application)/announcement/create.tsx b/app/(application)/announcement/create.tsx index 1f26731..8c87664 100644 --- a/app/(application)/announcement/create.tsx +++ b/app/(application)/announcement/create.tsx @@ -4,6 +4,7 @@ import ButtonSaveHeader from "@/components/buttonSaveHeader"; import ButtonSelect from "@/components/buttonSelect"; import DrawerBottom from "@/components/drawerBottom"; import { InputForm } from "@/components/inputForm"; +import LoadingOverlay from "@/components/loadingOverlay"; import MenuItemRow from "@/components/menuItemRow"; import ModalSelectMultiple from "@/components/modalSelectMultiple"; import Text from "@/components/Text"; @@ -153,6 +154,7 @@ export default function CreateAnnouncement() { ), }} /> + + + { diff --git a/app/(application)/discussion/edit/[id].tsx b/app/(application)/discussion/edit/[id].tsx index 340a400..23ff533 100644 --- a/app/(application)/discussion/edit/[id].tsx +++ b/app/(application)/discussion/edit/[id].tsx @@ -5,6 +5,7 @@ import ButtonSaveHeader from "@/components/buttonSaveHeader"; import ButtonSelect from "@/components/buttonSelect"; import DrawerBottom from "@/components/drawerBottom"; import { InputForm } from "@/components/inputForm"; +import LoadingOverlay from "@/components/loadingOverlay"; import MenuItemRow from "@/components/menuItemRow"; import Styles from "@/constants/Styles"; import { apiEditDiscussionGeneral, apiGetDiscussionGeneralOne } from "@/lib/api"; @@ -182,6 +183,7 @@ export default function EditDiscussionGeneral() { ), }} /> + - + + }} /> - + + + + + {text} + + + ); +} + +const styles = StyleSheet.create({ + overlay: { + ...StyleSheet.absoluteFillObject, + backgroundColor: "rgba(0,0,0,0.35)", + justifyContent: "center", + alignItems: "center", + zIndex: 9999, + }, + box: { + paddingVertical: 5, + paddingHorizontal: 15, + backgroundColor: "#fff", + borderRadius: 8, + alignItems: "center", + elevation: 6, // Android + shadowColor: "#000", // iOS + shadowOpacity: 0.25, + shadowRadius: 5, + shadowOffset: { width: 0, height: 4 }, + }, + text: { + marginTop: 5, + fontSize: 14, + color: "#2c3e50", + }, +});