upd: dokumen divisi

Deskripsi:
- move dokumen divisi
- copy dokumen divisi
- share dokumen divisi

NO issues
This commit is contained in:
amel
2025-06-02 14:32:32 +08:00
parent 572db6f5d1
commit d9a9c821ea
7 changed files with 308 additions and 119 deletions

View File

@@ -8,9 +8,15 @@ import DrawerBottom from "@/components/drawerBottom";
import { InputForm } from "@/components/inputForm";
import MenuItemRow from "@/components/menuItemRow";
import ModalFloat from "@/components/modalFloat";
import ModalSelectMultiple from "@/components/modalSelectMultiple";
import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles";
import { apiDocumentDelete, apiDocumentRename, apiGetDocument } from "@/lib/api";
import {
apiDocumentDelete,
apiDocumentRename,
apiGetDocument,
apiShareDocument,
} from "@/lib/api";
import { setUpdateDokumen } from "@/lib/dokumenUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import {
@@ -49,6 +55,7 @@ type PropsPath = {
};
export default function DocumentDivision() {
const [isShare, setShare] = useState(false);
const { token, decryptToken } = useAuthSession();
const { id } = useLocalSearchParams<{ id: string }>();
const [path, setPath] = useState("home");
@@ -61,7 +68,7 @@ export default function DocumentDivision() {
const [copyAllowed, setCopyAllowed] = useState(true);
const [modalMore, setModalMore] = useState(false);
const [isRename, setRename] = useState(false);
const dispatch = useDispatch()
const dispatch = useDispatch();
const update = useSelector((state: any) => state.dokumenUpdate);
const [bodyRename, setBodyRename] = useState({
id: "",
@@ -181,37 +188,67 @@ export default function DocumentDivision() {
async function handleRename() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiDocumentRename({ user: hasil, ...bodyRename })
const hasil = await decryptToken(String(token?.current));
const response = await apiDocumentRename({ user: hasil, ...bodyRename });
if (response.success) {
ToastAndroid.show("Berhasil mengubah nama", ToastAndroid.SHORT)
dispatch(setUpdateDokumen(!update))
handleBatal()
ToastAndroid.show("Berhasil mengubah nama", ToastAndroid.SHORT);
dispatch(setUpdateDokumen(!update));
handleBatal();
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT)
ToastAndroid.show(response.message, ToastAndroid.SHORT);
}
} catch (error) {
console.error(error)
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT)
console.error(error);
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT);
} finally {
setRename(false)
setRename(false);
}
}
async function handleDelete() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiDocumentDelete({ user: hasil, data: selectedFiles })
const hasil = await decryptToken(String(token?.current));
const response = await apiDocumentDelete({
user: hasil,
data: selectedFiles,
});
if (response.success) {
ToastAndroid.show("Berhasil menghapus", ToastAndroid.SHORT)
dispatch(setUpdateDokumen(!update))
handleBatal()
ToastAndroid.show("Berhasil menghapus", ToastAndroid.SHORT);
dispatch(setUpdateDokumen(!update));
handleBatal();
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT)
ToastAndroid.show(response.message, ToastAndroid.SHORT);
}
} catch (error) {
console.error(error)
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT)
console.error(error);
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT);
}
}
useEffect(() => {
handleBatal();
}, [update]);
async function handleShare(selectedDivision: any[]) {
try {
const hasil = await decryptToken(String(token?.current));
const response = await apiShareDocument({
user: hasil,
dataDivision: selectedDivision,
dataItem: selectedFiles,
});
if (response.success) {
ToastAndroid.show("Berhasil membagikan item", ToastAndroid.SHORT);
dispatch(setUpdateDokumen(!update));
handleBatal();
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT);
}
} catch (error) {
console.error(error);
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT);
} finally {
setShare(false);
}
}
@@ -352,7 +389,7 @@ export default function DocumentDivision() {
title: "Konfirmasi",
desc: "Apakah anda yakin ingin menghapus dokumen?",
onPress: () => {
handleDelete()
handleDelete();
},
});
}}
@@ -385,7 +422,9 @@ export default function DocumentDivision() {
/>
}
title="Bagikan"
onPress={() => { }}
onPress={() => {
setShare(true);
}}
column="many"
color="white"
disabled={selectedFiles.length != 1 || shareSelected}
@@ -434,7 +473,9 @@ export default function DocumentDivision() {
title="Ganti Nama"
isVisible={isRename}
setVisible={setRename}
onSubmit={() => { handleRename() }}
onSubmit={() => {
handleRename();
}}
disableSubmit={bodyRename.name == ""}
>
<View>
@@ -448,6 +489,19 @@ export default function DocumentDivision() {
/>
</View>
</ModalFloat>
<ModalSelectMultiple
choose="dinas"
title="Bagikan"
category="share-division"
open={isShare}
close={setShare}
onSelect={(value) => {
handleShare(value)
}}
value={id}
item={selectedFiles[0]?.id}
/>
</SafeAreaView>
);
}

