import ImageUser from "@/components/imageNew"; import Skeleton from "@/components/skeleton"; import Text from "@/components/Text"; import { ConstEnv } from "@/constants/ConstEnv"; import { isImageFile } from "@/constants/FileExtensions"; import Styles from "@/constants/Styles"; import { useTheme } from "@/providers/ThemeProvider"; import { MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons"; import * as FileSystem from 'expo-file-system'; import { startActivityAsync } from 'expo-intent-launcher'; import * as Sharing from 'expo-sharing'; import { useState } from "react"; import { Modal, Platform, Pressable, SafeAreaView, ScrollView, View } from "react-native"; import ImageViewing from "react-native-image-viewing"; import * as mime from 'react-native-mime-types'; import Toast from "react-native-toast-message"; export type CommentFile = { id: string name: string extension: string idStorage: string } export type CommentItem = { id: string comment: string createdAt: string idUser: string img: string username: string isEdited: boolean updatedAt: string files: CommentFile[] } type Props = { data: CommentItem[] loading: boolean myId: string canInteract: boolean onLongPress: (id: string, comment: string, files: CommentFile[]) => void } function getFileIcon(ext: string): keyof typeof MaterialCommunityIcons.glyphMap { if (isImageFile(ext)) return 'image-outline' if (ext === 'pdf') return 'file-pdf-box' if (['mp4', 'mov', 'avi', 'mkv'].includes(ext)) return 'video-outline' if (['doc', 'docx'].includes(ext)) return 'file-word-outline' if (['xls', 'xlsx'].includes(ext)) return 'file-excel-outline' if (['zip', 'rar', '7z'].includes(ext)) return 'zip-box-outline' return 'file-outline' } function getFileColor(ext: string): string { if (isImageFile(ext)) return '#339AF0' if (ext === 'pdf') return '#F03E3E' if (['mp4', 'mov', 'avi', 'mkv'].includes(ext)) return '#AE3EC9' if (['doc', 'docx'].includes(ext)) return '#1C7ED6' if (['xls', 'xlsx'].includes(ext)) return '#2F9E44' if (['zip', 'rar', '7z'].includes(ext)) return '#E8590C' return '#868E96' } function FileCard({ file, colors, onPress }: { file: CommentFile; colors: any; onPress: () => void }) { const ext = file.extension.toLowerCase() return ( [Styles.fileCard, { borderColor: colors.icon + '18', backgroundColor: pressed ? colors.icon + '10' : 'transparent' }]} > {file.name} {ext.toUpperCase()} ) } export default function DiscussionCommentList({ data, loading, myId, canInteract, onLongPress }: Props) { const { colors } = useTheme() const [expandedIds, setExpandedIds] = useState([]) const [modalFiles, setModalFiles] = useState([]) const [modalVisible, setModalVisible] = useState(false) const [previewFile, setPreviewFile] = useState(null) const [modalPreviewFile, setModalPreviewFile] = useState(null) const [loadingOpen, setLoadingOpen] = useState(false) const arrSkeleton = Array.from({ length: 3 }, (_, i) => i) function toggleExpand(id: string) { setExpandedIds(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]) } async function openExternal(file: CommentFile) { try { setLoadingOpen(true) const remoteUrl = `${ConstEnv.url_storage}/files/${file.idStorage}` const fileName = `${file.name}.${file.extension}` const localPath = `${FileSystem.documentDirectory}/${fileName}` const dl = await FileSystem.downloadAsync(remoteUrl, localPath) if (dl.status !== 200) throw new Error('Download failed') const contentURL = await FileSystem.getContentUriAsync(dl.uri) const mimeType = mime.lookup(fileName) as string if (Platform.OS === 'android') { await startActivityAsync('android.intent.action.VIEW', { data: contentURL, flags: 1, type: mimeType }) } else { await Sharing.shareAsync(localPath) } } catch { Toast.show({ type: 'error', text1: 'Gagal membuka file' }) } finally { setLoadingOpen(false) } } function handleFilePress(file: CommentFile) { if (isImageFile(file.extension.toLowerCase())) { setPreviewFile(file) } else { openExternal(file) } } if (loading) { return ( {arrSkeleton.map((_, i) => ( ))} ) } return ( <> {data.map((item, i) => ( toggleExpand(item.id)} onLongPress={() => item.idUser === myId && canInteract && onLongPress(item.id, item.comment, item.files ?? [])} style={({ pressed }) => [ Styles.discussionCommentCard, { backgroundColor: pressed ? colors.icon + '10' : colors.card, borderColor: colors.icon + '20' } ]} > {item.username} {item.isEdited && ( diedit )} {item.createdAt} {item.comment.length > 0 && ( {item.comment} )} {item.files?.length > 0 && ( 0 ? 8 : 0 }}> {(item.files.length > 2 ? item.files.slice(0, 1) : item.files).map((file, idx) => ( handleFilePress(file)} /> ))} {item.files.length > 2 && ( { setModalFiles(item.files); setModalVisible(true) }} style={[Styles.fileCard, { borderColor: colors.icon + '18', backgroundColor: 'transparent' }]} > +{item.files.length - 1} lainnya Lihat semua )} )} ))} setModalVisible(false)}> Lampiran ({modalFiles.length} file) setModalVisible(false)}> {modalFiles.map((file, idx) => ( { if (isImageFile(file.extension.toLowerCase())) { setModalPreviewFile(file) } else { openExternal(file) } }} /> ))} setModalPreviewFile(null)} doubleTapToZoomEnabled HeaderComponent={() => ( setModalPreviewFile(null)}> modalPreviewFile && openExternal(modalPreviewFile)} disabled={loadingOpen}> )} FooterComponent={() => ( {modalPreviewFile?.name}.{modalPreviewFile?.extension} )} /> setPreviewFile(null)} doubleTapToZoomEnabled HeaderComponent={() => ( setPreviewFile(null)}> previewFile && openExternal(previewFile)} disabled={loadingOpen}> )} FooterComponent={() => ( {previewFile?.name}.{previewFile?.extension} )} /> ) }