From 4af54980a0086600bd050af4db9140d719ad8f38 Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Fri, 8 May 2026 14:56:44 +0800 Subject: [PATCH] feat: tambah fitur tandai semua notifikasi dibaca dengan modal konfirmasi --- app/(application)/notification.tsx | 53 ++++++++++++++++++++++++++++-- lib/api.ts | 5 +++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/app/(application)/notification.tsx b/app/(application)/notification.tsx index c67f40b..64322f9 100644 --- a/app/(application)/notification.tsx +++ b/app/(application)/notification.tsx @@ -1,8 +1,9 @@ import AppHeader from "@/components/AppHeader"; +import ModalConfirmation from "@/components/ModalConfirmation"; import SkeletonTwoItem from "@/components/skeletonTwoItem"; import Text from "@/components/Text"; import Styles from "@/constants/Styles"; -import { apiGetNotification, apiReadOneNotification } from "@/lib/api"; +import { apiGetNotification, apiReadAllNotification, apiReadOneNotification } from "@/lib/api"; import { setUpdateNotification } from "@/lib/notificationSlice"; import { pushToPage } from "@/lib/pushToPage"; import { useAuthSession } from "@/providers/AuthProvider"; @@ -32,7 +33,7 @@ type ListRow = HeaderRow | ItemRow function getNotifStyle(category: string): { icon: keyof typeof Feather.glyphMap; color: string } { if (category === 'announcement') return { icon: 'volume-2', color: '#3B82F6' } if (category === 'project') return { icon: 'activity', color: '#10B981' } - if (category.includes('/task')) return { icon: 'check-circle', color: '#8B5CF6' } + if (category.includes('/task')) return { icon: 'clipboard', color: '#8B5CF6' } if (category === 'division') return { icon: 'users', color: '#3B82F6' } if (category.includes('/discussion') || category === 'discussion-general') return { icon: 'message-square', color: '#06B6D4' } if (category.includes('/calendar')) return { icon: 'calendar', color: '#F59E0B' } @@ -48,6 +49,8 @@ export default function Notification() { const dispatch = useDispatch() const updateNotification = useSelector((state: any) => state.notificationUpdate) const [refreshing, setRefreshing] = useState(false) + const [markingAll, setMarkingAll] = useState(false) + const [showConfirm, setShowConfirm] = useState(false) const { data, @@ -106,6 +109,22 @@ export default function Notification() { setRefreshing(false) }; + const hasUnread = flatData.some((item) => !item.isRead) + + async function handleReadAll() { + try { + setMarkingAll(true) + const hasil = await decryptToken(String(token?.current)) + await apiReadAllNotification({ user: hasil }) + await queryClient.invalidateQueries({ queryKey: ['notifications'] }) + dispatch(setUpdateNotification(!updateNotification)) + } catch (error) { + console.error(error) + } finally { + setMarkingAll(false) + } + } + async function handleReadNotification(id: string, category: string, idContent: string) { try { const hasil = await decryptToken(String(token?.current)) @@ -123,11 +142,39 @@ export default function Notification() { ( - router.back()} /> + router.back()} + right={ + hasUnread ? ( + setShowConfirm(true)} + disabled={markingAll} + style={{ opacity: markingAll ? 0.5 : 1, padding: 4 }} + > + + + ) : undefined + } + /> ) }} /> + { + setShowConfirm(false) + handleReadAll() + }} + onCancel={() => setShowConfirm(false)} + /> + {isLoading ? ( [0, 1, 2, 3, 4].map((_, i) => ) diff --git a/lib/api.ts b/lib/api.ts index 17a3967..cf3e82a 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -859,6 +859,11 @@ export const apiReadOneNotification = async (data: { user: string, id: string }) return response.data; }; +export const apiReadAllNotification = async (data: { user: string }) => { + const response = await api.post(`/mobile/home/notification`, data) + return response.data; +}; + export const apiGetVersion = async () => { const response = await api.get(`mobile/version`); return response.data;