fix: add null checks for document and firebase messaging to prevent SSR errors
Added defensive programming by adding null checks for document object before accessing its properties and methods across multiple components (MultiSelect, ConfirmationModal, Dropdown, Modal). Also implemented lazy initialization for Firebase messaging to prevent SSR-related errors and ensure messaging is only initialized on the client side. These changes improve server-side rendering compatibility and prevent potential runtime errors.
This commit is contained in:
@@ -130,8 +130,9 @@ function MultiSelect<T extends FieldValues>({
|
||||
return;
|
||||
setShow(false);
|
||||
};
|
||||
|
||||
document?.addEventListener("click", clickHandler);
|
||||
return () => document.removeEventListener("click", clickHandler);
|
||||
return () => document?.removeEventListener("click", clickHandler);
|
||||
}, [show]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -8,12 +8,15 @@ import { toast } from "react-toastify";
|
||||
|
||||
const Notification = ({ children }: PropsWithChildren) => {
|
||||
useEffect(() => {
|
||||
onMessage(messaging, (payload) => {
|
||||
console.log("Message received. ", payload);
|
||||
if (payload.notification) {
|
||||
toast.success(payload.notification.title ?? "New Notification");
|
||||
}
|
||||
});
|
||||
const messagingInstance = messaging();
|
||||
if (messagingInstance) {
|
||||
onMessage(messagingInstance, (payload) => {
|
||||
console.log("Message received. ", payload);
|
||||
if (payload.notification) {
|
||||
toast.success(payload.notification.title ?? "New Notification");
|
||||
}
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return <>{children}</>;
|
||||
|
||||
@@ -54,12 +54,12 @@ const ConfirmationModal: React.FC<ConfirmationModalProps> = (props) => {
|
||||
|
||||
if (isOpen) {
|
||||
document?.addEventListener("keydown", handleEscape);
|
||||
document.body.style.overflow = "hidden";
|
||||
if (document) document.body.style.overflow = "hidden";
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleEscape);
|
||||
document.body.style.overflow = "unset";
|
||||
document?.removeEventListener("keydown", handleEscape);
|
||||
if (document) document.body.style.overflow = "unset";
|
||||
};
|
||||
}, [isOpen, onCancel]);
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@ export function Dropdown({ children, isOpen, setIsOpen }: DropdownProps) {
|
||||
if (isOpen) {
|
||||
triggerRef.current = document.activeElement as HTMLElement;
|
||||
|
||||
document.body.style.pointerEvents = "none";
|
||||
if (document) document.body.style.pointerEvents = "none";
|
||||
} else {
|
||||
document.body.style.removeProperty("pointer-events");
|
||||
if (document) document.body.style.removeProperty("pointer-events");
|
||||
|
||||
setTimeout(() => {
|
||||
triggerRef.current?.focus();
|
||||
|
||||
@@ -33,13 +33,13 @@ const Modal: React.FC<ModalProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
document.body.style.overflow = "hidden";
|
||||
if (document) document.body.style.overflow = "hidden";
|
||||
} else {
|
||||
document.body.style.overflow = "unset";
|
||||
if (document) document.body.style.overflow = "unset";
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.body.style.overflow = "unset";
|
||||
if (document) document.body.style.overflow = "unset";
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { COOKIE_KEYS } from "@/lib/shared/cookies";
|
||||
import { initializeApp } from "firebase/app";
|
||||
import { getMessaging, getToken } from "firebase/messaging";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
const firebaseConfig = {
|
||||
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
|
||||
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
||||
@@ -11,11 +12,35 @@ const firebaseConfig = {
|
||||
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
|
||||
};
|
||||
|
||||
// Initialize Firebase app
|
||||
const app = initializeApp(firebaseConfig);
|
||||
export const messaging = getMessaging(app);
|
||||
|
||||
// Lazy initialization of messaging to avoid SSR issues
|
||||
let messaging: any = null;
|
||||
|
||||
const getMessagingInstance = () => {
|
||||
if (typeof window !== 'undefined' && !messaging) {
|
||||
try {
|
||||
messaging = getMessaging(app);
|
||||
} catch (error) {
|
||||
console.warn('Failed to initialize Firebase Messaging:', error);
|
||||
}
|
||||
}
|
||||
return messaging;
|
||||
};
|
||||
|
||||
export const requestForToken = () => {
|
||||
return getToken(messaging)
|
||||
// Only run on client side
|
||||
if (typeof window === 'undefined') {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
const messagingInstance = getMessagingInstance();
|
||||
if (!messagingInstance) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return getToken(messagingInstance)
|
||||
.then((currentToken) => {
|
||||
if (currentToken) {
|
||||
console.log("current token for client: ", currentToken);
|
||||
@@ -27,9 +52,13 @@ export const requestForToken = () => {
|
||||
);
|
||||
// ...
|
||||
}
|
||||
return currentToken;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("An error occurred while retrieving token. ", err);
|
||||
// ...
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
export { getMessagingInstance as messaging };
|
||||
|
||||
Reference in New Issue
Block a user