How to create a Google web app using Google Apps Script, React, and MobX - reactjs

I found react-google-apps-script project on GitHub, and it seems to be able to make my dreams of a React-based Google Apps Script project a reality. For a while, since I learned React (and MobX), I've been wanting to use it inside Google Apps Script projects!
Per the documentation, however, it seems to only work on dialog windows... :'(
That being said, I have a freelancing client who is looking for a UI that can interact with her Google Sheets, to which the most reasonable approach would be to create a web app. I've created Google Apps Script based web apps in the past, in fact it was my very first exposure to it. It seems like they only support raw HTML templates and jQuery .
However, knowing all that I know now, I'd like to create a simple React + MobX MVVM-based web app on the Google Apps Script. How can we use this project to get that done?

UPDATE: I should have read more carefully! This is embarassing!!
From looking at src/server/ui.js, I see that is how the main use case, injecting React project into the modals in Google Apps Script projects that control Google Spreadsheets, even gets to happen.
Here is the code from that file:
export const onOpen = () => {
const menu = SpreadsheetApp.getUi()
.createMenu('My Sample React Project') // edit me!
.addItem('Sheet Editor', 'openDialog')
.addItem('Sheet Editor (Bootstrap)', 'openDialogBootstrap')
.addItem('About me', 'openAboutSidebar');
menu.addToUi();
};
export const openDialog = () => {
const html = HtmlService.createHtmlOutputFromFile('dialog-demo')
.setWidth(600)
.setHeight(600);
SpreadsheetApp.getUi().showModalDialog(html, 'Sheet Editor');
};
export const openDialogBootstrap = () => {
const html = HtmlService.createHtmlOutputFromFile('dialog-demo-bootstrap')
.setWidth(600)
.setHeight(600);
SpreadsheetApp.getUi().showModalDialog(html, 'Sheet Editor (Bootstrap)');
};
export const openAboutSidebar = () => {
const html = HtmlService.createHtmlOutputFromFile('sidebar-about-page');
SpreadsheetApp.getUi().showSidebar(html);
};
It is worth noting that this will transpile to the back-end Google Apps Script code.
This means that we could customize this and make this more general, by editing out the onOpen method. I see it is developer's responsibility to do that :P
Great project! It's easy to follow, and I can see how I can make this my own, with MobX and MVVM!

Related

React.js: Best practices for API's grouping

I have been using Angular for 3 years. I have created some small and big projects. In every project, I have used proper folder structure for API calls(which many resources suggest). Below is a simple example
constants.ts
export const uploadData = `${url}/uploadData`;
service.ts
uploadData(formData: FormData): Observable<any> {
return this.http.post<any>(constants.uploadData, formData);
}
And in the component file, I import the service and call the API like this
this.service.uploadData(formData).pipe(take(1)).subscribe((res) => {
// do something
});
I specify all my related APIs and services in respective folders and call them wherever I need them. It's been 5 months since I started learning React and ReactNative. Now I am comfortable with both I started doing a major project. Now, the resources I followed to learn React didn't follow the proper structure(Create the API in whichever folder is required and call it with fetch/axios). Found some resources that follow structure but not effectively like how I did it in Angular. I can't find any resources with the requirement. It would be helpful if I can get one example of how we can have the folder structure like in Angular so that I will follow the good approach, instead of ending up writing bad code. (I am using Axios)

Google Analytics 4 with React

