import HeaderRightAnnouncementList from "@/components/announcement/headerAnnouncementList"; import AppHeader from "@/components/AppHeader"; import Styles from "@/constants/Styles"; import HeaderDiscussionGeneral from "@/components/discussion_general/headerDiscussionGeneral"; import HeaderRightDivisionList from "@/components/division/headerDivisionList"; import HeaderRightGroupList from "@/components/group/headerGroupList"; import HeaderMemberList from "@/components/member/headerMemberList"; import HeaderRightPositionList from "@/components/position/headerRightPositionList"; import HeaderRightProjectList from "@/components/project/headerProjectList"; import Text from "@/components/Text"; import ToastCustom from "@/components/toastCustom"; import ModalUpdateMaintenance from "@/components/ModalUpdateMaintenance"; import { apiGetVersion, apiReadOneNotification } from "@/lib/api"; import { pushToPage } from "@/lib/pushToPage"; import store from "@/lib/store"; import { useAuthSession } from "@/providers/AuthProvider"; import AsyncStorage from "@react-native-async-storage/async-storage"; import Constants from "expo-constants"; import { getApp } from "@react-native-firebase/app"; import { getMessaging, onMessage } from "@react-native-firebase/messaging"; import { Redirect, router, Stack, usePathname } from "expo-router"; import { StatusBar } from 'expo-status-bar'; import { useEffect, useState } from "react"; import { Easing, Notifier, NotifierComponents } from 'react-native-notifier'; import { Provider } from "react-redux"; import { useTheme } from "@/providers/ThemeProvider"; export default function RootLayout() { const { token, decryptToken, isLoading } = useAuthSession() const pathname = usePathname() const { colors } = useTheme() const [modalUpdateMaintenance, setModalUpdateMaintenance] = useState(false) const [modalType, setModalType] = useState<'update' | 'maintenance'>('update') const [isForceUpdate, setIsForceUpdate] = useState(false) const [updateMessage, setUpdateMessage] = useState('') const currentVersion = Constants.expoConfig?.version ?? '0.0.0' const compareVersions = (v1: string, v2: string) => { const parts1 = v1.split('.').map(Number); const parts2 = v2.split('.').map(Number); for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { const p1 = parts1[i] || 0; const p2 = parts2[i] || 0; if (p1 < p2) return -1; if (p1 > p2) return 1; } return 0; }; useEffect(() => { const checkVersion = async () => { try { const response = await apiGetVersion(); if (response.success && response.data) { const maintenance = response.data.find((item: any) => item.id === 'mobile_maintenance')?.value === 'true'; const latestVersion = response.data.find((item: any) => item.id === 'mobile_latest_version')?.value || '0.0.0'; const minVersion = response.data.find((item: any) => item.id === 'mobile_minimum_version')?.value || '0.0.0'; const message = response.data.find((item: any) => item.id === 'mobile_message_update')?.value || ''; if (maintenance) { setModalType('maintenance'); setModalUpdateMaintenance(true); setIsForceUpdate(true); return; } if (compareVersions(currentVersion, minVersion) === -1) { setModalType('update'); setIsForceUpdate(true); setUpdateMessage(message); setModalUpdateMaintenance(true); } else if (compareVersions(currentVersion, latestVersion) === -1) { // Check if this soft update version was already dismissed const dismissedVersion = await AsyncStorage.getItem('dismissed_update_version'); if (dismissedVersion !== latestVersion) { setModalType('update'); setIsForceUpdate(false); setUpdateMessage(message); setModalUpdateMaintenance(true); } } } } catch (error) { console.error('Failed to check version:', error); } }; checkVersion(); }, [currentVersion]); const handleDismissUpdate = async () => { if (!isForceUpdate) { try { const response = await apiGetVersion(); const latestVersion = response.data.find((item: any) => item.id === 'mobile_latest_version')?.value; if (latestVersion) { await AsyncStorage.setItem('dismissed_update_version', latestVersion); } } catch (e) { console.error(e); } setModalUpdateMaintenance(false); } } async function handleReadNotification(id: string, category: string, idContent: string, title: string) { try { if (title != "Komentar Baru") { const hasil = await decryptToken(String(token?.current)) const response = await apiReadOneNotification({ user: hasil, id: id }) } pushToPage(category, idContent) } catch (error) { console.error(error) } } useEffect(() => { const checkNavigation = async () => { const navData = await AsyncStorage.getItem('navigateOnOpen'); if (navData) { const { screen, content } = JSON.parse(navData); await AsyncStorage.removeItem('navigateOnOpen'); // reset pushToPage(screen, content) } }; checkNavigation(); }, []); useEffect(() => { const mess = getMessaging(getApp()); const unsubscribe = onMessage(mess, async remoteMessage => { const id = remoteMessage?.data?.id; const category = remoteMessage?.data?.category; const content = remoteMessage?.data?.content; const title = remoteMessage?.notification?.title; if (remoteMessage.notification?.title && remoteMessage.notification?.body) { if (category === 'discussion-general' && pathname === '/discussion/' + content) { return null; } else if (pathname !== `/${category}/${content}`) { Notifier.showNotification({ title: title, description: String(remoteMessage.notification?.body), duration: 3000, animationDuration: 300, showEasing: Easing.ease, onPress: () => handleReadNotification(String(id), String(category), String(content), String(title)), hideOnPress: true, Component: NotifierComponents.Notification, componentProps: { containerStyle: [ Styles.shadowBox, { backgroundColor: colors.modalBackground, borderRadius: 5, marginHorizontal: 15, marginTop: 10, padding: 15, } ], titleStyle: { color: colors.text, fontWeight: 'bold', fontSize: 16, }, descriptionStyle: { color: colors.dimmed, fontSize: 14, }, } }); } } }); return unsubscribe; }, [pathname]); if (isLoading) { return Loading...; } if (!token?.current) { return ; } return ( { router.back() }} />, headerTitle: 'Notifikasi', headerTitleAlign: 'center', header: () => ( router.back()} /> ) }} /> { router.back() }} />, title: 'Pengaturan', headerTitleAlign: 'center', // headerRight: () => header: () => ( router.back()} /> ) }} /> { router.back() }} />, title: 'Anggota', headerTitleAlign: 'center', // headerRight: () => header: () => ( router.back()} right={} /> ) }} /> { router.back() }} />, title: 'Diskusi Umum', headerTitleAlign: 'center', // headerRight: () => header: () => ( router.back()} right={} /> ) }} /> { router.back() }} />, title: 'Kegiatan', headerTitleAlign: 'center', // headerRight: () => header: () => ( router.back()} right={} /> ) }} /> { router.back() }} />, title: 'Divisi', headerTitleAlign: 'center', // headerRight: () => header: () => ( router.back()} right={} /> ) }} /> { router.back() }} />, headerTitle: 'Lembaga Desa', headerTitleAlign: 'center', // headerRight: () => header: () => ( router.back()} right={} /> ) }} /> { router.back() }} />, headerTitle: 'Jabatan', headerTitleAlign: 'center', // headerRight: () => header: () => ( router.back()} right={} /> ) }} /> { router.back() }} />, headerTitle: 'Pengumuman', headerTitleAlign: 'center', // headerRight: () => header: () => ( router.back()} right={} /> ) }} /> ) }