feat: redesign section progress, report, link, file, dan cancel pada project & division/task
- SectionProgress: progress bar animated, badge persentase, label status, task count - SectionReport: header ikon, left accent border, TextExpandable dengan label Indonesia - SectionLink: tap langsung buka URL, ikon per domain, long press untuk hapus - SectionFile: icon container konsisten 30×30 di semua section - SectionCancel: card subtle dengan warna error, konsisten dengan visual language baru - TextExpandable: fix bug show/hide tidak muncul setelah content diupdate - Tambah 14 style class baru di Styles.ts untuk menggantikan inline style - Terapkan semua perubahan ke fitur division/task - Fix menu "Edit Tugas" di sectionTanggalTugasTask yang terpotong karena overflow Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,12 +19,11 @@ type Props = {
|
||||
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 CHAR_W = 6.5
|
||||
const ICON_W = 17
|
||||
const PAD_H = 16
|
||||
const GAP = 6
|
||||
const PLUS_W = 72 // lebar chip "+X lainnya"
|
||||
const PLUS_W = 72
|
||||
|
||||
function estimateChipWidth(label: string) {
|
||||
return PAD_H + ICON_W + label.length * CHAR_W
|
||||
@@ -65,92 +64,90 @@ function getFileIcon(extension: string): keyof typeof MaterialCommunityIcons.gly
|
||||
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 { colors, activeTheme } = useTheme()
|
||||
const [containerWidth, setContainerWidth] = useState(0)
|
||||
|
||||
const { visible, extra } = getVisibleChips(files, containerWidth)
|
||||
|
||||
function onRowLayout(e: LayoutChangeEvent) {
|
||||
function onChipsLayout(e: LayoutChangeEvent) {
|
||||
const w = e.nativeEvent.layout.width
|
||||
if (w !== containerWidth) setContainerWidth(w)
|
||||
}
|
||||
|
||||
const dimmed = colors.dimmed.slice(0, 7)
|
||||
const successColor = activeTheme === 'dark' ? '#51CF66' : colors.success
|
||||
const accentColor = done === true ? successColor : dimmed + '80'
|
||||
|
||||
return (
|
||||
<Pressable style={[Styles.mb15, { borderBottomColor: colors.icon + '20', borderBottomWidth: 1 }]} onPress={onPress}>
|
||||
<Pressable
|
||||
onPress={onPress}
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
borderRadius: 10,
|
||||
overflow: 'hidden',
|
||||
borderWidth: 1,
|
||||
borderColor: colors.icon + '18',
|
||||
backgroundColor: colors.card,
|
||||
marginBottom: 10,
|
||||
}}
|
||||
>
|
||||
{/* Accent bar kiri */}
|
||||
{done !== undefined && (
|
||||
<View style={{ width: 4, backgroundColor: accentColor }} />
|
||||
)}
|
||||
|
||||
{/* Status */}
|
||||
<View style={[Styles.rowItemsCenter]}>
|
||||
{done != undefined && (
|
||||
done ? (
|
||||
<>
|
||||
<MaterialCommunityIcons name="checkbox-marked-circle-outline" size={22} color={colors.text} style={[Styles.mr10]} />
|
||||
<Text>Selesai</Text>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<MaterialCommunityIcons name="checkbox-blank-circle-outline" size={22} color={colors.text} style={[Styles.mr10]} />
|
||||
<Text>Belum Selesai</Text>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
{/* Konten */}
|
||||
<View style={{ flex: 1, padding: 12 }}>
|
||||
|
||||
{/* Judul tugas */}
|
||||
<View style={[Styles.wrapPaper, Styles.noShadow, Styles.borderAll, Styles.mv10, Styles.p10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
|
||||
<View style={[Styles.rowItemsCenter, { alignItems: 'flex-start' }]}>
|
||||
<MaterialCommunityIcons name="file-table-outline" size={22} color={colors.text} style={[Styles.mr10]} />
|
||||
<View style={[Styles.w90]}>
|
||||
<Text style={[Styles.textDefault]}>{title}</Text>
|
||||
</View>
|
||||
{/* Judul + badge status */}
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 8 }}>
|
||||
<Text style={[Styles.textDefault, { flex: 1, marginRight: 8 }]}>{title}</Text>
|
||||
{done !== undefined && (
|
||||
<View style={{
|
||||
backgroundColor: done ? successColor + '25' : dimmed + '18',
|
||||
borderRadius: 20,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
alignSelf: 'flex-start',
|
||||
}}>
|
||||
<Text style={[Styles.textSmallSemiBold, { color: done ? successColor : colors.dimmed }]}>
|
||||
{done ? 'Selesai' : 'Belum Selesai'}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Tanggal */}
|
||||
<View style={[Styles.rowSpaceBetween, Styles.mb15]}>
|
||||
<View style={[{ width: '48%' }]}>
|
||||
<Text style={[Styles.mb05]}>Tanggal Mulai</Text>
|
||||
<View style={[Styles.wrapPaper, Styles.noShadow, Styles.borderAll, Styles.p10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
|
||||
<Text style={{ textAlign: 'center' }}>{dateStart}</Text>
|
||||
</View>
|
||||
{/* Tanggal */}
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: files.length > 0 ? 8 : 0 }}>
|
||||
<MaterialCommunityIcons name="calendar-outline" size={13} color={colors.dimmed} style={{ marginRight: 4 }} />
|
||||
<Text style={[Styles.textSmallSemiBold, { color: colors.dimmed }]}>{dateStart}</Text>
|
||||
<MaterialCommunityIcons name="arrow-right" size={13} color={colors.dimmed} style={{ marginHorizontal: 4 }} />
|
||||
<Text style={[Styles.textSmallSemiBold, { color: colors.dimmed }]}>{dateEnd}</Text>
|
||||
</View>
|
||||
<View style={[{ width: '48%' }]}>
|
||||
<Text style={[Styles.mb05]}>Tanggal Berakhir</Text>
|
||||
<View style={[Styles.wrapPaper, Styles.noShadow, Styles.borderAll, Styles.p10, { backgroundColor: colors.card, borderColor: colors.icon + '20' }]}>
|
||||
<Text style={{ textAlign: 'center' }}>{dateEnd}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Lampiran file */}
|
||||
{files.length > 0 && (
|
||||
<View style={[Styles.mb15]}>
|
||||
<View style={[Styles.rowItemsCenter, Styles.mb05]}>
|
||||
<MaterialCommunityIcons name="paperclip" size={13} color={colors.dimmed} style={[Styles.mr10]} />
|
||||
<Text style={[Styles.textSmallSemiBold, { color: colors.dimmed }]}>
|
||||
{files.length} Lampiran
|
||||
</Text>
|
||||
</View>
|
||||
{/* Chips lampiran */}
|
||||
{files.length > 0 && (
|
||||
<View
|
||||
style={{ flexDirection: 'row', gap: GAP, overflow: 'hidden' }}
|
||||
onLayout={onRowLayout}
|
||||
onLayout={onChipsLayout}
|
||||
>
|
||||
{visible.map((file, index) => {
|
||||
const label = `${file.name}.${file.extension}`
|
||||
const chipW = Math.min(estimateChipWidth(label), containerWidth * 0.55)
|
||||
return (
|
||||
<View key={index} style={[chipStyle(colors), { width: chipW }]}>
|
||||
<View
|
||||
key={index}
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: dimmed + '18',
|
||||
borderRadius: 6,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
width: chipW,
|
||||
}}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name={getFileIcon(file.extension)}
|
||||
size={13}
|
||||
@@ -168,16 +165,20 @@ export default function ItemSectionTanggalTugas({ done, title, dateStart, dateEn
|
||||
)
|
||||
})}
|
||||
{extra > 0 && (
|
||||
<View style={[chipStyle(colors)]}>
|
||||
<View style={{
|
||||
backgroundColor: dimmed + '18',
|
||||
borderRadius: 6,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
}}>
|
||||
<Text style={[Styles.textSmallSemiBold, { color: colors.dimmed }]}>
|
||||
+{extra} lainnya
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
)}
|
||||
</View>
|
||||
</Pressable>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user