feat: tambah fitur approval task pada project dan divisi

- tambah komponen ModalRiwayatApproval dan ModalTolakApproval
- update itemSectionTanggalTugas untuk mendukung status menunggu persetujuan
- update sectionTanggalTugas (project) dan sectionTanggalTugasTask (divisi) dengan alur approval lengkap
- tambah API approval project task dan division task di lib/api.ts
- tambah toggle approver di headerMemberDetail dan tampilkan badge approver di detail member
- update carouselHome untuk dispatch isApprover ke Redux
- update drawerBottom untuk mendukung scroll pada modal
- ganti label 'Belum dimulai' menjadi 'Belum ada tugas yang diselesaikan'
This commit is contained in:
2026-05-07 16:04:02 +08:00
parent d2e1663f9f
commit e48456ea7f
13 changed files with 811 additions and 289 deletions

View File

@@ -11,7 +11,7 @@ type FileItem = {
}
type Props = {
done?: boolean
status?: number // 0=belum selesai, 1=selesai, 2=menunggu persetujuan
title: string
dateStart: string
dateEnd: string
@@ -64,7 +64,15 @@ function getFileIcon(extension: string): keyof typeof MaterialCommunityIcons.gly
return 'file-outline'
}
export default function ItemSectionTanggalTugas({ done, title, dateStart, dateEnd, files = [], onPress }: Props) {
const AMBER = '#FFA94D'
function getStatusStyle(status: number | undefined, successColor: string, dimmed: string) {
if (status === 1) return { accent: successColor, badge: successColor + '25', text: successColor, label: 'Selesai' }
if (status === 2) return { accent: AMBER, badge: AMBER + '25', text: AMBER, label: 'Menunggu Persetujuan' }
return { accent: dimmed + '80', badge: dimmed + '18', text: dimmed, label: 'Belum Selesai' }
}
export default function ItemSectionTanggalTugas({ status, title, dateStart, dateEnd, files = [], onPress }: Props) {
const { colors, activeTheme } = useTheme()
const [containerWidth, setContainerWidth] = useState(0)
@@ -77,7 +85,7 @@ export default function ItemSectionTanggalTugas({ done, title, dateStart, dateEn
const dimmed = colors.dimmed.slice(0, 7)
const successColor = activeTheme === 'dark' ? '#51CF66' : colors.success
const accentColor = done === true ? successColor : dimmed + '80'
const statusStyle = getStatusStyle(status, successColor, dimmed)
return (
<Pressable
@@ -93,8 +101,8 @@ export default function ItemSectionTanggalTugas({ done, title, dateStart, dateEn
}}
>
{/* Accent bar kiri */}
{done !== undefined && (
<View style={{ width: 4, backgroundColor: accentColor }} />
{status !== undefined && (
<View style={{ width: 4, backgroundColor: statusStyle.accent }} />
)}
{/* Konten */}
@@ -103,16 +111,16 @@ export default function ItemSectionTanggalTugas({ done, title, dateStart, dateEn
{/* 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 && (
{status !== undefined && (
<View style={{
backgroundColor: done ? successColor + '25' : dimmed + '18',
backgroundColor: statusStyle.badge,
borderRadius: 20,
paddingHorizontal: 8,
paddingVertical: 3,
alignSelf: 'flex-start',
}}>
<Text style={[Styles.textSmallSemiBold, { color: done ? successColor : colors.dimmed }]}>
{done ? 'Selesai' : 'Belum Selesai'}
<Text style={[Styles.textSmallSemiBold, { color: statusStyle.text }]}>
{statusStyle.label}
</Text>
</View>
)}