Files
mobile-darmasaba/app/(application)/division/[id]/(fitur-division)/document/index.tsx
amaliadwiy febb56f6e9 fix: document division
Deskripsi:
- update menu bottom pada saat select file atau dokumen

No Issues
2026-01-29 11:57:58 +08:00

624 lines
22 KiB
TypeScript

import AlertKonfirmasi from "@/components/alertKonfirmasi";
import AppHeader from "@/components/AppHeader";
import { ButtonHeader } from "@/components/buttonHeader";
import HeaderRightDocument from "@/components/document/headerDocument";
import ItemFile from "@/components/document/itemFile";
import ModalMore from "@/components/document/modalMore";
import DrawerBottom from "@/components/drawerBottom";
import { InputForm } from "@/components/inputForm";
import MenuItemRow from "@/components/menuItemRow";
import ModalFloat from "@/components/modalFloat";
import ModalLoading from "@/components/modalLoading";
import ModalSelectMultiple from "@/components/modalSelectMultiple";
import Skeleton from "@/components/skeleton";
import Text from "@/components/Text";
import { ColorsStatus } from "@/constants/ColorsStatus";
import { ConstEnv } from "@/constants/ConstEnv";
import Styles from "@/constants/Styles";
import {
apiDocumentDelete,
apiDocumentRename,
apiGetDivisionOneFeature,
apiGetDocument,
apiShareDocument,
} from "@/lib/api";
import { setUpdateDokumen } from "@/lib/dokumenUpdate";
import { useAuthSession } from "@/providers/AuthProvider";
import {
AntDesign,
MaterialCommunityIcons,
MaterialIcons,
} from "@expo/vector-icons";
import * as FileSystem from 'expo-file-system';
import { startActivityAsync } from 'expo-intent-launcher';
import { router, Stack, useLocalSearchParams } from "expo-router";
import * as Sharing from 'expo-sharing';
import { useEffect, useState } from "react";
import {
Alert,
Platform,
Pressable,
RefreshControl,
SafeAreaView,
ScrollView,
View
} from "react-native";
import * as mime from 'react-native-mime-types';
import Toast from "react-native-toast-message";
import { useDispatch, useSelector } from "react-redux";
type Props = {
id: string;
category: string;
name: string;
extension: string;
idStorage: string;
path: string;
createdBy: string;
share: boolean;
createdAt: string;
updatedAt: string;
};
type PropsPath = {
id: string;
name: string;
};
export default function DocumentDivision() {
const [loadingRename, setLoadingRename] = useState(false)
const [isShare, setShare] = useState(false)
const { token, decryptToken } = useAuthSession()
const { id } = useLocalSearchParams<{ id: string }>()
const [path, setPath] = useState("home")
const [data, setData] = useState<Props[]>([])
const [dataJalur, setDataJalur] = useState<PropsPath[]>([])
const [dariSelectAll, setDariSelectAll] = useState(false)
const [selectedFiles, setSelectedFiles] = useState<any>([])
const [selectAll, setSelectAll] = useState(false)
const [shareSelected, setShareSelected] = useState(false)
const [copyAllowed, setCopyAllowed] = useState(true)
const [modalMore, setModalMore] = useState(false)
const [isRename, setRename] = useState(false)
const dispatch = useDispatch();
const [loading, setLoading] = useState(true)
const arrSkeleton = Array.from({ length: 3 })
const update = useSelector((state: any) => state.dokumenUpdate)
const [refreshing, setRefreshing] = useState(false)
const [loadingOpen, setLoadingOpen] = useState(false)
const [isMemberDivision, setIsMemberDivision] = useState(false)
const entityUser = useSelector((state: any) => state.user)
const [bodyRename, setBodyRename] = useState({
id: "",
name: "",
path: "",
idDivision: id,
extension: "",
});
async function handleCheckMember() {
try {
const hasil = await decryptToken(String(token?.current));
const response = await apiGetDivisionOneFeature({
id,
user: hasil,
cat: "check-member",
});
setIsMemberDivision(response.data);
} catch (error) {
console.error(error);
}
}
useEffect(() => {
handleCheckMember()
}, [id])
async function handleLoad(loading: boolean) {
try {
setLoading(loading)
const hasil = await decryptToken(String(token?.current));
const response = await apiGetDocument({
user: hasil,
path,
division: id,
category: "all",
});
setData(response.data);
setDataJalur(response.jalur);
} catch (error) {
console.error(error);
} finally {
setLoading(false)
}
}
const handleCheckboxChange = (index: number) => {
setDariSelectAll(false);
if (selectedFiles.some((i: any) => i.id == data[index].id)) {
setSelectedFiles(
selectedFiles.filter((i: any) => i.id != data[index].id)
);
} else {
setSelectedFiles([
...selectedFiles,
{
id: data[index].id,
name: data[index].name,
path: data[index].path,
extension: data[index].extension,
category: data[index].category,
share: data[index].share,
idStorage: data[index].idStorage,
},
]);
}
};
function cek() {
if (selectedFiles.length == data.length) {
setSelectAll(true);
} else {
setSelectAll(false);
}
const shareSelected = selectedFiles.some((i: any) => i?.share == true);
if (shareSelected) {
setShareSelected(true);
} else {
setShareSelected(false);
}
const cek = selectedFiles.some((i: any) => i?.category == "FOLDER");
if (cek || selectedFiles.length > 1) {
setCopyAllowed(false);
} else {
setCopyAllowed(true);
}
}
useEffect(() => {
cek();
}, [selectedFiles]);
const handleSelectAll = () => {
if (!selectAll) {
setDariSelectAll(false);
for (let index = 0; index < data.length; index++) {
if (!selectedFiles.some((i: any) => i.id == data[index].id)) {
const newArr = {
id: data[index].id,
name: data[index].name,
path: data[index].path,
extension: data[index].extension,
category: data[index].category,
share: data[index].share,
idStorage: data[index].idStorage,
};
setSelectedFiles((selectedFiles: any) => [...selectedFiles, newArr]);
}
}
} else {
setDariSelectAll(true);
setSelectedFiles([]);
}
};
const handleBatal = () => {
setSelectedFiles([]);
setSelectAll(false);
setDariSelectAll(false);
};
function onChooseRename() {
setBodyRename({
...bodyRename,
id: selectedFiles[0].id,
name: selectedFiles[0].name,
path: selectedFiles[0].path,
extension: selectedFiles[0].extension,
});
setRename(true);
}
async function handleRename() {
try {
setLoadingRename(true)
const hasil = await decryptToken(String(token?.current));
const response = await apiDocumentRename({ user: hasil, ...bodyRename });
if (response.success) {
Toast.show({ type: 'small', text1: 'Berhasil mengubah nama', })
dispatch(setUpdateDokumen(!update));
handleBatal();
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} finally {
setLoadingRename(false)
setRename(false)
}
}
async function handleDelete() {
try {
const hasil = await decryptToken(String(token?.current));
const response = await apiDocumentDelete({
user: hasil,
data: selectedFiles,
});
if (response.success) {
Toast.show({ type: 'small', text1: 'Berhasil menghapus', })
dispatch(setUpdateDokumen(!update));
handleBatal();
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
}
}
useEffect(() => {
handleBatal();
handleLoad(false)
}, [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) {
Toast.show({ type: 'small', text1: 'Berhasil membagikan item', })
dispatch(setUpdateDokumen(!update));
handleBatal();
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error) {
console.error(error);
Toast.show({ type: 'small', text1: 'Terjadi kesalahan', })
} finally {
setShare(false);
}
}
const openFile = (item: Props) => {
if (Platform.OS == 'android') setLoadingOpen(true)
let remoteUrl = ConstEnv.url_storage + '/files/' + item.idStorage;
const fileName = item.name + '.' + item.extension;
let localPath = `${FileSystem.documentDirectory}/${fileName}`;
const mimeType = mime.lookup(fileName)
FileSystem.downloadAsync(remoteUrl, localPath).then(async ({ uri }) => {
const contentURL = await FileSystem.getContentUriAsync(uri);
setLoadingOpen(false)
try {
if (Platform.OS == 'android') {
await startActivityAsync(
'android.intent.action.VIEW',
{
data: contentURL,
flags: 1,
type: mimeType as string,
}
);
} else if (Platform.OS == 'ios') {
Sharing.shareAsync(localPath);
}
} catch (error) {
Alert.alert('INFO', 'Gagal membuka file, tidak ada aplikasi yang dapat membuka file ini');
} finally {
if (Platform.OS == 'android') setLoadingOpen(false)
}
});
};
const handleRefresh = async () => {
setRefreshing(true)
handleLoad(false)
await new Promise(resolve => setTimeout(resolve, 2000));
setRefreshing(false)
};
useEffect(() => {
handleLoad(true);
}, [path]);
return (
<SafeAreaView style={{ flex: 1 }}>
<Stack.Screen
options={{
// headerLeft: () =>
// selectedFiles.length > 0 || dariSelectAll ? (
// <ButtonHeader
// item={<MaterialIcons name="close" size={20} color="white" />}
// onPress={() => {
// handleBatal();
// }}
// />
// ) : (
// <ButtonBackHeader
// onPress={() => {
// router.back();
// }}
// />
// ),
headerTitle:
selectedFiles.length > 0 || dariSelectAll
? `${selectedFiles.length} item terpilih`
: "Dokumen Divisi",
headerTitleAlign: "center",
// headerRight: () =>
// selectedFiles.length > 0 || dariSelectAll ? (
// <ButtonHeader
// item={
// <MaterialIcons name="checklist-rtl" size={20} color="white" />
// }
// onPress={() => {
// handleSelectAll();
// }}
// />
// ) : (
// <HeaderRightDocument path={path} isMember={isMemberDivision} />
// ),
header: () => (
<AppHeader
title={
selectedFiles.length > 0 || dariSelectAll
? `${selectedFiles.length} item terpilih`
: "Dokumen Divisi"
}
showBack={(selectedFiles.length > 0 || dariSelectAll) ? false : true}
left={
<ButtonHeader
item={<MaterialIcons name="close" size={20} color="white" />}
onPress={() => {
handleBatal();
}}
/>
}
onPressLeft={() => {
(selectedFiles.length > 0 || dariSelectAll) ? handleBatal() : router.back();
}}
right={
selectedFiles.length > 0 || dariSelectAll ? (
<ButtonHeader
item={
<MaterialIcons name="checklist-rtl" size={20} color="white" />
}
onPress={() => {
handleSelectAll();
}}
/>
) : (
<HeaderRightDocument path={path} isMember={isMemberDivision} />
)
}
/>
)
}}
/>
<ModalLoading isVisible={loadingOpen} setVisible={setLoadingOpen} />
<ScrollView
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
/>
}>
<View style={[Styles.p15, Styles.mb100]}>
<View style={[Styles.rowItemsCenter]}>
{
dataJalur.map((item, index) => (
<Pressable
key={index}
style={[Styles.rowItemsCenter]}
onPress={() => {
setPath(item.id);
}}
>
{item.id != "home" && (
<AntDesign name="right" style={[Styles.mh05, Styles.mt02]} color="black" />
)}
<Text> {item.name} </Text>
</Pressable>
))
}
</View>
<View>
{
loading ?
arrSkeleton.map((item, index) => (
<Skeleton key={index} width={100} widthType="percent" height={50} borderRadius={10} />
))
:
data.length > 0 ? (
data.map((item, index) => {
const isSelected = selectedFiles.some((i: any) => i?.id == item.id);
return (
<ItemFile
key={index}
category={
item.category == "FOLDER"
? item.share
? "folder-shared"
: "folder"
: item.share
? "file-shared"
: "file"
}
title={
item.category == "FOLDER"
? item.name
: `${item.name}.${item.extension}`
}
dateTime={item.createdAt}
canChecked={(entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision}
onChecked={() => {
handleCheckboxChange(index);
}}
checked={isSelected}
onPress={() => {
if (item.category == "FOLDER" && selectedFiles.length == 0 && !dariSelectAll) {
setPath(item.id);
} else if (item.category == "FILE" && selectedFiles.length == 0 && !dariSelectAll) {
openFile(item)
}
}}
/>
);
})
) : (
<Text
style={[
Styles.textDefault,
Styles.cGray,
Styles.mt15,
{ textAlign: "center" },
]}
>
Tidak ada dokumen
</Text>
)}
</View>
</View>
</ScrollView>
{(selectedFiles.length > 0 || dariSelectAll) && (
<View style={[ColorsStatus.primary, Styles.bottomMenuSelectDocument]}>
<View style={[Styles.rowItemsCenter, { justifyContent: "center" }]}>
<MenuItemRow
icon={
<MaterialCommunityIcons
name="trash-can-outline"
color="white"
size={25}
/>
}
title="Hapus"
onPress={() => {
AlertKonfirmasi({
title: "Konfirmasi",
desc: "Apakah anda yakin ingin menghapus dokumen?",
onPress: () => {
handleDelete();
},
});
}}
column="many"
color="white"
disabled={selectedFiles.length == 0 || shareSelected}
/>
<MenuItemRow
icon={
<MaterialCommunityIcons
name="pencil-outline"
color="white"
size={25}
/>
}
title="Ganti Nama"
onPress={() => {
onChooseRename();
}}
column="many"
color="white"
disabled={selectedFiles.length != 1 || shareSelected}
/>
<MenuItemRow
icon={
<MaterialCommunityIcons
name="share-variant-outline"
color="white"
size={25}
/>
}
title="Bagikan"
onPress={() => {
setShare(true);
}}
column="many"
color="white"
disabled={selectedFiles.length != 1 || shareSelected}
/>
<MenuItemRow
icon={
<MaterialCommunityIcons
name="dots-vertical"
color="white"
size={25}
/>
}
title="Lainnya"
onPress={() => {
setModalMore(true);
}}
column="many"
color="white"
disabled={
selectedFiles.length == 1 ||
(selectedFiles.length > 0 && !shareSelected)
? false
: true
}
/>
</View>
</View>
)}
<DrawerBottom
animation="slide"
isVisible={modalMore}
setVisible={() => { setModalMore(false) }}
title=""
>
<ModalMore
onClose={() => { setModalMore(false); }}
data={selectedFiles}
share={shareSelected}
/>
</DrawerBottom>
<ModalFloat
title="Ganti Nama"
isVisible={isRename}
setVisible={() => { setRename(false) }}
onSubmit={() => { handleRename() }}
disableSubmit={bodyRename.name == "" || loadingRename}
>
<View>
<InputForm
type="default"
placeholder="Nama File"
value={bodyRename.name}
onChange={(text) => {
setBodyRename({ ...bodyRename, name: text });
}}
/>
</View>
</ModalFloat>
<ModalSelectMultiple
choose="dinas"
title="Bagikan"
category="share-division"
open={isShare}
close={() => { setShare(false) }}
onSelect={(value) => {
handleShare(value)
}}
value={id}
item={selectedFiles[0]?.id}
/>
</SafeAreaView>
);
}