I've been trying to use react-ga package with google analytics 4 in my app. The measurement id doesn't work with it and there is no tracking code in google analytics 4 I can use. Please, I need help!
import ReactGA from 'react-ga';
const trackingId = 'G-XXXXXXXXXX'; // UA-XXXXXXXXX-X isn't available in GA4
ReactGA.initialize(trackingId, options);
ReactGA.pageview(page);
The code you entered in the example, G-XXXXXXXXXX , refers to the new Google Analytics 4 which, being a different system from the previous one and does not work (yet) with that plugin.
So you can follow the instructions mentioned in the answer of #Shyam or (and I suggest you because GA4 is too unripe at the moment) create a Universal Analytics type Property and use its ID (UA-XXXXX-X) with the plugin you indicated. You can find it by clicking on Show advanced options (when you create a new property):
.. react-ga does not work with Google Analytics 4.
Use ga-4-react instead: https://github.com/unrealmanu/ga-4-react
npm i ga-4-react
By adding
import GA4React from "ga-4-react";
const ga4react = new GA4React("G-XXXXXXXXXX");
ga4react.initialize().then().catch()
Thanks to the comments, I updated this post a little. I added a try/catch (for preventing AddBlocker Crashes) and a setTimeout.
The ".catch()"-Methode should be trailed to "ga4react.initialize()" to handle errors inside the initialize promise.
Analytics Systems should not be loaded at the beginning of a Page load. React apps are mostly single page applications, so this code is only loaded once (if needed you can replace "4000" milliseconds to "0").
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import GA4React from "ga-4-react";
ReactDOM.render(<App />, document.getElementById("root"));
try {
setTimeout(_ => {
const ga4react = new GA4React("G-XXXXXXXXXX");
ga4react.initialize().catch(err => console.error(err));
}, 4000);
} catch (err) {
console.error(err);
}
// G-XXXXXXXXXX is your MESS-ID from Google Analytics
How to find the MESS-ID in Google Analytics 4 (new) properties =>
https://analyticshelp.io/blog/google-analytics-property-tracking-id/
Google Analytics 4 is different from pre ga 4.
react-ga does not support this yet.
https://github.com/react-ga/react-ga/issues/460
You may need to do this manually
https://support.google.com/analytics/answer/9325020
https://developers.google.com/analytics/devguides/collection/ga4/tag-guide
Background: There are 2 types of Google Analytics properties: Universal Analytics (UA-xxxxxxxxx-x) which is deprecated with the end of life on 2023.07.01 and Google Analytics 4 property (G-xxxxxxxxxx) which is the replacement.
react-ga was popular for Universal Analytics but the maintainer doesn't plan to update it (related issues: 1, 2, 3) and it had maintenance issues (1). react-ga4 and ga-4-react popped up as replacements but since these are similar wrappers you're at the mercy of the maintainers to implement and support all functionality.
The simplest way to get started is to follow Google's guide: include gtag on the page and use it as window.gtag. This method works for both old and new tags and there's even TypeScript support via #types/gtag.js. The script can be loaded async as recommended.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=G-xxxxxxxxxx" >
</script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-xxxxxxxxxx')
</script>
<!-- ... -->
</head>
<body>
<!-- ... -->
</body>
</html>
Keep in mind that Google Analytics does automatic page tracking, but this will not work for every use case. For example, hash and search parameter changes are not tracked. This can lead to a lot of confusion. For example, when using HashRouter or anchor links the navigation will not be tracked. To have full control over page view tracking you can disable automatic tracking. See for a detailed explanation: The Ultimate Guide to Google Analytics (UA & GA4) on React (Or Anything Else
Manual page tracking: https://stackoverflow.com/a/63249329/2771889
You can see this working in cra-typescript-starter where I'm also setting the tag from an env var.
react-ga does not work with GA-4. I will also say that in react-ga's issues, the owner has said that unless someone creates a PR, he does not intend to add GA-4 support. The project is also not well maintained anymore.
You could theoretically create a universal property in the GA admin dashboard for backwards compatibility with earlier GA versions. At that point, you could use react-ga, but your best bet is to use ga-4-react instead: https://github.com/unrealmanu/ga-4-react
npm i ga-4-react
...
I will add on to #TG___ 's answer. The code he provided in his answer is a good start, but I will mention that it typically crashes the app if someone has an adblocker (adblocker blocks analytics request endpoints, no error handling, etc).
ERROR: Loading failed for the with source “https://www.google-analytics.com/analytics.js”
... Below is an expansion of his code to use the promise that ga4react.initialize() returns. This way, you can essentially detect whether the script didn't load and hence derive if the user has an adblocker that's preventing the GA script from loading. In my example code, I just ignore it and load the app... in other scenarios, I suppose you could invoke a modal to tell them to disable it (of course, that would come with extra code).
By adding
await ga4react.initialize()
to your index.js in src GA-4 will start and add a pageview. Works also with react-router without adding any code. By the Promise (await) you have to wrap it into an async-function (below as a closure).
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
const ga4react = new GA4React("G-XXXXXXXXXX");
(async _ => {
await ga4react.initialize()
.then(res => console.log("Analytics Success."))
.catch(err => console.log("Analytics Failure."))
.finally(() => {
ReactDOM.render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>,
document.getElementById('root')
);
});
})();
You may want to have a look at this package:
https://www.npmjs.com/package/react-ga4
It offers the same API as the normal react-ga. So just change your package name from react-ga to react-ga4 and it should work.
Tried it myself and it works great!
There are 2 versions of google analytics
Google Analytics 4 ( the updated one )
Universal Analytics ( the older one )
react-ga works fine with Universal Analytics as it takes the Tracking Id to initialize the connection between react and google analytics.
The problem is that whenever a user creates a new account, GA4 is being offered by default. But the GA4 doesn't have the Tracking Id that is required. GA4 has the Measurement ID but the react-ga doesn't want it. So we need the Tracking Id in order to set up the react-ga in our react app.
So the solution is, "Either downgrade from GA4 to Universal Analytics or Create a property that contains both of them as in GA4 and Universal Analytics together."
I would recommend watching the following videos:
GA4 vs Universal Analytics: https://www.youtube.com/watch?v=Y6WxUEk6clw
How to downgrade or keep both: https://www.youtube.com/watch?v=jRmb0jMNUKU
You probably know about the react-ga npm package but the sad news is, it does not work with the latest Google Analytics 4 version. It works with the old UA-0000-01 tags that was associated with Universal Analytics , but not with the G-XXXXXX tags that is Google Analytics 4. Universal Analytics will stop working in the near future.
Solution:
To tackle this issue you should start using react-ga4 npm package which supports Google Analytics 4.
https://www.npmjs.com/package/react-ga4
Note:
Universal analytics properties will stop collecting data starting july 1, 2023. it’s recommended that you create a google analytics 4 property instead.
Reference: Google Analytics Support
Doesn't specifically answer the question. But, you can create a Firebase web app to log events. Worked for me as a workaround to get data into Google Analytics as it does not seem like you can create a UA identifier to me anymore.
Adblock. Disable your Ad Block extension.
It took me quiet a few long and painful hours to realize that the problem was with an Ad Block chrome extension.
Once I disabled the extension, the events started to trigger.

