I want to use pusher.js in service worker for sending notification to user when the app(pwa) is closed. But I get below error in pusher.js:
window is not defined
I got the answer, in service worker you can not import pusher as below:
import Pusher from 'pusher-js';
Instead import as below:
importScripts("https://js.pusher.com/7.0/pusher.worker.min.js");
Or
import Pusher from 'pusher-js/worker';
According with Pusher docs the correct way to import the script is:
importScripts("https://js.pusher.com/beams/service-worker.js");
// The rest of your Service Worker code goes here...
Not sure what are you trying to achieve but in my case I needed to manipulate the new notifications to display different messages, and I made it using:
importScripts("https://js.pusher.com/beams/service-worker.js");
PusherPushNotifications.onNotificationReceived = ({ pushEvent, payload }) => {
// NOTE: Overriding this method will disable the default notification
// handling logic offered by Pusher Beams. You MUST display a notification
// in this callback unless your site is currently in focus
// https://developers.google.com/web/fundamentals/push-notifications/subscribing-a-user#uservisibleonly_options
// Your custom notification handling logic here 🛠️
// https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification
pushEvent.waitUntil(
self.registration.showNotification(payload.notification.title, {
body: payload.notification.body,
icon: payload.notification.icon,
data: payload.data,
})
);
};
Source: https://pusher.com/docs/beams/guides/handle-incoming-notifications/web/
Related
I want to implement an "isActive" feature on my app that is built using firebase firestore. I am using firebase functions along with authentication in my React App.
Is there a way of detecting if the user is "active" or "inActive" on my app by triggering a cloud function when they login or disconnect to the app?
If i can determine this i would store the value in firestore and handle it in the frontend to display a UI.
Thanks
I see two aspects to the question here:
Auth state: You want to track the logged-in duration of the user.
Focus state: You want to track when the user is active on the app.
For #1, you will have to listen to the auth state changes, and you may also want to change your auth state persistence strategy accordingly. From https://firebase.google.com/docs/auth/web/auth-state-persistence:
Enum
Value
Description
firebase.auth.Auth.Persistence.LOCAL
'local'
Indicates that the state will be persisted even when the browser window is closed or the activity is destroyed in React Native. An explicit sign out is needed to clear that state. Note that Firebase Auth web sessions are single host origin and will be persisted for a single domain only.
firebase.auth.Auth.Persistence.SESSION
'session'
Indicates that the state will only persist in the current session or tab, and will be cleared when the tab or window in which the user authenticated is closed. Applies only to web apps.
firebase.auth.Auth.Persistence.NONE
'none'
Indicates that the state will only be stored in memory and will be cleared when the window or activity is refreshed.
import { getAuth, setPersistence, signInWithRedirect, inMemoryPersistence, GoogleAuthProvider } from "firebase/auth";
const auth = getAuth();
setPersistence(auth, inMemoryPersistence)
.then(() => {
const provider = new GoogleAuthProvider();
// In memory persistence will be applied to the signed in Google user
// even though the persistence was set to 'none' and a page redirect
// occurred.
return signInWithRedirect(auth, provider);
})
.catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
});
You don't need a cloud function for th
For #2, you might want to check out this blog. https://javascript.plainenglish.io/validate-your-apps-session-on-focus-892f610f7e23.
import { useLocation } from '#reach/router';
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
export function WindowFocusHandler() {
const dispatch = useDispatch()
const location = useLocation()
useEffect(() => {
window.addEventListener("focus", onFocus)
return () => {
window.removeEventListener("focus", onFocus)
}
}, [])
const onFocus = () => dispatch(session.effects.checkSessionOnFocus(location))
return <></>
}
The Focus event on a window might get triggered more often if it is a browser app. Depending on what you want to achieve, both things should be possible in
your front-end code without the need for cloud functions. Although, you might opt to code the logic as a firebase function and invoke it from your react code when onFocus.
I've been using events in my ionic application, where i subscribe in one page, and publish the event in the other page. Now I see a warning that Events are going to be changed with Observables and Redux state and effect.
I was using Events mainly to call for component function changes outside it, so I had a components for example:
Component1.ts
this.events.subscribe('event:addValue1', (data: any) => {
this.valueName = 'VALUE1';
});
this.events.subscribe('event:addValue2', (data: any) => {
this.valueName = 'VALUE2';
});
and than outside this component I was calling the publish methods from any page, like:
Page1.ts
this.events.publish('event:addValue1');
Page2.ts
this.events.publish('event:addValue2');
By this i was able to change the data (this.valueName) outside the Component1.ts from any other page, simply by publishing the desired event.
I know that this might not sound or be right approach, but It was the only way I was doing changes to my Component1.ts outside it from any page.
I have now changed this and just put separate functions and than i access them via ViewChild component name like
#ViewChild('component') component: any;
....
this.component.functionAddValue1().
and additionally I send additional params via Angular NavigationExtras if i need to calculate and call some function from the Component1.ts, lets say if I navigate to some route.
Before this I was just calling the events.publish and I was able to make the changes to the Component1.ts on the fly.
Create event service.
In the EventService.ts:
export class EventService {
private dataObserved = new BehaviorSubject<any>('');
currentEvent = this.dataObserved.asObservable();
constructo(){}
publish(param):void {
this.dataObserved.next(param);
}
}
For publishing the event from example page1:
constructor(public eventService:EventService){}
updatePost(value){
this.eventService.publish({name:'post:updated',params:value});
}
In page 2:
constructor(public eventService:EventService){
eventService.currentEvent.subscribe(value=>{
if(value.name=='post:updated'){
//get value.name
}else if(value.name=='another:event'){
//get value or update view or trigger function or method...
}
// here you can get the value or do whatever you want
});
}
I'm working with cordova's BLE (bluetooth low energy)
After I subscribe to notifications of BLE (which returns Observable), I want to send some message to the ble device, what is the best way to perform this, basically I need to run a function once after the subscription is made so that once device responds back to me, the code in the subscription is run.
ble.startNotification(deviceId, uuid1, uuid2).subscribe(bufferData=> {
//do something with bufferData
})
now after this, I want to run something like a callback,
.then(()=> {
//send message to device (only once), after the message is sent, the device will respond back and the `do something with bufferData` code will be run
})
I could easily do a setTimeout and send a message to the device after few seconds, and of course it works, but I want to do it cleanly, after I'm sure the subscription happened (subscription to the Observable of course)
You can wrap existing method using create operator and add custom code that will be executed on every new subscription.
See the example:
// emulate cordova with "dummy" bluetooth interface
const BLE = {
startNotification: () => Rx.Observable.interval(1000)
}
const wrappedBLE = (...params) =>
Rx.Observable.create(observer => {
// constructor fn will be executed on every new subscribtion
const disposable = BLE.startNotification(...params).subscribe(observer);
// place code to send notification here, instead of console log
console.log('New subscriber for BLE with params: ', params);
return disposable;
});
wrappedBLE("param1", "param2", "param3")
.subscribe(e => console.log("received notification: ", e));
<script src="https://unpkg.com/rxjs#5.4.3/bundles/Rx.min.js"></script>
I'am building a react/meteor app. I'm having a problem with subscriptions. There's a component that is showed when the subscriotion.ready() is false. When it's turned to true the component is replaced by a table with data, but it takes a few seconds between the ready and the data from find().fetch(), showing another component for a while.
Any suggestion ?
Thanks
If you are using react-meteor-data you can get the subscription status in ready property. Then you can send this property to the presentation component and update it accordingly.
Sample code snippet from the package's documentation:
import { createContainer } from 'meteor/react-meteor-data';
export default PresenterContainer = createContainer(props => {
// Do all your reactive data access in this method.
// Note that this subscription will get cleaned up when your component is unmounted
const handle = Meteor.subscribe('publication_name');
return {
isReady: ! handle.ready(),
list: CollectionName.find().fetch(),
};
}, PresenterComponent);
Explanation:
The first argument to createContainer is a reactive function that will get re-run whenever its reactive inputs change.
The PresenterComponent component will receive {isReady, list} as props. So, you can render your component according to the status of isReady
Addition:
Write your render method of the presenter component like this:
render(){
if(!this.isReady) return <LoadingComponent/>
else if(this.props.list.length() != 0) return <TableComponent/>
else return <NoDataFoundComponent/>
}
Here is my use case:
I have two different apps, react client app and express/node backend server app having REST APIs. I want the react client app to refresh the component states, every time the Server sends an event on the socket which has change of the data on the server side.
I have seen examples of websocket doing this (http://www.thegreatcodeadventure.com/real-time-react-with-socket-io-building-a-pair-programming-app/) but in this case the client and the server components are in the same app. How to do this when you different apps for client and the server components.
Should I use Timer (https://github.com/reactjs/react-timer-mixin) to make a call from the client to the server rest endpoint and refresh the components on the client if there is any change in data. Or does redux middleware provide those capabilities..
thanks, Rajesh
I think what you are looking for is something like react-redux. This allows you to connect the component to depend on a piece of the state tree and will be updated whenever the state changes (as long as you are applying new references). See below:
UserListContainer.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as UserActions from '../actions/userActions';
import UserList from '../components/UserList';
class UserListContainer {
// Subscribe to changes when the component mounts
componentDidMount() {
// This function
this.props.UserActions.subscribe();
}
render() {
return <UserList {...props} />
}
}
// Add users to props (this.props.users)
const mapStateToProps = (state) => ({
users: state.users,
});
// Add actions to props
const mapDispatchToProps = () => ({
UserActions
});
// Connect the component so that it has access to the store
// and dispatch functions (Higher order component)
export default connect(mapStateToProps)(UserListContainer);
UserList.jsx
import React from 'react';
export default ({ users }) => (
<ul>
{
users.map((user) => (
<li key={user.id}>{user.fullname}</li>
));
}
</ul>
);
UserActions.js
const socket = new WebSocket("ws://www.example.com/socketserver");
// An action creator that is returns a function to a dispatch is a thunk
// See: redux-thunk
export const subscribe = () => (dispatch) => {
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'user add') {
// Dispatch ADD_USER to be caught in the reducer
dispatch({
type: 'ADD_USER',
payload: {
data.user
}
});
}
// Other types to change state...
};
};
Explanation
Essentially what is happening is that when the container component mounts it will dispatch a subscribe action which will then listed for messages from the socket. When it receives a message it will dispatch another action base off of its type with the corresponding data which will be caught in the reducer and added to state. *Note: Do not mutate the state or the component will not reflect the changes when it is connected.
Then we connect the container component using react-redux which applies state and actions to props. So now any time the users state changes it will send it to the container component and down to the UserList component for rendering.
This is a naive approach but I believe it illustrates the solution and gets you on the right track!
Good luck and hope this helped!