React PWA - enforce update on click - javascript

community,
I am doing "programmatic presentations" using React (CLI) and PWA (register()). Everything works just fine, but anytime some changes are made, the URL of the final app needs to be changed so all changes are loaded.
The whole mechanism works like this:
The final app is sent to Github,
this private repo is connected to Netlify,
Netlify generates a unique URL,
users visit this Netlify URL and hit "add to home screen" on iPad,
the whole app runs under the Safari engine.
If any change in the code is made, I have to change the link in Netlify and send this new link to a people.
The process mentioned above works just fine, but honestly, it would be nice to have some kind of functionality that allows request latest update on demand - let's say - on click of a button.
Is something like that possible?
Thank you for comments!
Kind Regards
Linc

At serviceWorker.js file can find this code
if (config && config.onUpdate) {
config.onUpdate(registration);
}
So implement the config.onUpdate funtion
Create a file swConfig.js
export default {
onUpdate: registration => {
registration.unregister().then(() => {
window.location.reload()
})
},
}
At index.js send the implement function to serviceWorker
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import swConfig from './swConfig'
ReactDOM.render(<App />,
document.getElementById('root'));
serviceWorker.register(swConfig);
Check out this repo
https://github.com/wgod58/create_react_app_pwaupdate

If you want to control the update with a button click, I did using the following snippet:
Note: If your app must work offline, you should add some extra logic to verify if the user has internet connection, as the following code would break the app if it's unable to fetch the service-worker.
import React from 'react';
function App(){
const updateApp = () => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
});
}}
return(
<div style={{margin:"auto"}}>
<button onClick={updateApp}>
Update App
</button>
</div>
);
}
https://gist.github.com/juliomilani/6492312d1eb657d06b13c9b87d5ad023

Related

Integrate Countly SDK Web with Typescript

Has anyone here has experience integrating Countly SDK Web with ReactJS using Typescript?
The example given here assume people use Javascript to use the SDK. I want to do something like.
import { Countly } from 'countly-sdk-web';
and use it to hit some API that has been created in Countly when webpage load. Any help would be greatly appreciated.
Note: The files is in .tsx extension
you can reach an example on how to integrate Countly Web SDK in a ReactJS project from here.
Again there, a basic example to import Countly would be like this:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App-WithEffect';
import * as serviceWorker from './serviceWorker';
import Countly from 'countly-sdk-web';
//Exposing Countly to the DOM as a global variable
//Usecase - Heatmaps
window.Countly = Countly;
Countly.init({
app_key: 'YOUR_APP_KEY',
url: 'YOUR_SERVER_URL',
session_update: 10,
use_session_cookie: true,
debug: false,
require_consent: true,
namespace: "react-demo",
inactivity_time: 1,
offline_mode: false,
// device_id: "cly-device-demo-id" //Set only if you want dont want to use countly generated device_id
});
//Since Countly is loaded and available, you can use synchronus or asynchronus calls, does not matter
Countly.q.push(['group_features', {
activity: ["sessions", "events", "views", "location"],
interaction: ["scrolls", "clicks", "crashes"],
whereabouts: ["users"]
}]);
if (typeof(localStorage) !== "undefined") {
var consents = localStorage.getItem("consents");
if(consents){
Countly.q.push(['add_consent', JSON.parse(consents)]);
}
else{
var consent = window.confirm("We are going to track you. Do you give your consent ?");
consents = ["activity", "interaction", "whereabouts"];
if(consent) {
Countly.q.push(['add_consent', consents]);
localStorage.setItem("consents", JSON.stringify(consents));
}
else {
Countly.q.push(['remove_consent', consents]);
localStorage.removeItem("consents");
}
}
}
Countly.q.push(['enableRatingWidgets', {'widgets': ['widget-id-1','widget-id-2']}]);
Countly.q.push(['track_sessions']);
Countly.q.push(['track_scrolls']);
Countly.q.push(['track_clicks']);
Countly.q.push(['track_links']);
Countly.q.push(["track_errors"]);
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
You can reach this code from here

Not able to hide react native splashscreen shown before AWS Authenticator

I'm showing the react native splashscreen and trying to hide it in useEffect, but the useEffect doesn't get called if I'm using AWS Authenticator in App.js. It works fine when I don't use the authenticator.
App.js
import Amplify from 'aws-amplify';
import config from './src/aws-exports';
import { withAuthenticator } from 'aws-amplify-react-native';
import Auth from '#aws-amplify/auth';
import SplashScreen from 'react-native-splash-screen';
import { useEffect } from 'react';
function App (){
useEffect(() => {
SplashScreen.hide();
});
return (
<View>
</View>
);
};
export default withAuthenticator(App);
It works fine without the Authenticator if I remove the last line.
You need a state change in order to proc the useEffect. And the withAuthenticator takes care of the whole login process. So to include customization i suggest using the Authenticator (Which is the wrapped component in WithAuthenticator) instead. It has onStateChange prop that you can use to detect a change of authority.
Example:
<Authenticator
// Fired when Authentication State changes, use it to hide/show stuff
onStateChange={(authState) => console.log(authState)}
>
// Default components can be customized/passed in as child components.
// Define them here if you used hideDefault={true}
</Authenticator>
Source: AWS amplify Authenticator

Office Add-ins excel extension is not working on IE11 with 'import axios' statement

