upd: notifikasi

Deskripsi:
- belom selesai notifikasi

No Issues
This commit is contained in:
2026-03-03 16:44:02 +08:00
parent a53b99b39d
commit 868b712fbb
4 changed files with 71 additions and 63 deletions

View File

@@ -3,13 +3,14 @@ import Text from "@/components/Text";
import ButtonSetting from "@/components/buttonSetting"; import ButtonSetting from "@/components/buttonSetting";
import DrawerBottom from "@/components/drawerBottom"; import DrawerBottom from "@/components/drawerBottom";
import Styles from "@/constants/Styles"; import Styles from "@/constants/Styles";
import { apiRegisteredToken, apiUnregisteredToken } from "@/lib/api"; import { apiGetCheckToken, apiRegisteredToken, apiUnregisteredToken } from "@/lib/api";
import { checkPermission, getToken, openSettings, requestPermission } from "@/lib/useNotification"; import { checkPermission, getToken, openSettings } from "@/lib/useNotification";
import { useAuthSession } from "@/providers/AuthProvider"; import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider"; import { useTheme } from "@/providers/ThemeProvider";
import { Feather, Ionicons } from "@expo/vector-icons"; import { Feather, Ionicons } from "@expo/vector-icons";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { router } from "expo-router"; import { router } from "expo-router";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { AppState, AppStateStatus, Pressable, View } from "react-native"; import { AppState, AppStateStatus, Pressable, View } from "react-native";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
@@ -28,12 +29,13 @@ export default function ListSetting() {
const [showLogoutModal, setShowLogoutModal] = useState(false) const [showLogoutModal, setShowLogoutModal] = useState(false)
const [showThemeModal, setShowThemeModal] = useState(false) const [showThemeModal, setShowThemeModal] = useState(false)
const prevOsPermission = useRef<boolean | undefined>(undefined);
const registerToken = async () => { const registerToken = async () => {
try { try {
const token = await getToken(); const token = await getToken();
if (token) { if (token) {
await apiRegisteredToken({ user: entities.id, token }); await apiRegisteredToken({ user: entities.id, token, category: "register" });
} }
} catch (error) { } catch (error) {
console.warn('Error registering token:', error); console.warn('Error registering token:', error);
@@ -52,15 +54,31 @@ export default function ListSetting() {
}; };
const checkNotif = useCallback(async () => { const checkNotif = useCallback(async () => {
const status = await checkPermission(); const osPermission = await checkPermission();
setIsNotificationEnabled((prev) => {
if (prev === false && status === true) { // Jika dari tidak diijinkan sistem kemudian diijinkan (setelah balik dari pengaturan device)
registerToken(); if (prevOsPermission.current === false && osPermission === true) {
} else if (prev === true && status === false) { await registerToken();
unregisterToken(); }
prevOsPermission.current = osPermission;
if (!osPermission) {
setIsNotificationEnabled(false);
return;
}
try {
const token = await getToken();
if (token) {
const response = await apiGetCheckToken({ user: entities.id, token });
setIsNotificationEnabled(!!response.data);
} else {
setIsNotificationEnabled(false);
} }
return !!status; } catch (error) {
}); console.warn('Error checking token status:', error);
setIsNotificationEnabled(false);
}
}, [entities.id]); }, [entities.id]);
useEffect(() => { useEffect(() => {
@@ -78,10 +96,12 @@ export default function ListSetting() {
}, [checkNotif]); }, [checkNotif]);
const handleToggleNotif = async () => { const handleToggleNotif = async () => {
if (isNotificationEnabled) { const osPermission = await checkPermission();
if (!osPermission) {
setModalConfig({ setModalConfig({
title: "Matikan Notifikasi?", title: "Aktifkan Notifikasi?",
message: "Anda akan diarahkan ke pengaturan sistem untuk mematikan notifikasi.", message: "Izin notifikasi tidak diberikan. Buka pengaturan sistem untuk mengaktifkannya?",
confirmText: "Buka Pengaturan", confirmText: "Buka Pengaturan",
onConfirm: () => { onConfirm: () => {
setModalVisible(false); setModalVisible(false);
@@ -90,22 +110,17 @@ export default function ListSetting() {
}); });
setModalVisible(true); setModalVisible(true);
} else { } else {
const granted = await requestPermission(); // OS Permission is granted, perform in-app toggle
if (granted) { const targetState = !isNotificationEnabled;
setIsNotificationEnabled(true); if (targetState) {
registerToken(); await AsyncStorage.setItem('@notification_permission', "true");
await registerToken();
} else { } else {
setModalConfig({ await AsyncStorage.setItem('@notification_permission', "false");
title: "Aktifkan Notifikasi?", await unregisterToken();
message: "Izin notifikasi tidak diberikan. Buka pengaturan sistem untuk mengaktifkannya?",
confirmText: "Buka Pengaturan",
onConfirm: () => {
setModalVisible(false);
openSettings();
}
});
setModalVisible(true);
} }
// UI will be updated by checkNotif (triggered by state change or manually here)
setIsNotificationEnabled(targetState);
} }
}; };

View File

@@ -740,7 +740,7 @@ export const apiShareDocument = async (data: { dataDivision: any[], dataItem: an
return response.data; return response.data;
}; };
export const apiRegisteredToken = async (data: { user: string, token: string }) => { export const apiRegisteredToken = async (data: { user: string, token: string, category?: string }) => {
const response = await api.post(`/mobile/auth-token`, data) const response = await api.post(`/mobile/auth-token`, data)
return response.data; return response.data;
}; };
@@ -750,6 +750,11 @@ export const apiUnregisteredToken = async (data: { user: string, token: string }
return response.data; return response.data;
}; };
export const apiGetCheckToken = async (data: { user: string, token: string }) => {
const response = await api.post(`mobile/auth-token/check`, data);
return response.data;
};
export const apiGetNotification = async ({ user, page }: { user: string, page?: number }) => { export const apiGetNotification = async ({ user, page }: { user: string, page?: number }) => {
const response = await api.get(`mobile/home/notification?user=${user}&page=${page}`); const response = await api.get(`mobile/home/notification?user=${user}&page=${page}`);
return response.data; return response.data;

View File

@@ -1,3 +1,5 @@
import { ConstEnv } from '@/constants/ConstEnv';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { getApp, getApps, initializeApp } from '@react-native-firebase/app'; import { getApp, getApps, initializeApp } from '@react-native-firebase/app';
import { import {
getMessaging, getMessaging,
@@ -6,8 +8,7 @@ import {
} from '@react-native-firebase/messaging'; } from '@react-native-firebase/messaging';
import * as Notifications from 'expo-notifications'; import * as Notifications from 'expo-notifications';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { Linking, PermissionsAndroid, Platform } from 'react-native'; import { Linking, Platform } from 'react-native';
import { ConstEnv } from '@/constants/ConstEnv';
const RNfirebaseConfig = { const RNfirebaseConfig = {
apiKey: ConstEnv.firebase.apiKey, apiKey: ConstEnv.firebase.apiKey,
@@ -39,13 +40,15 @@ const initializeFirebase = async () => {
export const checkPermission = async () => { export const checkPermission = async () => {
try { try {
if (Platform.OS === 'android') { // Cek status permission sekarang
return await PermissionsAndroid.check( const { status } = await Notifications.getPermissionsAsync();
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
); if (status === 'granted') {
} else if (Platform.OS === 'ios') { return true;
const { status } = await Notifications.getPermissionsAsync(); }
return status === 'granted';
if (status === 'denied') {
return false;
} }
} catch (err) { } catch (err) {
console.warn('Error checking notification permissions:', err); console.warn('Error checking notification permissions:', err);
@@ -63,21 +66,9 @@ export const openSettings = () => {
export const requestPermission = async () => { export const requestPermission = async () => {
try { try {
if (Platform.OS === 'android') { const { status: newStatus } = await Notifications.requestPermissionsAsync();
const cek = await PermissionsAndroid.check( await AsyncStorage.setItem('@notification_permission', newStatus === 'granted' ? "true" : "false");
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS return newStatus === 'granted';
);
if (!cek) {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
);
return granted === PermissionsAndroid.RESULTS.GRANTED;
}
return true;
} else if (Platform.OS === 'ios') {
const { status } = await Notifications.requestPermissionsAsync();
return status === 'granted';
}
} catch (err) { } catch (err) {
console.warn('Error requesting notification permissions:', err); console.warn('Error requesting notification permissions:', err);
} }

View File

@@ -1,6 +1,6 @@
import { ConstEnv } from '@/constants/ConstEnv'; import { ConstEnv } from '@/constants/ConstEnv';
import { apiRegisteredToken, apiUnregisteredToken } from '@/lib/api'; import { apiRegisteredToken, apiUnregisteredToken } from '@/lib/api';
import { getToken, requestPermission } from '@/lib/useNotification'; import { getToken } from '@/lib/useNotification';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import CryptoES from "crypto-es"; import CryptoES from "crypto-es";
import { router } from "expo-router"; import { router } from "expo-router";
@@ -52,16 +52,12 @@ export default function AuthProvider({ children }: { children: ReactNode }): Rea
const signIn = useCallback(async (token: string) => { const signIn = useCallback(async (token: string) => {
const hasil = await decryptToken(String(token)) const hasil = await decryptToken(String(token))
const permission = await requestPermission() // const permission = await requestPermission()
if (permission) { const permissionStorage = await AsyncStorage.getItem('@notification_permission')
if (permissionStorage === "true") {
const tokenDevice = await getToken()
try { try {
// if (Platform.OS === 'android') {
const tokenDevice = await getToken()
const register = await apiRegisteredToken({ user: hasil, token: String(tokenDevice) }) const register = await apiRegisteredToken({ user: hasil, token: String(tokenDevice) })
// }else{
// const tokenDevice = await getToken()
// const register = await apiRegisteredToken({ user: hasil, token: String(tokenDevice) })
// }
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} finally { } finally {
@@ -71,6 +67,7 @@ export default function AuthProvider({ children }: { children: ReactNode }): Rea
return true return true
} }
} else { } else {
const register = await apiRegisteredToken({ user: hasil, token: "" })
await AsyncStorage.setItem('@token', token); await AsyncStorage.setItem('@token', token);
tokenRef.current = token; tokenRef.current = token;
router.replace('/home') router.replace('/home')