Notifications API onclose event not firing - reactjs

I am trying to kick off some behavior within our application from a notification that is created using the Notification API. I doing this with some success, but we need the same behavior whether the user clicks the notification or closes the notification by clicking the X and for whatever reason the onclose event does not fire regardless of browser. This is a react application and the code looks something like this:
`async function showNotification() {
if (Notification.permission !== "granted") {
await Notification.requestPermission()
}
if (Notification.permission === "granted") {
const notification = new Notification('New Camera Alerts', {
body: 'There are new notifications to review in the Notification Panel',
icon: `${logo}`,
requireInteraction: true // this makes the dialog stay open until someone clicks it
})
const testEvent = (event: Event) => {
event.preventDefault()
// more lines of code here with what should happen when the
// notification is clicked/closed
}
notification.onclick = (event) => testEvent (event)
notification.onclose = (event) => testEvent (event)
}
}`
What I tried is assigning the same function call to both the click and close handlers. I was expecting both actions to have the same behavior. What actually happens is the close event is never fired at all.

Related

How to detect click outside React APPLICATION?

I want a functional React component to close whenever the user clicks outside the application as well as outside the component within the application.
I've worked out how to close the component so long as the user clicks inside the containing application, but it still ignores clicks in an entirely different Windows application.
I want to emulate the behavior of the "Avatar" button at the top right of a Google Maps window. The button opens a modal dialog that is dismissed when the user clicks anywhere outside the dialog.
My current code has a useEffect hook that calls addEventListener and removeEventListener on the current document:
useEffect(() => {
const handleClickOutside = (event) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
onCloseButtonClick(event)
}
};
document.addEventListener("click", handleClickOutside, true);
return () => {
document.removeEventListener("click", handleClickOutside, true);
};
}, [onCloseButtonClick]);
I had hoped the solution was as simple as attaching addEventListener and removeEventListener on window instead of document, but it doesn't work.
How can I clear the visible property of the component when the user clicks outside the containing application?
Thanks in advance for your attention.
You probably need to also listen to onblur on the window. That can call the onCloseButtonClick straight away as theres no element attached to those events.
useEffect(() => {
const handleClickOutside = (event) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
onCloseButtonClick(event)
}
};
document.addEventListener("click", handleClickOutside, true);
window.addEventListener("blur", onCloseButtonClick, true);
return () => {
document.removeEventListener("click", handleClickOutside, true);
window.removeEventListener("blur", onCloseButtonClick, true);
};
}, [onCloseButtonClick]);

Can you use an 'beforeunload' listener in an export default function? If so how?