View File

@@ -208,7 +208,7 @@ export default function MenuBottomSelectDocument({ onDone }: Props) {
setShare(false)
}}
/>
<ModalSalinMove open={isMoveCopy} close={setMoveCopy} category={valMoveCopy} onConfirm={(value: string) => { }} />
<ModalSalinMove open={isMoveCopy} close={setMoveCopy} category={valMoveCopy} onConfirm={(value: string) => { }} dataChoose={[]} />
</>
)
}

View File

@@ -1,8 +1,9 @@
import Styles from "@/constants/Styles";
import { apiMoveDocument } from "@/lib/api";
import { apiCopyDocument, apiMoveDocument } from "@/lib/api";
import { setUpdateDokumen } from "@/lib/dokumenUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { ToastAndroid, View } from "react-native";
import { useDispatch, useSelector } from "react-redux";
@@ -22,90 +23,159 @@ type Props = {
createdBy: string;
createdAt: string;
updatedAt: string;
}
};
export default function ModalMore({ onClose, data, share }: { onClose: () => void, data: Props[], share: boolean }) {
const [isInformasi, setInformasi] = useState(false)
const [isCut, setIsCut] = useState(false)
const [isCopy, setIsCopy] = useState(false)
const [forbidCopy, setForbidCopy] = useState(true)
const [nFileSelected, setNFileSelected] = useState(0)
const { token, decryptToken } = useAuthSession()
const dispatch = useDispatch()
const update = useSelector((state: any) => state.dokumenUpdate)
const [isMoveCopy, setMoveCopy] = useState(false)
export default function ModalMore({
onClose,
data,
share,
}: {
onClose: () => void;
data: Props[];
share: boolean;
}) {
const { id } = useLocalSearchParams<{ id: string }>();
const [isInformasi, setInformasi] = useState(false);
const [isCut, setIsCut] = useState(false);
const [isCopy, setIsCopy] = useState(false);
const [forbidCopy, setForbidCopy] = useState(true);
const [nFileSelected, setNFileSelected] = useState(0);
const { token, decryptToken } = useAuthSession();
const dispatch = useDispatch();
const update = useSelector((state: any) => state.dokumenUpdate);
function cekFileSelected() {
const cek = data.some((i: any) => i.category == "FOLDER")
setForbidCopy(cek)
setNFileSelected(data.length)
const cek = data.some((i: any) => i.category == "FOLDER");
setForbidCopy(cek);
setNFileSelected(data.length);
}
useEffect(() => {
cekFileSelected()
}, [data])
cekFileSelected();
}, [data]);
async function handleMove(path: string) {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiMoveDocument({ user: hasil, dataItem: data, path })
const hasil = await decryptToken(String(token?.current));
const response = await apiMoveDocument({
user: hasil,
dataItem: data,
path,
});
if (response.success) {
ToastAndroid.show("Berhasil memindahkan file", ToastAndroid.SHORT)
dispatch(setUpdateDokumen(!update))
ToastAndroid.show("Berhasil memindahkan file", ToastAndroid.SHORT);
dispatch(setUpdateDokumen(!update));
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT)
ToastAndroid.show(response.message, ToastAndroid.SHORT);
}
} catch (error) {
console.error(error)
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT)
console.error(error);
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT);
} finally {
setMoveCopy(false)
onClose()
setIsCut(false);
onClose();
}
}
async function handleCopy(path: string) {
try {
const hasil = await decryptToken(String(token?.current));
const response = await apiCopyDocument({
user: hasil,
dataItem: data,
path,
idDivision: id
});
if (response.success) {
ToastAndroid.show("Berhasil menyalin file", ToastAndroid.SHORT);
dispatch(setUpdateDokumen(!update));
} else {
ToastAndroid.show(response.message, ToastAndroid.SHORT);
}
} catch (error) {
console.error(error);
ToastAndroid.show("Terjadi kesalahan", ToastAndroid.SHORT);
} finally {
setIsCopy(false);
onClose();
}
}
return (
<>
<View style={Styles.rowItemsCenter}>
{
!share &&
{!share && (
<MenuItemRow
icon={<MaterialCommunityIcons name="folder-move-outline" color="black" size={25} />}
icon={
<MaterialCommunityIcons
name="folder-move-outline"
color="black"
size={25}
/>
}
title="Pindah"
onPress={() => {
setMoveCopy(true)
setIsCut(true);
}}
/>
}
{
!forbidCopy &&
)}
{!forbidCopy && (
<MenuItemRow
icon={<MaterialCommunityIcons name="folder-multiple-outline" color="black" size={25} />}
icon={
<MaterialCommunityIcons
name="folder-multiple-outline"
color="black"
size={25}
/>
}
title="Salin"
onPress={() => {
// handleMoveCopy('copy')
setIsCopy(true);
}}
/>
}
{
nFileSelected == 1 &&
)}
{nFileSelected == 1 && (
<MenuItemRow
icon={<MaterialCommunityIcons name="information-variant" color="black" size={25} />}
icon={
<MaterialCommunityIcons
name="information-variant"
color="black"
size={25}
/>
}
title="Informasi"
onPress={() => {
// onClose()
setInformasi(true)
setInformasi(true);
}}
/>
}
)}
</View>
<DrawerBottom animation="slide" isVisible={isInformasi} setVisible={setInformasi} title="Informasi Dokumen" height={80}>
<DrawerBottom
animation="slide"
isVisible={isInformasi}
setVisible={setInformasi}
title="Informasi Dokumen"
height={80}
>
<ModalInformasi data={data[0]} />
</DrawerBottom>
<ModalSalinMove open={isMoveCopy} close={() => setMoveCopy(false)} category={'move'} onConfirm={(value: string) => handleMove(value)} />
<ModalSalinMove
open={isCut}
close={() => setIsCut(false)}
category={"move"}
onConfirm={(value: string) => handleMove(value)}
dataChoose={data}
/>
<ModalSalinMove
open={isCopy}
close={() => setIsCopy(false)}
category={"copy"}
onConfirm={(value: string) => handleCopy(value)}
dataChoose={data}
/>
</>
)
}
);
}

