import Styles from "@/constants/Styles"; import { useTheme } from "@/providers/ThemeProvider"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import { useState } from "react"; import { LayoutChangeEvent, Pressable, View } from "react-native"; import Text from "./Text"; type FileItem = { name: string extension: string } type Props = { done?: boolean title: string dateStart: string dateEnd: string files?: FileItem[] onPress?: () => void } // estimasi lebar chip berdasarkan panjang teks const CHAR_W = 6.5 // lebar rata-rata per karakter (font size 10) const ICON_W = 17 // icon 13px + margin 4px const PAD_H = 16 // paddingHorizontal 8 * 2 const GAP = 6 const PLUS_W = 72 // lebar chip "+X lainnya" function estimateChipWidth(label: string) { return PAD_H + ICON_W + label.length * CHAR_W } function getVisibleChips(files: FileItem[], containerWidth: number) { if (containerWidth === 0) return { visible: [], extra: files.length } let used = 0 const visible: FileItem[] = [] for (let i = 0; i < files.length; i++) { const label = `${files[i].name}.${files[i].extension}` const chipW = estimateChipWidth(label) const isLast = i === files.length - 1 const plusChipW = isLast ? 0 : PLUS_W + GAP const gapW = visible.length > 0 ? GAP : 0 if (used + gapW + chipW + plusChipW <= containerWidth) { visible.push(files[i]) used += gapW + chipW } else { break } } return { visible, extra: files.length - visible.length } } function getFileIcon(extension: string): keyof typeof MaterialCommunityIcons.glyphMap { const ext = extension.toLowerCase() if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'heic', 'heif'].includes(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' } const chipStyle = (colors: any) => ({ flexDirection: 'row' as const, alignItems: 'center' as const, backgroundColor: colors.dimmed + '5', borderRadius: 6, borderWidth: 0.5, borderColor: colors.icon + '20', paddingHorizontal: 8, paddingVertical: 4, }) export default function ItemSectionTanggalTugas({ done, title, dateStart, dateEnd, files = [], onPress }: Props) { const { colors } = useTheme() const [containerWidth, setContainerWidth] = useState(0) const { visible, extra } = getVisibleChips(files, containerWidth) function onRowLayout(e: LayoutChangeEvent) { const w = e.nativeEvent.layout.width if (w !== containerWidth) setContainerWidth(w) } return ( {/* Status */} {done != undefined && ( done ? ( <> Selesai ) : ( <> Belum Selesai ) )} {/* Judul tugas */} {title} {/* Tanggal */} Tanggal Mulai {dateStart} Tanggal Berakhir {dateEnd} {/* Lampiran file */} {files.length > 0 && ( {files.length} Lampiran {visible.map((file, index) => { const label = `${file.name}.${file.extension}` const chipW = Math.min(estimateChipWidth(label), containerWidth * 0.55) return ( {label} ) })} {extra > 0 && ( +{extra} lainnya )} )} ) }