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

@@ -1,5 +1,5 @@
import Styles from "@/constants/Styles"
import { apiDeleteUser } from "@/lib/api"
import { apiDeleteUser, apiToggleApprover } from "@/lib/api"
import { setUpdateMember } from "@/lib/memberSlice"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
@@ -16,14 +16,17 @@ import MenuItemRow from "../menuItemRow"
type Props = {
active: any,
id: string
id: string,
isApprover: boolean,
}
export default function HeaderRightMemberDetail({ active, id }: Props) {
export default function HeaderRightMemberDetail({ active, id, isApprover }: Props) {
const { token, decryptToken } = useAuthSession()
const [isVisible, setVisible] = useState(false)
const update = useSelector((state: any) => state.memberUpdate)
const [showModal, setShowModal] = useState(false)
const entityUser = useSelector((state: any) => state.user)
const [showModalActive, setShowModalActive] = useState(false)
const [showModalApprover, setShowModalApprover] = useState(false)
const { colors } = useTheme();
const dispatch = useDispatch()
@@ -37,17 +40,36 @@ export default function HeaderRightMemberDetail({ active, id }: Props) {
} else {
Toast.show({ type: 'small', text1: response.message, })
}
} catch (error : any ) {
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengupdate data"
Toast.show({ type: 'small', text1: message })
} finally {
setVisible(false)
}
}
async function handleToggleApprover() {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiToggleApprover({ user: hasil, isApprover: !isApprover }, id)
if (response.success) {
Toast.show({ type: 'small', text1: response.message })
dispatch(setUpdateMember(!update))
} else {
Toast.show({ type: 'small', text1: response.message })
}
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal mengupdate data"
Toast.show({ type: 'small', text1: message })
} finally {
setShowModalApprover(false)
}
}
const canManageApprover = ['supadmin', 'developer'].includes(entityUser.role)
return (
<>
<ButtonMenuHeader onPress={() => { setVisible(true) }} />
@@ -55,12 +77,10 @@ export default function HeaderRightMemberDetail({ active, id }: Props) {
<View style={Styles.rowItemsCenter}>
<MenuItemRow
icon={<MaterialCommunityIcons name="toggle-switch-off-outline" color={colors.text} size={25} />}
title={active ? "Non Aktifkan" : "Aktifkan"}
title={active ? "Nonaktifkan" : "Aktifkan"}
onPress={() => {
setVisible(false)
setTimeout(() => {
setShowModal(true)
}, 600)
setTimeout(() => setShowModalActive(true), 600)
}}
/>
<MenuItemRow
@@ -71,18 +91,39 @@ export default function HeaderRightMemberDetail({ active, id }: Props) {
router.push(`/member/edit/${id}`)
}}
/>
{canManageApprover && (
<MenuItemRow
icon={<MaterialCommunityIcons name="shield-check-outline" color={colors.text} size={25} />}
title={isApprover ? "Revoke Approver" : "Jadikan Approver"}
color={colors.text}
onPress={() => {
setVisible(false)
setTimeout(() => setShowModalApprover(true), 600)
}}
/>
)}
</View>
</DrawerBottom>
<ModalConfirmation
visible={showModal}
visible={showModalActive}
title="Konfirmasi"
message={active ? 'Apakah anda yakin ingin menonaktifkan user?' : 'Apakah anda yakin ingin mengaktifkan user?'}
message={active ? 'Apakah anda yakin ingin menonaktifkan anggota ini?' : 'Apakah anda yakin ingin mengaktifkan anggota ini?'}
onConfirm={() => {
setShowModal(false)
setShowModalActive(false)
handleActive()
}}
onCancel={() => setShowModal(false)}
onCancel={() => setShowModalActive(false)}
confirmText="Konfirmasi"
cancelText="Batal"
/>
<ModalConfirmation
visible={showModalApprover}
title="Konfirmasi"
message={isApprover ? 'Apakah anda yakin ingin mencabut status approver user ini?' : 'Apakah anda yakin ingin menjadikan user ini sebagai approver?'}
onConfirm={handleToggleApprover}
onCancel={() => setShowModalApprover(false)}
confirmText="Konfirmasi"
cancelText="Batal"
/>