All examples I am seeing online are using React Components. I am a newbie to react. So any explanation will be helpful, and what I should do to achieve this.
export default function Review() {
...
useEffect(() => {
console.log("useeffect called")
window.addEventListener("beforeunload", save());
}, []);
...
return (...);
Here is a CodeSandbox.io link. Here you will find that I have 2 pages 1 home the other dashboard.
When I go to dashboard. I get the Alert. But Leaving Dashboard I do not get the Alert Message. beforeunload is not working how I expect it to.
https://codesandbox.io/s/react-router-basic-forked-8uvvi?file=/
An alternate way to call a function when a page/component is about to be unmounted is to add it as a return from your useEffect(). For example:
useEffect(() => {
return(() => save())
}, []);
CodeSandbox Example
You are not passing an onbeforeunload callback, you are immediately invoking the alert.
useEffect(() => {
console.log("useeffect called");
// subscribe event
window.addEventListener("beforeunload", alert("HI"));
}, []);
Create/define a callback that does one, or more, of the following:
Prevents the default on the event object
Assigns a string to the event object's returnValue property
Returns a string from the event handler.
window.beforeunload
Note: To combat unwanted pop-ups, some browsers don't display prompts created in beforeunload event handlers unless the page has
been interacted with. Moreover, some don't display them at all.
Code suggestion
useEffect(() => {
const handler = (e) => {
// Cancel the event
e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
// Chrome requires returnValue to be set
e.returnValue = "";
// ... business logic to save any data, etc... before the window unloads
save();
return "";
};
// subscribe event
window.addEventListener("beforeunload", handler);
return () => {
window.removeEventListener("beforeunload", handler);
};
}, []);

Put A Warning If Page Refresh in ReactJS

My problem is that I need the user to confirm if he wants to continue to refresh the page. If he press No, it won't refresh the page.
Kindly take a look at my development so far:-
useEffect(() => {
window.addEventListener("beforeunload", alertUser);
return () => {
window.removeEventListener("beforeunload", alertUser);
};
}, []);
If you want to display a sort of confirmation before leaving the page then follow the beforeunload event guidelines
According to the specification, to show the confirmation dialog an
event handler should call preventDefault() on the event.
However note that not all browsers support this method, and some
instead require the event handler to implement one of two legacy
methods:
assigning a string to the event's returnValue property
returning a string from the event handler.
To combat unwanted pop-ups, browsers may not display prompts created
in beforeunload event handlers unless the page has been interacted
with, or may even not display them at all.
The HTML specification states that calls to window.alert(),
window.confirm(), and window.prompt() methods may be ignored during
this event. See the HTML specification for more details.
I just tested this in chrome and safari and it works. I don't have a windows box, but this should cover most cases.
useEffect(() => {
const unloadCallback = (event) => {
event.preventDefault();
event.returnValue = "";
return "";
};
window.addEventListener("beforeunload", unloadCallback);
return () => window.removeEventListener("beforeunload", unloadCallback);
}, []);
I think you are looking for this.
https://dev.to/eons/detect-page-refresh-tab-close-and-route-change-with-react-router-v5-3pd
Browser Refresh, Closing Tab, and back and forward buttons, are all explained.
Try this:
useEffect(()=>{
const unloadCallback = (event) => {
const e = event || window.event;
//console.log(e)
e.preventDefault();
if (e) {
e.returnValue = ''
}
return '';
};
window.addEventListener("beforeunload", unloadCallback);
return () => {
//cleanup function
window.removeEventListener("beforeunload", unloadCallback);
}
},[])

Show default browser dialog to prevent user from going back

I know many questions about this have already been asked but I'm struggling finding what I need. I am using react-router 5.1.2 to manage navigation in my web-app. I want to alert the user before he leaves the page. Attach beforeUnload listener does not work when users press the browser's back button. I understand I can use history.block() or <Prompt>, but the alert does not behaves like the default one shown when beforeUnload is fired, e.g. I can press back button twice then press "cancel" and have inconsistencies between the route and the actual rendered component. The question is: how can I alert the user pressing back button obtaining a confirmation dialog that behaves as the default one (preventing further actions other than those proposed by the alert)?
This is the custom hook I've used so far:
const alertUser = (e: BeforeUnloadEvent | PopStateEvent) => {
e.preventDefault();
e.returnValue = '';
};
export const useAlertBeforeLeaving = (showAlert = true) => {
const history = useHistory();
const unblock = useRef<UnregisterCallback | null>(null);
useEffect(() => {
if (showAlert) {
window.addEventListener('beforeunload', alertUser);
unblock.current = history.block('Leave the page?');
}
return () => {
if (showAlert && unblock.current) {
window.removeEventListener('beforeunload', alertUser);
unblock.current();
}
};
}, [history, showAlert]);
};

Intercept back event in an react app to confirm save

I am building a react native app using expo.io.
The app is using a Stack Navigator to move between pages (cards).
My problem is that I have one page where users can create new items and I want to save the items when they leave the page.
Instead of saving all their changes, I want to prompt the user if they want to save changes before leaving the page so they get a chance to discard any changes they have made.
I have not been able to find an event for exiting the page that I can hook into and prompt the user if they want to save their changes?
The closest I have found to what I want to do is in backhandler, but that only works for Android back button.
Is there a way to do something similar if the user goes back with the back button in the header of the card, or if they use a swipe gesture?
Use NavigationEvents. Add event listeners to your components.
onWillFocus - event listener
onDidFocus - event listener
onWillBlur - event listener
onDidBlur - event listener
for example, the following will get fired when the next screen is focused.In the other screen, save user's changes in temporary storage, when they navigate back, get those unsaved changes and prompt the user, whether they want to save or not.
focusSubscription = null;
onWillFocus = (payload) => {
if (payload && payload.action && payload.action.type && payload.action.type === 'Navigation/BACK') {
// get values from storage here
// if there were unsaved changes prompt the user if they want to those changes or not
}
};
componentDidMount = () => {
this.focusSubscription = this.props.navigation.addListener(
'willFocus',
this.onWillFocus,
);
}
componentWillUnmount = () => {
this.focusSubscription && this.focusSubscription.remove();
this.focusSubscription = null;
};
Demo
React Navigation added in version 5.7 the beforeRemove event which you can use for this.
This is the demo from their site:
function EditText({ navigation }) {
const [text, setText] = React.useState('');
const hasUnsavedChanges = Boolean(text);
React.useEffect(
() =>
navigation.addListener('beforeRemove', (e) => {
if (!hasUnsavedChanges) {
// If we don't have unsaved changes, then we don't need to do anything
return;
}
// Prevent default behavior of leaving the screen
e.preventDefault();
// Prompt the user before leaving the screen
Alert.alert(
'Discard changes?',
'You have unsaved changes. Are you sure to discard them and leave the screen?',
[
{ text: "Don't leave", style: 'cancel', onPress: () => {} },
{
text: 'Discard',
style: 'destructive',
// If the user confirmed, then we dispatch the action we blocked earlier
// This will continue the action that had triggered the removal of the screen
onPress: () => navigation.dispatch(e.data.action),
},
]
);
}),
[navigation, hasUnsavedChanges]
);
return (
<TextInput
value={text}
placeholder="Type something…"
onChangeText={setText}
/>
);
}

Resources