How to Integrate/use Camunda BPMN Model API in ReactJs frontend to edit bpmn diagrams?

I am working on a React-Python/Flask app which takes input bpmn diagram image from user & through python scripts convert it into bpmn file which then can be downloaded through flask api on user's device. I am working on react UI. Now i have to edit the diagrams & apply some visualization to them. So how can i use Camunda BPMN Model API in my app.I am new to Camunda & i have gone through Camunda with React docs but i am still confused on where or how to start. Any help is appreciated. Thank you.
I am not professional in Camunda BPMN, but I am doing now research about it. Are you looking for bpmn.js library? Here is an example for BPMN Modeler:
https://github.com/bpmn-io/bpmn-js-examples/tree/master/modeler
And this is how you can integrate the library with React, basically, all you need is to provide ref from React.
const containerRef = useRef();
useEffect(() => {
const bpmnViewer = new BpmnJS({ container: containerRef.current });
}, []);
JSX Template:
<div ref={containerRef}></div>
Example here:
https://github.com/bpmn-io/react-bpmn/blob/master/src/index.jsx#L25

Has anyone been successful in implementing google optimize in a SPA React App?

I am fairly new to the Google Analytics Suite and am currently trying to integrate Google Optimize for A/B testing in a react app.
I have gotten to the point where the variant changes display on the desired web page, but only in Preview mode, and am stumped as to how to proceed to viewing the variant changes on a live site.
So far:
google optimize scripts are installed in app
<style>.async-hide { opacity: 0 !important} </style>
<script>(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;
h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;
})(window,document.documentElement,'async-hide','dataLayer',4000,
{'GTM-XXXXXXX':true});</script>
ga tracking is setup using ReactGA
GTM is setup and is firing tags to track
firing google optimize experiments on custom activation event and using dataLayer to push new events
const initializeReactGa = () => {
console.log('called to initialize react ga');
ReactGA.initialize(config.gaTag)
ReactGA.ga('require', config.optimizeTag);
ReactGA.pageview(window.location.pathname + window.location.search);
}
const googleOptimizeLoader = () => {
console.log('called google optimize loader');
if(window.dataLayer) {
window.dataLayer.push({'event': 'optimize.activate'})
}
}
The problem
unable to see variant changes in live site (without preview running)
Any help is appreciated.
TIA
Nayyir
[SOLVED]
Was able to determine the issues were not with the setup. The issue was that google optimize's cookie management was unable to set the required cookie for the expirement on localhost:3000, but rather a custom domain pointing to localhost, similar to XXXX.local:3000.
This might be what you are looking for
How to Add Google Optimize A/B Testing to Your React App in 10 Lines of Code

Microfrontends React/Component based splitting

Background:
I am confronted with the task to modernize a tool and convert it to microservices with a react frontend. My idea was to have a general top-level component containing e.g. the Nav and a component for each microservice that contains the functionality.
Approaches:
bundle the components locally so that it becomes effectively a monolithic frontend and the the forntend code is seperated just in the repo.
I think that would give up on the advantage of not having to redeploy your entire app for every change
lazy-load a minified bundle of each of the components from the microservice by defining them in a config file
With this approach I could just webpack each component on their own and async import it from the Main Page but maybe there would be a huge overhead
I read about component based splitting with react-loadable and bundling react-router or webpack, but I can't find information on how to load small bundles form different URL-Endpoints.
Question:
Is it possible to bundle react components on their own and import them from different Resource-URL's and how would one approach that ?(Or is React even suitable for that)
So after quite some search and experiments I found the Project Mosaic of Zalando, which is what I wanted. It offers a great way of React Component Splitting to support Micro Frontends. Note however that it is probably not suitable for smaller projects as it takes some time to get into the material and setting up all necessary applications.
Take a look at the below link:
https://www.martinfowler.com/articles/micro-frontends.html
I've recently made a project based on that article and I think that it might be what You are looking for.
I made the wrapper app which is rendering the microfrontends dynamically on the runtime based on the URL and routings. In the article above, there is a demo app showing the idea.
Every microfrontend is the separate project with it's own code repo.
https://demo.microfrontends.com/
Each app is hosted and js chunks are getting loaded on the runtime. This code might make it a little bit more clear what's going on there.
componentDidMount() {
const { name, host } = this.props;
const scriptId =micro-frontend-script-${name}`;
if (document.getElementById(scriptId)) {
this.renderMicroFrontend();
return;
}
fetch(`${host}/asset-manifest.json`)
.then(res => res.json())
.then(manifest => {
const script = document.createElement('script');
script.id = scriptId;
script.src = `${host}${manifest['main.js']}`;
script.onload = this.renderMicroFrontend;
document.head.appendChild(script);
});
}`
I hope You'll find that helpful :)
Good luck!

Resources