Merge pull request 'upd: diskusi umum' (#8) from amalia/17-jan-26 into join
Reviewed-on: http://wibugit.wibudev.com/wibu/mobile-darmasaba/pulls/8
This commit is contained in:
@@ -23,7 +23,7 @@ import { ref } from '@react-native-firebase/database';
|
|||||||
import { useHeaderHeight } from '@react-navigation/elements';
|
import { useHeaderHeight } from '@react-navigation/elements';
|
||||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { KeyboardAvoidingView, Platform, Pressable, ScrollView, View } from "react-native";
|
import { KeyboardAvoidingView, Platform, Pressable, RefreshControl, ScrollView, View } from "react-native";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
@@ -73,6 +73,7 @@ export default function DetailDiscussionGeneral() {
|
|||||||
const [detailMore, setDetailMore] = useState<any>([])
|
const [detailMore, setDetailMore] = useState<any>([])
|
||||||
const [loadingSendKomentar, setLoadingSendKomentar] = useState(false)
|
const [loadingSendKomentar, setLoadingSendKomentar] = useState(false)
|
||||||
const [isVisible, setVisible] = useState(false)
|
const [isVisible, setVisible] = useState(false)
|
||||||
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
const [selectKomentar, setSelectKomentar] = useState({
|
const [selectKomentar, setSelectKomentar] = useState({
|
||||||
id: '',
|
id: '',
|
||||||
comment: ''
|
comment: ''
|
||||||
@@ -209,6 +210,16 @@ export default function DetailDiscussionGeneral() {
|
|||||||
setViewEdit(!viewEdit)
|
setViewEdit(!viewEdit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleRefresh = async () => {
|
||||||
|
setRefreshing(true)
|
||||||
|
handleLoad('detail', false)
|
||||||
|
handleLoad('komentar', false)
|
||||||
|
handleLoad('cek-anggota', false)
|
||||||
|
handleLoad('file', false)
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
|
setRefreshing(false)
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@@ -220,8 +231,17 @@ export default function DetailDiscussionGeneral() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<View style={{ flex: 1 }}>
|
<View style={{ flex: 1 }}>
|
||||||
<ScrollView showsVerticalScrollIndicator={false}>
|
<ScrollView
|
||||||
<View style={[Styles.p15, Styles.mb100]}>
|
showsVerticalScrollIndicator={false}
|
||||||
|
style={[Styles.h100]}
|
||||||
|
refreshControl={
|
||||||
|
<RefreshControl
|
||||||
|
refreshing={refreshing}
|
||||||
|
onRefresh={() => handleRefresh()}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View style={[Styles.p15]}>
|
||||||
{
|
{
|
||||||
loading ?
|
loading ?
|
||||||
<SkeletonContent />
|
<SkeletonContent />
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ export default function EditDiscussionGeneral() {
|
|||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [fileForm, setFileForm] = useState<any[]>([])
|
const [fileForm, setFileForm] = useState<any[]>([])
|
||||||
const [isModalFile, setModalFile] = useState(false)
|
const [isModalFile, setModalFile] = useState(false)
|
||||||
const [indexDelFile, setIndexDelFile] = useState<number>(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 }[]>([])
|
||||||
const update = useSelector((state: any) => state.discussionGeneralDetailUpdate)
|
const update = useSelector((state: any) => state.discussionGeneralDetailUpdate)
|
||||||
const [dataForm, setDataForm] = useState({
|
const [dataForm, setDataForm] = useState({
|
||||||
title: "",
|
title: "",
|
||||||
@@ -45,9 +46,17 @@ export default function EditDiscussionGeneral() {
|
|||||||
user: hasil,
|
user: hasil,
|
||||||
cat: "detail",
|
cat: "detail",
|
||||||
});
|
});
|
||||||
|
const responseFile = await apiGetDiscussionGeneralOne({
|
||||||
|
id: id,
|
||||||
|
user: hasil,
|
||||||
|
cat: "file",
|
||||||
|
});
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
setDataForm(response.data);
|
setDataForm(response.data);
|
||||||
}
|
}
|
||||||
|
if (responseFile.success) {
|
||||||
|
setDataFile(responseFile.data);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
@@ -102,8 +111,18 @@ export default function EditDiscussionGeneral() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function deleteFile(index: number) {
|
function deleteFile(index: number | string, cat: "newFile" | "oldFile" | null) {
|
||||||
setFileForm([...fileForm.filter((val, i) => i !== index)])
|
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)
|
setModalFile(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +131,22 @@ export default function EditDiscussionGeneral() {
|
|||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const hasil = await decryptToken(String(token?.current));
|
const hasil = await decryptToken(String(token?.current));
|
||||||
const response = await apiEditDiscussionGeneral({ user: hasil, title: dataForm.title, desc: dataForm.desc }, id);
|
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, title: dataForm.title, desc: dataForm.desc, oldFile: dataFile
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
|
const response = await apiEditDiscussionGeneral(fd, id);
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
dispatch(setUpdateDiscussionGeneralDetail(!update))
|
dispatch(setUpdateDiscussionGeneralDetail(!update))
|
||||||
Toast.show({ type: 'small', text1: 'Berhasil mengubah data', })
|
Toast.show({ type: 'small', text1: 'Berhasil mengubah data', })
|
||||||
@@ -173,19 +207,31 @@ export default function EditDiscussionGeneral() {
|
|||||||
/>
|
/>
|
||||||
<ButtonSelect value="Upload File" onPress={pickDocumentAsync} />
|
<ButtonSelect value="Upload File" onPress={pickDocumentAsync} />
|
||||||
{
|
{
|
||||||
fileForm.length > 0
|
(fileForm.length > 0 || dataFile.filter((val) => !val.delete).length > 0)
|
||||||
&&
|
&&
|
||||||
<View style={[Styles.borderAll, Styles.round10, Styles.p10, Styles.mb10]}>
|
<View style={[Styles.borderAll, Styles.round10, Styles.p10, Styles.mb10]}>
|
||||||
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
|
<Text style={[Styles.textDefaultSemiBold]}>File</Text>
|
||||||
|
{
|
||||||
|
dataFile.filter((val) => !val.delete).map((item, index) => (
|
||||||
|
<BorderBottomItem
|
||||||
|
key={index}
|
||||||
|
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
|
||||||
|
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
||||||
|
title={item.name + '.' + item.extension}
|
||||||
|
titleWeight="normal"
|
||||||
|
onPress={() => { setIndexDelFile({ id: item.id, cat: "oldFile" }); setModalFile(true) }}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
{
|
{
|
||||||
fileForm.map((item, index) => (
|
fileForm.map((item, index) => (
|
||||||
<BorderBottomItem
|
<BorderBottomItem
|
||||||
key={index}
|
key={index}
|
||||||
borderType={fileForm.length > 1 ? "bottom" : "none"}
|
borderType={(fileForm.length + dataFile.length) > 1 ? "bottom" : "none"}
|
||||||
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
icon={<MaterialCommunityIcons name="file-outline" size={25} color="black" />}
|
||||||
title={item.name}
|
title={item.name}
|
||||||
titleWeight="normal"
|
titleWeight="normal"
|
||||||
onPress={() => { setIndexDelFile(index); setModalFile(true) }}
|
onPress={() => { setIndexDelFile({ id: index, cat: "newFile" }); setModalFile(true) }}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -199,7 +245,7 @@ export default function EditDiscussionGeneral() {
|
|||||||
<MenuItemRow
|
<MenuItemRow
|
||||||
icon={<Ionicons name="trash" color="black" size={25} />}
|
icon={<Ionicons name="trash" color="black" size={25} />}
|
||||||
title="Hapus"
|
title="Hapus"
|
||||||
onPress={() => { deleteFile(indexDelFile) }}
|
onPress={() => { deleteFile(indexDelFile.id, indexDelFile.cat) }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</DrawerBottom>
|
</DrawerBottom>
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import { ColorsStatus } from "@/constants/ColorsStatus";
|
import { ColorsStatus } from "@/constants/ColorsStatus";
|
||||||
|
import { ConstEnv } from "@/constants/ConstEnv";
|
||||||
import Styles from "@/constants/Styles";
|
import Styles from "@/constants/Styles";
|
||||||
import { Ionicons, Entypo, EvilIcons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import * as FileSystem from 'expo-file-system';
|
||||||
|
import { startActivityAsync } from 'expo-intent-launcher';
|
||||||
|
import * as Sharing from 'expo-sharing';
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Dimensions, Pressable, View } from "react-native";
|
import { Alert, Dimensions, Platform, Pressable, View } from "react-native";
|
||||||
import { ScrollView } from "react-native-gesture-handler";
|
import { ScrollView } from "react-native-gesture-handler";
|
||||||
|
import * as mime from 'react-native-mime-types';
|
||||||
import Text from "./Text";
|
import Text from "./Text";
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title?: string
|
title?: string
|
||||||
subtitle?: string | React.ReactNode
|
subtitle?: string | React.ReactNode
|
||||||
@@ -32,6 +38,39 @@ export default function BorderBottomItem2({ title, subtitle, icon, desc, onPress
|
|||||||
const lebar = width ? lebarDim * width / 100 : 'auto';
|
const lebar = width ? lebarDim * width / 100 : 'auto';
|
||||||
const textColorFix = textColor ? textColor : 'black';
|
const textColorFix = textColor ? textColor : 'black';
|
||||||
const [isTap, setIsTap] = useState(false);
|
const [isTap, setIsTap] = useState(false);
|
||||||
|
const [loadingOpen, setLoadingOpen] = useState(false)
|
||||||
|
|
||||||
|
|
||||||
|
const openFile = (item: { idStorage: string; name: string; extension: string }) => {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -74,10 +113,14 @@ export default function BorderBottomItem2({ title, subtitle, icon, desc, onPress
|
|||||||
dataFile.length > 0 && (
|
dataFile.length > 0 && (
|
||||||
<ScrollView horizontal style={[Styles.mv05]} showsHorizontalScrollIndicator={false}>
|
<ScrollView horizontal style={[Styles.mv05]} showsHorizontalScrollIndicator={false}>
|
||||||
{dataFile.map((item, index) => (
|
{dataFile.map((item, index) => (
|
||||||
<View key={index} style={[Styles.rowItemsCenter, Styles.borderAll, Styles.round10, Styles.ph05, Styles.pv03, Styles.mr05]}>
|
<Pressable
|
||||||
|
key={index}
|
||||||
|
style={[Styles.rowItemsCenter, Styles.borderAll, Styles.round10, Styles.ph05, Styles.pv03, Styles.mr05]}
|
||||||
|
onPress={() => { openFile({ idStorage: item.idStorage, name: item.name, extension: item.extension }) }}
|
||||||
|
>
|
||||||
<Ionicons name="document-text" size={18} color="grey" style={Styles.mr05} />
|
<Ionicons name="document-text" size={18} color="grey" style={Styles.mr05} />
|
||||||
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>{item.name}.{item.extension}</Text>
|
<Text style={[Styles.textInformation, Styles.cGray, Styles.mb05]}>{item.name}.{item.extension}</Text>
|
||||||
</View>
|
</Pressable>
|
||||||
))}
|
))}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
)
|
)
|
||||||
|
|||||||
13
lib/api.ts
13
lib/api.ts
@@ -230,8 +230,17 @@ export const apiDeleteDiscussionGeneral = async (data: { user: string, active: b
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const apiEditDiscussionGeneral = async (data: { user: string, title: string, desc: string }, id: string) => {
|
// export const apiEditDiscussionGeneral = async (data: { user: string, title: string, desc: string }, id: string) => {
|
||||||
const response = await api.put(`/mobile/discussion-general/${id}`, data)
|
// const response = await api.put(`/mobile/discussion-general/${id}`, data)
|
||||||
|
// return response.data;
|
||||||
|
// };
|
||||||
|
|
||||||
|
export const apiEditDiscussionGeneral = async (data: FormData, id: string) => {
|
||||||
|
const response = await api.put(`/mobile/discussion-general/${id}`, data, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
})
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user