upd: notifikasi

Deskripsi:
- update notifikasi push routing ketika di klik

No Issues
This commit is contained in:
amel
2025-06-26 14:30:40 +08:00
parent 76c0ba0535
commit 32908e1362
6 changed files with 105 additions and 68 deletions

View File

@@ -7,10 +7,12 @@ import HeaderMemberList from "@/components/member/headerMemberList";
import HeaderRightPositionList from "@/components/position/headerRightPositionList"; import HeaderRightPositionList from "@/components/position/headerRightPositionList";
import HeaderRightProjectList from "@/components/project/headerProjectList"; import HeaderRightProjectList from "@/components/project/headerProjectList";
import { Headers } from "@/constants/Headers"; import { Headers } from "@/constants/Headers";
import { apiReadOneNotification } from "@/lib/api";
import { pushToPage } from "@/lib/pushToPage";
import store from "@/lib/store"; import store from "@/lib/store";
import { useAuthSession } from "@/providers/AuthProvider"; import { useAuthSession } from "@/providers/AuthProvider";
import messaging from "@react-native-firebase/messaging"; import messaging from "@react-native-firebase/messaging";
import { Redirect, router, Stack, usePathname } from "expo-router"; import { Redirect, router, Stack } from "expo-router";
import { StatusBar } from 'expo-status-bar'; import { StatusBar } from 'expo-status-bar';
import { useEffect } from "react"; import { useEffect } from "react";
import { Text } from "react-native"; import { Text } from "react-native";
@@ -18,56 +20,37 @@ import { Easing, Notifier } from 'react-native-notifier';
import { Provider } from "react-redux"; import { Provider } from "react-redux";
export default function RootLayout() { export default function RootLayout() {
const pathname = usePathname(); const { token, decryptToken, isLoading } = useAuthSession()
const handleNotificationPress = (category: any, content: any) => { async function handleReadNotification(id: string, category: string, idContent: string) {
switch (category) { try {
case 'announcement': const hasil = await decryptToken(String(token?.current))
router.push(`/announcement/${content}`); const response = await apiReadOneNotification({ user: hasil, id: id })
break; pushToPage(category, idContent)
case 'discussion': } catch (error) {
router.push(`/discussion/${content}`); console.error(error)
break; }
case 'division':
router.push(`/division/${content}`);
break;
case 'member':
router.push(`/member/${content}`);
break;
case 'project':
router.push(`/project/${content}`);
break;
case 'announcement':
router.push(`/announcement/${content}`);
break;
// Add other cases as needed
default:
// Handle unknown category
console.warn(`Unknown category: ${category}`);
} }
};
useEffect(() => { useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => { const unsubscribe = messaging().onMessage(async remoteMessage => {
const id = remoteMessage?.data?.id;
const category = remoteMessage?.data?.category; const category = remoteMessage?.data?.category;
const content = remoteMessage?.data?.content; const content = remoteMessage?.data?.content;
if (category != pathname.substring(1)) {
Notifier.showNotification({ Notifier.showNotification({
title: remoteMessage.notification?.title, title: remoteMessage.notification?.title,
description: remoteMessage.notification?.body, description: remoteMessage.notification?.body,
duration: 3000, duration: 3000,
animationDuration: 300, animationDuration: 300,
showEasing: Easing.ease, showEasing: Easing.ease,
onPress: () => handleNotificationPress(category, content), onPress: () => handleReadNotification(String(id), String(category), String(content)),
hideOnPress: true, hideOnPress: true,
}); });
}
}); });
return unsubscribe; return unsubscribe;
}, []); }, []);
const { token, isLoading } = useAuthSession()
if (isLoading) { if (isLoading) {
return <Text>Loading...</Text>; return <Text>Loading...</Text>;

View File

@@ -3,11 +3,13 @@ import SkeletonTwoItem from "@/components/skeletonTwoItem";
import { ColorsStatus } from "@/constants/ColorsStatus"; import { ColorsStatus } from "@/constants/ColorsStatus";
import Styles from "@/constants/Styles"; import Styles from "@/constants/Styles";
import { apiGetNotification, apiReadOneNotification } from "@/lib/api"; import { apiGetNotification, apiReadOneNotification } from "@/lib/api";
import { setUpdateNotification } from "@/lib/notificationSlice";
import { pushToPage } from "@/lib/pushToPage";
import { useAuthSession } from "@/providers/AuthProvider"; import { useAuthSession } from "@/providers/AuthProvider";
import { Feather } from "@expo/vector-icons"; import { Feather } from "@expo/vector-icons";
import { router } from "expo-router";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { SafeAreaView, Text, View, VirtualizedList } from "react-native"; import { SafeAreaView, Text, View, VirtualizedList } from "react-native";
import { useDispatch, useSelector } from "react-redux";
type Props = { type Props = {
id: string id: string
@@ -26,6 +28,8 @@ export default function Notification() {
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
const [waiting, setWaiting] = useState(false) const [waiting, setWaiting] = useState(false)
const arrSkeleton = Array.from({ length: 5 }, (_, index) => index) const arrSkeleton = Array.from({ length: 5 }, (_, index) => index)
const dispatch = useDispatch()
const updateNotification = useSelector((state: any) => state.notificationUpdate)
async function handleLoad(loading: boolean, thisPage: number) { async function handleLoad(loading: boolean, thisPage: number) {
try { try {
@@ -77,37 +81,38 @@ export default function Notification() {
const hasil = await decryptToken(String(token?.current)) const hasil = await decryptToken(String(token?.current))
const response = await apiReadOneNotification({ user: hasil, id: id }) const response = await apiReadOneNotification({ user: hasil, id: id })
pushToPage(category, idContent) pushToPage(category, idContent)
dispatch(setUpdateNotification(!updateNotification))
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} }
} }
function pushToPage(category: string, idContent: string) { // function pushToPage(category: string, idContent: string) {
const cat = category.split('/') // const cat = category.split('/')
if (cat.length > 1) { // if (cat.length > 1) {
if (cat[2] == 'calendar') { // if (cat[2] == 'calendar') {
router.push(`/division/${cat[1]}/calendar/${idContent}`) // router.push(`/division/${cat[1]}/calendar/${idContent}`)
} else if (cat[2] == 'discussion') { // } else if (cat[2] == 'discussion') {
router.push(`/division/${cat[1]}/discussion/${idContent}`) // router.push(`/division/${cat[1]}/discussion/${idContent}`)
} else if (cat[2] == 'document') { // } else if (cat[2] == 'document') {
router.push(`/division/${cat[1]}/document/${idContent}`) // router.push(`/division/${cat[1]}/document/${idContent}`)
} else if (cat[2] == 'task') { // } else if (cat[2] == 'task') {
router.push(`/division/${cat[1]}/task/${idContent}`) // router.push(`/division/${cat[1]}/task/${idContent}`)
} // }
} else { // } else {
if (cat[0] == 'announcement') { // if (cat[0] == 'announcement') {
router.push(`/announcement/${idContent}`) // router.push(`/announcement/${idContent}`)
} else if (cat[0] == 'discussion-general') { // } else if (cat[0] == 'discussion-general') {
router.push(`/discussion/${idContent}`) // router.push(`/discussion/${idContent}`)
} else if (cat[0] == 'division') { // } else if (cat[0] == 'division') {
router.push(`/division/${idContent}`) // router.push(`/division/${idContent}`)
} else if (cat[0] == 'member') { // } else if (cat[0] == 'member') {
router.push(`/member/${idContent}`) // router.push(`/member/${idContent}`)
} else if (cat[0] == 'project') { // } else if (cat[0] == 'project') {
router.push(`/project/${idContent}`) // router.push(`/project/${idContent}`)
} // }
} // }
} // }
return ( return (
@@ -140,7 +145,10 @@ export default function Notification() {
rightTopInfo={item.createdAt} rightTopInfo={item.createdAt}
desc={item.desc} desc={item.desc}
textColor={item.isRead ? 'gray' : 'black'} textColor={item.isRead ? 'gray' : 'black'}
onPress={() => handleReadNotification(item.id, item.category, item.idContent)} onPress={() => {
handleReadNotification(item.id, item.category, item.idContent)
}}
/> />
) )
}} }}

View File

@@ -5,11 +5,13 @@ import Feather from '@expo/vector-icons/Feather';
import { router } from "expo-router"; import { router } from "expo-router";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { View } from "react-native"; import { View } from "react-native";
import { useSelector } from "react-redux";
import { ButtonHeader } from "../buttonHeader"; import { ButtonHeader } from "../buttonHeader";
export function HeaderRightHome() { export function HeaderRightHome() {
const { decryptToken, token } = useAuthSession() const { decryptToken, token } = useAuthSession()
const [notification, setNotification] = useState(0) const [notification, setNotification] = useState(0)
const updateNotification = useSelector((state: any) => state.notificationUpdate)
async function handleData() { async function handleData() {
try { try {
@@ -23,7 +25,7 @@ export function HeaderRightHome() {
useEffect(() => { useEffect(() => {
handleData() handleData()
}, []); }, [updateNotification]);
return ( return (

14
lib/notificationSlice.ts Normal file
View File

@@ -0,0 +1,14 @@
import { createSlice } from '@reduxjs/toolkit';
const notificationUpdate = createSlice({
name: 'notificationUpdate',
initialState: false,
reducers: {
setUpdateNotification: (state, action) => {
return action.payload;
},
},
});
export const { setUpdateNotification } = notificationUpdate.actions;
export default notificationUpdate.reducer;

28
lib/pushToPage.ts Normal file
View File

@@ -0,0 +1,28 @@
import { router } from "expo-router"
export function pushToPage(category: string, idContent: string) {
const cat = category.split('/')
if (cat.length > 1) {
if (cat[2] == 'calendar') {
return router.push(`/division/${cat[1]}/calendar/${idContent}`)
} else if (cat[2] == 'discussion') {
return router.push(`/division/${cat[1]}/discussion/${idContent}`)
} else if (cat[2] == 'document') {
return router.push(`/division/${cat[1]}/document/${idContent}`)
} else if (cat[2] == 'task') {
return router.push(`/division/${cat[1]}/task/${idContent}`)
}
} else {
if (cat[0] == 'announcement') {
return router.push(`/announcement/${idContent}`)
} else if (cat[0] == 'discussion-general') {
return router.push(`/discussion/${idContent}`)
} else if (cat[0] == 'division') {
return router.push(`/division/${idContent}`)
} else if (cat[0] == 'member') {
return router.push(`/member/${idContent}`)
} else if (cat[0] == 'project') {
return router.push(`/project/${idContent}`)
}
}
}

View File

@@ -12,6 +12,7 @@ import filterSlice from './filterSlice';
import groupUpdate from './groupSlice'; import groupUpdate from './groupSlice';
import memberChoose from './memberChoose'; import memberChoose from './memberChoose';
import memberUpdate from './memberSlice'; import memberUpdate from './memberSlice';
import notificationUpdate from './notificationSlice';
import positionUpdate from './positionSlice'; import positionUpdate from './positionSlice';
import projectUpdate from './projectUpdate'; import projectUpdate from './projectUpdate';
import taskCreate from './taskCreate'; import taskCreate from './taskCreate';
@@ -38,6 +39,7 @@ const store = configureStore({
taskUpdate: taskUpdate, taskUpdate: taskUpdate,
divisionCreate: divisionCreate, divisionCreate: divisionCreate,
dokumenUpdate: dokumenUpdate, dokumenUpdate: dokumenUpdate,
notificationUpdate: notificationUpdate,
} }
}); });