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}
)}
/>
>
)
}