import AppHeader from "@/components/AppHeader"; import BorderBottomItem from "@/components/borderBottomItem"; import BorderBottomItem2 from "@/components/borderBottomItem2"; import HeaderRightDiscussionDetail from "@/components/discussion/headerDiscussionDetail"; import DrawerBottom from "@/components/drawerBottom"; import ImageUser from "@/components/imageNew"; import { InputForm } from "@/components/inputForm"; import LabelStatus from "@/components/labelStatus"; import MenuItemRow from "@/components/menuItemRow"; import ModalConfirmation from "@/components/ModalConfirmation"; import Skeleton from "@/components/skeleton"; import SkeletonContent from "@/components/skeletonContent"; import Text from "@/components/Text"; import { ConstEnv } from "@/constants/ConstEnv"; import { regexOnlySpacesOrEnter } from "@/constants/OnlySpaceOrEnter"; import Styles from "@/constants/Styles"; import { apiDeleteDiscussionCommentar, apiEditDiscussionCommentar, apiGetDiscussionOne, apiGetDivisionOneFeature, apiSendDiscussionCommentar, } from "@/lib/api"; import { getDB } from "@/lib/firebaseDatabase"; import { useAuthSession } from "@/providers/AuthProvider"; import { useTheme } from "@/providers/ThemeProvider"; import { Feather, Ionicons, MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"; import { ref } from "@react-native-firebase/database"; import { useHeaderHeight } from '@react-navigation/elements'; import { router, Stack, useLocalSearchParams } from "expo-router"; import { useEffect, useState } from "react"; import { KeyboardAvoidingView, Platform, Pressable, RefreshControl, ScrollView, View } from "react-native"; import Toast from "react-native-toast-message"; import { useSelector } from "react-redux"; type Props = { id: string; title: string; desc: string; status: number; createdAt: string; createdBy: string; username: string; user_img: string; isCreator: boolean; isActive: boolean; }; type PropsComment = { id: string; comment: string; createdAt: string; username: string; img: string; idUser: string; isEdited: boolean; updatedAt: string; }; type PropsFile = { id: string; idStorage: string; name: string; extension: string } export default function DiscussionDetail() { const { colors } = useTheme(); 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); const update = useSelector((state: any) => state.discussionUpdate); const entityUser = useSelector((state: any) => state.user); const [isMemberDivision, setIsMemberDivision] = useState(false); const [isAdminDivision, setIsAdminDivision] = useState(false); const [isCreator, setIsCreator] = useState(false); const [loading, setLoading] = useState(true) const [loadingKomentar, setLoadingKomentar] = useState(true) const arrSkeleton = Array.from({ length: 3 }) const reference = ref(getDB(), `/discussion-division/${detail}`); const [refreshing, setRefreshing] = useState(false) const headerHeight = useHeaderHeight(); const [detailMore, setDetailMore] = useState([]) const entities = useSelector((state: any) => state.entities) const [isVisible, setVisible] = useState(false) const [selectKomentar, setSelectKomentar] = useState({ id: '', comment: '' }) const [viewEdit, setViewEdit] = useState(false) const [showDeleteModal, setShowDeleteModal] = useState(false) useEffect(() => { const onValueChange = reference.on('value', snapshot => { if (snapshot.val() == null) { reference.set({ trigger: true }) } handleLoadComment(false) }); // Stop listening for updates when no longer required return () => reference.off('value', onValueChange); }, []); function updateTrigger() { reference.once('value', snapshot => { const data = snapshot.val(); reference.update({ trigger: !data.trigger }); }); } async function handleLoad(loading: boolean) { try { setLoading(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetDiscussionOne({ id: detail, 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); } finally { setLoading(false) } } async function handleLoadComment(loading: boolean) { try { setLoadingKomentar(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetDiscussionOne({ id: detail, user: hasil, cat: "comment", }); setDataComment(response.data); } catch (error) { console.error(error); } finally { setLoadingKomentar(false) } } async function handleCheckMember() { try { const hasil = await decryptToken(String(token?.current)); const response = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-member", }); const response2 = await apiGetDivisionOneFeature({ id, user: hasil, cat: "check-admin", }); setIsMemberDivision(response.data); setIsAdminDivision(response2.data); } catch (error) { console.error(error); } } useEffect(() => { handleLoad(false); }, [update.data]); useEffect(() => { handleLoad(true) handleLoadComment(true); handleCheckMember(); }, []); async function handleKomentar() { try { setLoadingSend(true); const hasil = await decryptToken(String(token?.current)); const response = await apiSendDiscussionCommentar({ id: detail, data: { comment: komentar, user: hasil }, }); if (response.success) { setKomentar("") updateTrigger() } } catch (error: any) { console.error(error); const message = error?.response?.data?.message || "Gagal menambahkan komentar" Toast.show({ type: 'small', text1: message }) } finally { setLoadingSend(false); } } async function handleEditKomentar() { try { setLoadingSend(true); const hasil = await decryptToken(String(token?.current)); const response = await apiEditDiscussionCommentar({ id: selectKomentar.id, data: { comment: selectKomentar.comment, user: hasil }, }); if (response.success) { updateTrigger() } else { Toast.show({ type: 'small', text1: response.message }) } } catch (error : any ) { console.error(error); const message = error?.response?.data?.message || "Gagal mengedit komentar" Toast.show({ type: 'small', text1: message }) } finally { setLoadingSend(false); handleViewEditKomentar() } } async function handleDeleteKomentar() { try { setLoadingSend(true); const hasil = await decryptToken(String(token?.current)); const response = await apiDeleteDiscussionCommentar({ id: selectKomentar.id, data: { user: hasil }, }); if (response.success) { updateTrigger() } else { Toast.show({ type: 'small', text1: response.message }) } } catch (error : any ) { console.error(error); const message = error?.response?.data?.message || "Gagal menghapus komentar" Toast.show({ type: 'small', text1: message }) } finally { setLoadingSend(false) setVisible(false) } } function handleMenuKomentar(id: string, comment: string) { setSelectKomentar({ id, comment }) setVisible(true) } function handleViewEditKomentar() { setVisible(false) setViewEdit(!viewEdit) } const handleRefresh = async () => { setRefreshing(true) handleLoad(false) handleLoadComment(false) await new Promise(resolve => setTimeout(resolve, 2000)); setRefreshing(false) }; return ( <> ( // { // router.back(); // }} // /> // ), headerTitle: "Diskusi", headerTitleAlign: "center", // headerRight: () => // (entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator ? // : (<>) // , header: () => ( router.back()} right={ ((entityUser.role != "user" && entityUser.role != "coadmin") || isAdminDivision || isCreator) ? : (<>) } /> ) }} /> } > { loading ? : } title={data?.username} subtitle={ data?.isActive ? ( data?.status == 1 ? ( ) : ( ) ) : ( ) } rightTopInfo={data?.createdAt} desc={data?.desc} leftBottomInfo={ {dataComment.length} Komentar } /> } { loadingKomentar ? arrSkeleton.map((item, index) => ( )) : dataComment.map((item, index) => ( } title={item.username} rightTopInfo={item.createdAt} desc={item.comment} rightBottomInfo={item.isEdited ? "Edited" : ""} descEllipsize={detailMore.includes(item.id) ? false : true} bgColor="white" onPress={() => { setDetailMore((prev: any) => { if (prev.includes(item.id)) { return prev.filter((id: string) => id !== item.id) } else { return [...prev, item.id] } }) }} onLongPress={() => { item.idUser == entities.id && data?.status != 2 && data?.isActive && handleMenuKomentar(item.id, item.comment) }} /> )) } { viewEdit ? <> Edit Komentar handleViewEditKomentar()}> setSelectKomentar({ ...selectKomentar, comment: val })} value={selectKomentar.comment} itemRight={ { selectKomentar.comment != "" && !regexOnlySpacesOrEnter.test(selectKomentar.comment) && !loadingSend && data?.status != 2 && data?.isActive && (((entityUser.role == "user" || entityUser.role == "coadmin") && isMemberDivision) || entityUser.role == "admin" || entityUser.role == "supadmin" || entityUser.role == "developer" || entityUser.role == "cosupadmin") && handleEditKomentar(); }} style={[ Platform.OS == 'android' && Styles.mb12, ]} > } /> : data?.status != 2 && data?.isActive && ((entityUser.role != "user" && entityUser.role != "coadmin") || isMemberDivision) ? { komentar != "" && !regexOnlySpacesOrEnter.test(komentar) && !loadingSend && data?.status != 2 && data?.isActive && (((entityUser.role == "user" || entityUser.role == "coadmin") && isMemberDivision) || entityUser.role == "admin" || entityUser.role == "supadmin" || entityUser.role == "developer" || entityUser.role == "cosupadmin") && handleKomentar(); }} style={[ Platform.OS == 'android' && Styles.mb12, ]} > } /> : { data?.status == 2 ? "Diskusi telah ditutup" : data?.isActive == false ? "Diskusi telah diarsipkan" : "Hanya anggota divisi yang dapat memberikan komentar" } } } title="Edit" onPress={() => { handleViewEditKomentar() }} /> } title="Hapus" onPress={() => { setVisible(false) setTimeout(() => { setShowDeleteModal(true) }, 600) }} /> { setShowDeleteModal(false) handleDeleteKomentar() }} onCancel={() => setShowDeleteModal(false)} confirmText="Hapus" cancelText="Batal" /> ); }