File "PushNotification.jsx"
Full Path: /home/trinadezambia/public_html/student_panel/src/lib/PushNotification.jsx
File size: 3.98 KB
MIME-type: text/x-java
Charset: utf-8
'use client';
import React from 'react';
import { useForegroundNotifications } from '@/lib/firebase/useForegroundNotifications';
import { useSyncFCMToken } from '@/lib/firebase/useSyncFCMToken';
import ServiceWorkerNavigationListener from '@/lib/firebase/ServiceWorkerNavigationListener';
import {
NotificationProvider,
useNotification,
} from '@/lib/firebase/NotificationContext';
import { useQueryClient } from '@tanstack/react-query';
import { useGetSchoolSettings } from '@/lib/api/student/queryHooks';
import { showNotificationIfNeeded } from './notificationHelper';
/**
* Inner component to use the hook inside the provider
*/
const PushNotificationContent = ({ children, onNotificationReceived }) => {
const { setLastNotification } = useNotification();
const queryClient = useQueryClient();
const { data: settingsData } = useGetSchoolSettings();
const logoUrl = settingsData?.data?.settings?.favicon;
const handleNotification = React.useCallback(
(payload) => {
// Check if this is a navigation message (from clicked notification)
// Navigation messages should NOT trigger a new notification
const isNavigationMessage =
payload.action === 'navigate' || payload.type === 'NAVIGATE';
// If it's a navigation message, skip notification display
if (isNavigationMessage) {
// console.log('[PushNotification] Navigation message received, skipping notification display');
return;
}
// Update the context
setLastNotification(payload);
// Show notification if needed (e.g. not on chat page)
showNotificationIfNeeded(payload, logoUrl);
// Invalidate queries based on notification type to ensure fresh data
const type = payload.data?.type || payload.notification?.type;
const lowerType = type?.toLowerCase();
// Always invalidate notifications list
queryClient.invalidateQueries({ queryKey: ['student', 'notifications'] });
if (lowerType) {
if (lowerType === 'assignment') {
queryClient.invalidateQueries({
queryKey: ['student', 'assignments'],
});
} else if (lowerType === 'message') {
// ChatWindow handles this, but good to have backup
queryClient.invalidateQueries({ queryKey: ['chat', 'messages'] });
} else if (
lowerType === 'exam' ||
lowerType === 'exam result' ||
lowerType === 'result'
) {
queryClient.invalidateQueries({ queryKey: ['online-exam-list'] });
queryClient.invalidateQueries({ queryKey: ['offline-exam-list'] });
queryClient.invalidateQueries({
queryKey: ['online-exam-result-list'],
});
} else if (lowerType === 'lesson') {
queryClient.invalidateQueries({ queryKey: ['lessons'] });
queryClient.invalidateQueries({ queryKey: ['subject-details'] });
} else if (lowerType === 'attendance') {
queryClient.invalidateQueries({ queryKey: ['attendance'] });
} else if (lowerType === 'class section') {
queryClient.invalidateQueries({ queryKey: ['subject-details'] });
}
}
// Call the original prop if provided
if (onNotificationReceived) {
onNotificationReceived(payload);
}
},
[setLastNotification, queryClient, onNotificationReceived, logoUrl]
);
useForegroundNotifications(handleNotification);
useSyncFCMToken();
return (
<>
<ServiceWorkerNavigationListener onMessage={handleNotification} />
{children}
</>
);
};
/**
* PushNotificationLayout centralizes all notification-related hooks.
* It keeps hooks alive and renders the service worker listener once.
*/
const PushNotificationLayout = ({
children,
onNotificationReceived = () => {},
}) => {
return (
<NotificationProvider>
<PushNotificationContent onNotificationReceived={onNotificationReceived}>
{children}
</PushNotificationContent>
</NotificationProvider>
);
};
export default PushNotificationLayout;