From 3199d31d57bd819391781500371c2cb47d31ced5 Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 19 May 2025 17:46:42 +0800 Subject: [PATCH] upd: project Deskripsi: - tambah file pada project kegiatan -nb : blm selesai No Issues --- app/(application)/project/[id]/add-file.tsx | 187 ++++++++++++++++---- app/(application)/project/[id]/index.tsx | 2 +- bun.lockb | Bin 490396 -> 490396 bytes components/project/sectionFile.tsx | 3 +- lib/api.ts | 24 +++ package.json | 2 +- 6 files changed, 178 insertions(+), 40 deletions(-) diff --git a/app/(application)/project/[id]/add-file.tsx b/app/(application)/project/[id]/add-file.tsx index 8d93a69..49c6cc0 100644 --- a/app/(application)/project/[id]/add-file.tsx +++ b/app/(application)/project/[id]/add-file.tsx @@ -2,13 +2,122 @@ import BorderBottomItem from "@/components/borderBottomItem" import ButtonBackHeader from "@/components/buttonBackHeader" import ButtonSaveHeader from "@/components/buttonSaveHeader" import ButtonSelect from "@/components/buttonSelect" +import DrawerBottom from "@/components/drawerBottom" +import MenuItemRow from "@/components/menuItemRow" import Styles from "@/constants/Styles" -import { MaterialCommunityIcons } from "@expo/vector-icons" +import { apiAddFileProject, apiCheckFileProject } from "@/lib/api" +import { setUpdateProject } from "@/lib/projectUpdate" +import { useAuthSession } from "@/providers/AuthProvider" +import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons" +import * as DocumentPicker from "expo-document-picker" import { router, Stack, useLocalSearchParams } from "expo-router" -import { SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native" +import { useState } from "react" +import { ActivityIndicator, SafeAreaView, ScrollView, Text, ToastAndroid, View } from "react-native" +import { useDispatch, useSelector } from "react-redux" export default function ProjectAddFile() { - const { id } = useLocalSearchParams() + const { id } = useLocalSearchParams<{ id: string }>() + const [fileForm, setFileForm] = useState([]) + const [listFile, setListFile] = useState([]) + const [indexDelFile, setIndexDelFile] = useState(0) + const [isModal, setModal] = useState(false) + const { token, decryptToken } = useAuthSession() + const [loadingCheck, setLoadingCheck] = useState(false) + const dispatch = useDispatch() + const update = useSelector((state: any) => state.projectUpdate) + + const pickDocumentAsync = async () => { + let result = await DocumentPicker.getDocumentAsync({ + type: ["*/*"], + multiple: false + }); + if (!result.canceled) { + if (result.assets?.[0].uri) { + const check = await handleCheckFile(result.assets?.[0]) + if (check) { + setFileForm([...fileForm, result.assets?.[0]]) + setListFile([...listFile, result.assets?.[0].name]) + } else { + ToastAndroid.show('File sudah ada', ToastAndroid.SHORT) + } + } + } + }; + + function deleteFile(index: number) { + setListFile([...listFile.filter((val, i) => i !== index)]) + setFileForm([...fileForm.filter((val, i) => i !== index)]) + setModal(false) + } + + async function handleCheckFile(val: any) { + try { + setLoadingCheck(true) + const hasil = await decryptToken(String(token?.current)) + const fd = new FormData(); + + fd.append("file", { + uri: val.uri, + type: val.mimeType, + name: val.fileName, + } as any); + + fd.append( + "data", + JSON.stringify({ + user: hasil, + }) + ); + + const response = await apiCheckFileProject({ data: fd, id: id }) + return response.success + } catch (error) { + console.error(error); + return false + } finally { + setLoadingCheck(false) + } + } + + + async function handleAddFile() { + try { + const hasil = await decryptToken(String(token?.current)) + const fd = new FormData(); + + for (let i = 0; i < fileForm.length; i++) { + fd.append(`file${i}`, { + uri: fileForm[i].uri, + type: fileForm[i].mimeType, + name: fileForm[i].fileName, + } as any); + } + + fd.append( + "data", + JSON.stringify({ + user: hasil, + }) + ); + + console.log(fd) + + const response = await apiAddFileProject({ data: fd, id: id }) + // if (response.success) { + // ToastAndroid.show('Berhasil menambahkan file', ToastAndroid.SHORT) + // dispatch(setUpdateProject({ ...update, file: !update.file })) + // router.back() + // } else { + // ToastAndroid.show(response.message, ToastAndroid.SHORT) + // } + } catch (error) { + console.error(error); + ToastAndroid.show('Terjadi kesalahan', ToastAndroid.SHORT) + } + } + + + return ( @@ -17,46 +126,50 @@ export default function ProjectAddFile() { headerLeft: () => { router.back() }} />, headerTitle: 'Tambah File', headerTitleAlign: 'center', - headerRight: () => { - ToastAndroid.show('Berhasil menambah data', ToastAndroid.SHORT) - router.push('/project/4324') - }} /> + headerRight: () => { handleAddFile() }} /> }} /> - - - File - - } - title="image_pertama.jpg" - titleWeight="normal" - /> - } - title="file_kedua.pdf" - titleWeight="normal" - /> - - - {/* { - AlertKonfirmasi({ - title: 'Konfirmasi', - desc: 'Apakah anda yakin ingin menambahkan data?', - onPress: () => { - ToastAndroid.show('Berhasil menambahkan data', ToastAndroid.SHORT) - router.push('/project/4324') - } - }) - }} /> */} + + { + listFile.length > 0 && ( + + File + + { + listFile.map((item, index) => ( + } + title={item} + titleWeight="normal" + onPress={() => { setIndexDelFile(index); setModal(true) }} + /> + )) + } + + + ) + } + { + loadingCheck && + } + + + } + title="Hapus" + onPress={() => { deleteFile(indexDelFile) }} + /> + + ) } \ No newline at end of file diff --git a/app/(application)/project/[id]/index.tsx b/app/(application)/project/[id]/index.tsx index 45fb2c4..d26c05b 100644 --- a/app/(application)/project/[id]/index.tsx +++ b/app/(application)/project/[id]/index.tsx @@ -78,7 +78,7 @@ export default function DetailProject() { { router.back() }} />, - headerTitle: loading ? '' : data?.title, + headerTitle: loading ? 'Loading...' : data?.title, headerTitleAlign: 'center', headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMember ? null : , }} diff --git a/bun.lockb b/bun.lockb index a5742bd4e8db266309bcc0aecd596d7a04d0ba7f..4bb6edbe3b2c47faad7211c7151b937602e9ea74 100755 GIT binary patch delta 40 qcmbR9U3SiQ*@hOz7N!>FEi9!+IhYtApuP4e3lOtzuRY2pzYPE-gbm&R delta 40 ucmbR9U3SiQ*@hOz7N!>FEi9!+IT+&%jr9!ljN5CEvH&sb_S&Ot^4kDG3J+cY diff --git a/components/project/sectionFile.tsx b/components/project/sectionFile.tsx index 04bc169..261912e 100644 --- a/components/project/sectionFile.tsx +++ b/components/project/sectionFile.tsx @@ -24,6 +24,7 @@ export default function SectionFile({ status, member }: { status: number | undef const { token, decryptToken } = useAuthSession(); const { id } = useLocalSearchParams<{ id: string }>(); const [data, setData] = useState([]); + const update = useSelector((state: any) => state.projectUpdate) async function handleLoad() { try { @@ -41,7 +42,7 @@ export default function SectionFile({ status, member }: { status: number | undef useEffect(() => { handleLoad(); - }, []); + }, [update.file]); return ( <> diff --git a/lib/api.ts b/lib/api.ts index bbda427..bf7aeb1 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -320,4 +320,28 @@ export const apiCreateProject = async (data: FormData) => { export const apiDeleteProject = async (data: { user: string }, id: string) => { const response = await api.delete(`/mobile/project/${id}/lainnya`, { data }) return response.data; +}; + +export const apiAddFileProject = async ({ data, id }: { data: FormData, id: string }) => { + console.log('apiAddFileProject') + const response = await api.post(`/mobile/project/file/${id}`, data, + { + headers: { + 'Content-Type': 'multipart/form-data', + }, + } + ) + console.log(response) + return response.data; +}; + +export const apiCheckFileProject = async ({ data, id }: { data: FormData, id: string }) => { + const response = await api.put(`/mobile/project/file/${id}`, data, + { + headers: { + 'Content-Type': 'multipart/form-data', + }, + } + ) + return response.data; }; \ No newline at end of file diff --git a/package.json b/package.json index 940b3d5..cde28b0 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "expo": "^53.0.9", "expo-blur": "~14.1.4", "expo-constants": "~17.1.6", - "expo-document-picker": "^13.0.3", + "expo-document-picker": "^13.1.5", "expo-file-system": "~18.1.10", "expo-font": "~13.3.1", "expo-haptics": "~14.1.4",