View File

@@ -13,6 +13,7 @@ type Props = {
close: (value: boolean) => void
category: 'copy' | 'move'
onConfirm: (value: string) => void
dataChoose: any[]
}
type DataProps = {
@@ -33,7 +34,7 @@ type PropsPath = {
name: string;
};
export default function ModalSalinMove({ open, close, category, onConfirm }: Props) {
export default function ModalSalinMove({ open, close, category, onConfirm, dataChoose }: Props) {
const [data, setData] = useState<DataProps[]>([])
const { token, decryptToken } = useAuthSession()
const [path, setPath] = useState('home')
@@ -79,18 +80,28 @@ export default function ModalSalinMove({ open, close, category, onConfirm }: Pro
</View>
<View>
{
data.map((item, index) => (
<BorderBottomItem
key={index}
borderType="bottom"
icon={<Ionicons name="folder-open-sharp" color={'#f9cc40'} size={30} />}
title={item.name}
titleWeight="normal"
onPress={() => {
setPath(item.id);
}}
/>
))
data.length > 0 ?
data.map((item, index) => {
const found = dataChoose.some((i: any) => i.id == item.id);
return (
<BorderBottomItem
key={index}
borderType="bottom"
icon={<Ionicons name="folder-open-sharp" style={[found ? Styles.cGray : Styles.cFolder]} size={30} />}
title={item.name}
titleWeight="normal"
onPress={() => {
if (found) return;
setPath(item.id);
}}
subtitle={found ? <Text style={[Styles.textInformation, Styles.cGray]}>Tidak dapat memilih folder ini</Text> : ''}
/>
)
}
)
:
<Text style={[Styles.textDefault, Styles.cGray, Styles.mt15, { textAlign: 'center' }]}>Tidak ada data</Text>
}
</View>
<View style={[Styles.rowOnly, Styles.mt15, Styles.absolute0]}>

View File

@@ -1,5 +1,5 @@
import Styles from "@/constants/Styles"
import { apiGetDivisionGroup } from "@/lib/api"
import { apiGetDivisionGroup, apiGetDocumentInformasi, apiGetListDivisionByIdDivision } from "@/lib/api"
import { useAuthSession } from "@/providers/AuthProvider"
import { AntDesign } from "@expo/vector-icons"
import { useEffect, useState } from "react"
@@ -15,6 +15,7 @@ type Props = {
choose: string
onSelect: (value: any[]) => void
value?: any
item?: any
}
type CheckedState = {
@@ -30,11 +31,12 @@ type GroupData = {
}[];
}
export default function ModalSelectMultiple({ open, close, title, category, choose, onSelect, value }: Props) {
export default function ModalSelectMultiple({ open, close, title, category, choose, onSelect, value, item }: Props) {
const [isChoose, setChoose] = useState(choose)
const { token, decryptToken } = useAuthSession()
const [data, setData] = useState<any>([])
const [checked, setChecked] = useState<CheckedState>({});
const [selectedDivision, setSelectedDivision] = useState<any>([]);
async function handleLoadChooseDivision() {
try {
@@ -54,12 +56,27 @@ export default function ModalSelectMultiple({ open, close, title, category, choo
}
}
useEffect(() => {
if (category == 'choose-division') {
handleLoadChooseDivision()
} else if (category == 'share-division') {
// handleLoadPosition()
async function handleLoadShareDivision() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetListDivisionByIdDivision({ user: hasil, search: '', division: value })
const response2 = await apiGetDocumentInformasi({ user: hasil, item: item, cat: 'share' })
setData(response.data.filter((i: any) => i.id != value))
setSelectedDivision(response2.data)
} catch (error) {
console.error(error)
}
}
useEffect(() => {
if (open) {
if (category == 'choose-division') {
handleLoadChooseDivision()
} else if (category == 'share-division') {
handleLoadShareDivision()
}
}
}, [open]);
const handleCheck = (groupId: string, divisionId: string) => {
@@ -93,19 +110,38 @@ export default function ModalSelectMultiple({ open, close, title, category, choo
setChecked(newChecked);
};
const handleDivisionClick = (index: number) => {
if (selectedDivision.some((i: any) => i.id == data[index].id)) {
setSelectedDivision(
selectedDivision.filter((i: any) => i.id != data[index].id)
);
} else {
setSelectedDivision([
...selectedDivision,
{ id: data[index].id, name: data[index].name },
]);
}
};
const handleSubmit = () => {
const selectedGroups: GroupData[] = [];
Object.keys(checked).forEach((groupId) => {
const group = data.find((item: { id: string }) => item.id === groupId);
if (group) {
selectedGroups.push({
id: group.id,
name: group.name,
Division: group.Division.filter((division: { id: string }) => checked[groupId].includes(division.id)),
});
}
});
onSelect(selectedGroups);
if (category == "choose-division") {
const selectedGroups: GroupData[] = [];
Object.keys(checked).forEach((groupId) => {
const group = data.find((item: { id: string }) => item.id === groupId);
if (group) {
selectedGroups.push({
id: group.id,
name: group.name,
Division: group.Division.filter((division: { id: string }) => checked[groupId].includes(division.id)),
});
}
});
onSelect(selectedGroups);
} else {
onSelect(selectedDivision);
}
};
return (
@@ -114,22 +150,22 @@ export default function ModalSelectMultiple({ open, close, title, category, choo
{
category == 'share-division' ?
<>
<Pressable style={[Styles.itemSelectModal]} onPress={() => {
setChoose('dinas')
close(false)
}}>
<Text style={[Styles.textDefaultSemiBold]}>Sosial Kemasyarakatan</Text>
<AntDesign name="check" size={20} />
</Pressable>
{/* <Pressable style={[Styles.itemSelectModal]}>
<Text>Kaur Pemerintahan</Text>
</Pressable>
<Pressable style={[Styles.itemSelectModal]}>
<Text>Kasi Kemasyarakatan</Text>
</Pressable>
<Pressable style={[Styles.itemSelectModal]}>
<Text>PKK</Text>
</Pressable> */}
{
data.map((item: any, index: number) => {
return (
<Pressable key={index} style={[Styles.itemSelectModal]} onPress={() => {
handleDivisionClick(index)
}}>
<Text numberOfLines={1} style={[Styles.w80]}>{item.name}</Text>
{
selectedDivision.some((i: any) => i.id == item.id)
? <AntDesign name="check" size={18} />
: <></>
}
</Pressable>
)
})
}
</>
:
data.map((item: any, index: number) => {

View File

@@ -62,6 +62,9 @@ const Styles = StyleSheet.create({
cDefault: {
color: '#19345E'
},
cFolder:{
color: '#f9cc40'
},
mb05: {
marginBottom: 5
},

View File

@@ -399,6 +399,11 @@ export const apiGetDivisionMember = async ({ user, id, search }: { user: string,
return response.data;
};
export const apiGetListDivisionByIdDivision = async ({ user, search, division }: { user: string, search: string, division: string }) => {
const response = await api.get(`mobile/division/more?user=${user}&search=${search}&division=${division}`);
return response.data;
};
export const apiCreateDivision = async (data: { data: { idGroup: string, name: string, desc: string }, member: [], admin: string[], user: string }) => {
const response = await api.post(`/mobile/division`, data)
return response.data;
@@ -597,7 +602,6 @@ export const apiCreateFolderDocument = async (data: { name: string, path: string
};
export const apiUploadFileDocument = async ({ data }: { data: FormData }) => {
console.log(data)
const response = await api.post(`/mobile/document/upload`, data,
{
headers: {
@@ -612,3 +616,14 @@ export const apiMoveDocument = async (data: { path: string, dataItem: any[], use
const response = await api.post(`/mobile/document/more`, data)
return response.data;
};
export const apiCopyDocument = async (data: { path: string, dataItem: any[], user: string, idDivision: string }) => {
const response = await api.put(`/mobile/document/more`, data)
return response.data;
};
export const apiShareDocument = async (data: { dataDivision: any[], dataItem: any[], user: string }) => {
const response = await api.delete(`/mobile/document/more`, { data })
return response.data;
};