I'm currently developing a Excel extension for my company with Office Add-ins and Reactjs.
Lately I've been using Axios in order to make http requests to get data from a remote back-end service. The issue is that the statement "import axios from 'axios'" is not handled in IE11 and the application runs into an exception when this statement is present in a script file. The exception is :
Office.js has not fully loaded. Your app must call "Office.onReady()" as part of it's loading sequence (or set the "Office.initialize" function). In itself that doesn't say a lot except that "the code does not compile".
After a few researches on my own I discovered that IE11 needs polyfill in order to make it work since it doesn't natively support the most recent js scripts (ES6, promises by example).
I've tried many kinds of combinations with babel/polyfill, react-app-polyfill, es-promise with no result so far. Happily, in a another application I've been working on recently (VueJs with axios), I met the same problem and just adding 'import babel/polyfill' did the trick.
I would like to know if anyone has succeeded in doing what I am trying to do for a few days and if not, any help will be appreciated. Some of my coworkers are using Windows 7 or Windows Server 2019 and I really need this excel extension to function with IE11.
Thank you for your help.
Edit on 06/29 :
Here is what I have in my index.js :
import "office-ui-fabric-react/dist/css/fabric.min.css";
import App from "./components/App";
import { AppContainer } from "react-hot-loader";
import { initializeIcons } from "office-ui-fabric-react/lib/Icons";
import * as React from "react";
import * as ReactDOM from "react-dom";
/* global AppCpntainer, Component, document, Office, module, React, require */
initializeIcons();
let isOfficeInitialized = false;
const title = "Contoso Task Pane Add-in";
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component title={title} isOfficeInitialized={isOfficeInitialized} />
</AppContainer>,
document.getElementById("container")
);
};
Office.initialize = () => {
isOfficeInitialized = true;
render(App);
};
render(App);
if (module.hot) {
module.hot.accept("./components/App", () => {
const NextApp = require("./components/App").default;
render(NextApp);
});
}
commands.js : You can see that I have a commented import statement in this file regarding axios. My intent is to make it work in the dataservice instead but I put that statement here just for testing purpose. The dataservice class itself has only one dependency : axios.
import "babel-polyfill";
// import axios from 'axios';
import DataService from '../server/dataservice';

Phonegap-plugin-push's on.('notification') doesn't fire

I'm trying to implement push-notification in my hybrid app, which is built with reactjs and cordova, using phonegap-plugin-push.
i have setup everything correctly (added the plugin, registered with firebase, the google-services.js file is in the right place).
i put this in my index.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers:
const startApp = () => {
ReactDOM.render(
<App />,
document.getElementById('root')
);
serviceWorker.unregister();
var push = window.PushNotification.init({
android:{}
});
console.log(push);
push.on('registration', function (data) {
console.log("on registration");
console.log(data);
});
push.on('notification', function (data) {
// console.log("notification received");
alert("Title:"+data.title+" Message:"+ data.message);
});
push.on('error', function (e) {
console.log(e.message)
});
}
if(!window.cordova) {
console.log("cordova is null");
startApp();
} else {
document.addEventListener('deviceready', startApp, false);
}
when i run the app on android emulator, and debug it using the chrome inspect devices, i can see the on('registration') is fired and work properly. But when i try to send a notification from firebase to the device, nothing happen.
This is how i compose my notification:
*Notification title(optional): title
Notification text: test noti
Notification label: test noti
*Target
App com.allen.thomas.netdi //the package name that i registered
*Scheduling
i chose "send now"
*Conversion events(optional)
didn't do anything with this
*Additional options(optional)
//left the Android "Notification Channel" field blank
//For custom data I filled in the following keys-values
title Test Notification
body Please work!
badge 1
content-available 1
priority: high
sound: enabled
expires: 4 weeks
then i hitted publish. But nothing happened. I don't understand what is the problem here?
Does your packagename match with the project in firebase?
Have you enabled Android Support Repository version 47+ in Android Studio?
See: https://github.com/phonegap/phonegap-plugin-push/blob/master/docs/INSTALLATION.md#android-details
It seems that i figure out the solution to this. All i need to do was adding these lines of code inside the on('notification) 's callback function:
push.finish(function(){
console.log("notification received successfully");
})
It solve my problem.

How to make a default page in React Native?

Why I have index.android.js as default. How I can make a home.js as default?
When your platform-specific code is more complex, you should consider splitting the code out into separate files. React Native will detect when a file has a .ios. or .android. extension and load the relevant platform file when required from other components.
see: https://facebook.github.io/react-native/docs/platform-specific-code.html#platform-specific-extensions
so if you add .android.js or .ios.js to your extension RN will pick one of them based on the platform. If you want the same component for both platform just don't add platform specific extension and use just foo.js
I think what you asked for can be done this way:
import { AppRegistry } from 'react-native';
import Home from './path/to/home';
AppRegistry.registerComponent('SBlank', () => Home);
By doing this in both your index.android.js and index.ios.js you redirect your app to Home.js file.
Bonus: In addition to knowbody's answer, you can use Platform object to change how your code works on different platforms. For example:
render() {
if (Platform.OS === 'android') {
return this.renderAndroid();
}
return this.renderIOS();
}
where you import Platform by adding
import { Platform } from 'react-native';

Categories

Resources