Adding Truepush initalization code to Gatsby - reactjs

I am using GatsbyJS. Recently I created a file in which I put this code.
import React from 'react'
import { Helmet } from 'react-helmet'
const CustomScript = () => {
return (
<Helmet>
<script type="application/javascript" src="https://sdki.truepush.com/sdk/v2.0.2/app.js" async></script>
<script>
var truepush = window.truepush || [];
truepush.push(function(){
truepush.Init({
id: "..."
},function(error){
if(error) console.error(error);
})
})
</script>
</Helmet>
)
}
export default CustomScript
But it gives me this error
ERROR #98123 WEBPACK
Generating development JavaScript bundle failed
/home/lilynicole/GitLab/portfolio/src/components/CustomScript.js
12:17 error 'truepush' is not defined no-undef
✖ 1 problem (1 error, 0 warnings)
File: src/components/CustomScript.js
failed Re-building development bundle - 5.401s
I have tried couple of things but nothing seems to work. Any help will be really appreciated.

If you want to insert inline JavaScript (the second <script> tag) with React Helmet, you'd need to quote the entire JavaScript as follows:
import React from 'react'
import { Helmet } from 'react-helmet'
const CustomScript = () => {
return (
<Helmet>
<script type="application/javascript" src="https://sdki.truepush.com/sdk/v2.0.2/app.js" async></script>
<script>{`
var truepush = window.truepush || [];
truepush.push(function(){
truepush.Init({
id: "..."
},function(error){
if(error) console.error(error);
})
})
`}
</script>
</Helmet>
)
}
export default CustomScript
The only change is that I wrapped the entire content of the <script> tag in {` ... `}.
In any case, I'd find it cleaner to write the following:
import React from 'react'
import { Helmet } from 'react-helmet'
import { useEffect } from 'react'
const CustomScript = () => {
useEffect(() => {
var truepush = window.truepush || []
truepush.push(function () {
truepush.Init(
{
id: '...',
},
function (error) {
if (error) console.error(error)
}
)
})
}, [])
return (
<Helmet>
<script
type="application/javascript"
src="https://sdki.truepush.com/sdk/v2.0.2/app.js"
async
></script>
</Helmet>
)
}
export default CustomScript
Here, instead of treating the JavaScript for the initialization as a string you're actually including it in your component code.
To make sure it runs only once you wrap it with useEffect(() => {...}, []).
(Note that I edited out your private Truepush ID and replaced it with ...; you'll need to put it back in)

I am David from Truepush Tech support. Can you please tell me if the project that you are doing is "a WebSite" or "a WebApp".
As if you are building a website then the code please try using the method that #ehrencrona has given out. That is Code by #ehrencrona
But if it is a webapp, we are not supporting them as of now and can't help you with setting it up for them.
We are working on a solution for this from our end as well. We will let you know when we have something that we can give out to help you.

Related

Cannot get react components with Cypress + cypress-react-selector

I'm trying to setup React testing with Cypress + cypress-react-selector.
Cypress seems to be working fine, but cypress-react-selector not so much.
I can run normal cypress methods.
But when I run cy.react(), it throws: "Could not find instance of React in given element"
I've been googling a lot, but nothing helps.
MyComponent.js
`
import React from 'react';
export const MyComponent = () => {
return <div data-testid="myTestId">my text</div>;
};
`
MyComponent.cy.js
`
import React from 'react';
import { MyComponent } from './MyComponent';
describe('<MyComponent />', () => {
beforeEach(() => {
cy.mount(<MyComponent />);
});
it('renders', () => {
//this works
cy.get('[data-testid=myTestId]').should('have.text', 'my text');
//this seems to be working, but I don't know
cy.waitForReact(5000, '#__cy_root');
//This fails with: "Could not find instance of React in given element"
cy.react('MyComponent');
});
});
`
cypress/support/component.js
`
import 'cypress-react-selector';
import './commands';
import { mount } from 'cypress/react18';
Cypress.Commands.add('mount', mount);`
cypress/support/component-index.html
`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Components App</title>
</head>
<body>
<div id="__cy_root" data-cy-root></div>
</body>
</html>
`
cypress.config.js
`
const { defineConfig } = require('cypress');
module.exports = defineConfig({
env: {
'cypress-react-selector': {
root: '#__cy_root',
},
},
component: {
devServer: {
framework: 'create-react-app',
bundler: 'webpack',
},
},
});
`
Ask for code, if I haven't provided something.
cypress-react-selector pre-dates cypress component testing, and I don't see any sign that it has been updated to handle component testing - all examples are e2e style testing.
Logically, Cypress built-in component testing and cypress-react-selector do the same thing, so maybe consider using one or the other.
IMO the cypress-react-selector has somewhat better API and more accessible examples, for instance I can't see how to do this in Cypress component testing
cypress-react-selector#sample-tests
Get current state
cy.getReact('MyTextInput', {
props: { field: { name: 'email' } },
}).getCurrentState(); // can return string | boolean | any[] | {}

Trying to import Email.js CDN with Next.js

Cant find a concrete answer on how to import this correctly.
Email js is installed via NPM
I try to import it with HEAD tag
<Head>
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/emailjs-com#2/dist/email.min.js">
</script>
<script type="text/javascript">
(function(){
emailjs.init("YOUR_USER_ID");
})();
</script></Head>
And i keep getting emailjs is undefined. No worries i will not be using next js again this was a mistake.
Here is an example from their npm package documentation. When using NextJS, you should generally use import or require
import emailjs from 'emailjs-com';
const templateParams = {
name: 'James',
notes: 'Check this out!'
};
emailjs.send('<YOUR SERVICE ID>','<YOUR TEMPLATE ID>', templateParams, '<YOUR USER ID>')
.then((response) => {
console.log('SUCCESS!', response.status, response.text);
}, (err) => {
console.log('FAILED...', err);
});

gatsby ssr - add script to header before other plugins

I am using Gatsby and need to head a script in the header BEFORE other plugin.
If I add it via gatsby-ssr.js
exports.onRenderBody = ({ setHeadComponents }) => setHeadComponents([#MY-SCRIPT#]);
it's being added last.
How can I add it BEFORE other plugins?
In addition to onRenderBody, use onPreRenderHTML to reorder your scripts.
exports.onRenderBody = ({ setHeadComponents }) =>
setHeadComponents([
<script key='myscript' src='...' />
]);
exports.onPreRenderHTML = ({ getHeadComponents, replaceHeadComponents }) => {
const headComponents = getHeadComponents()
// reorder your array with the sort method, by putting your item at top
const orderedComponents = headComponents.sort((item) => (item.key === 'your-key' ? -1 : 1)); const orderedComponents = reorder(headComponents)
replaceHeadComponents(orderedComponents)
}
For more info, see the Gatsby docs on SSR API.
2022 update
Since the release of the Script Gatsby component (powered by Partytown) it's much easier adding third-party scripts. Just:
import React from "react"
import { Script } from "gatsby"
function YourPage() {
return <Script src="https://my-example-script" />
}
export default YourPage
Why you use gatsby-ssr.js file if you can use <Helmet> tag, maybe it fits you. You just need to use it like this in any component:
import React from "react"
import Helmet from "react-helmet"
import Layout from "../components/layout"
import SEO from "../components/seo"
const IndexPage= () => (
<Layout>
<SEO title="Index page" />
<Helmet>
<script src="https://whatever.com" type="text/javascript"/>
<script src="https://whatever2.com" type="text/javascript"/>
</Helmet>
</Layout>
)
export default IndexPage
The snippet above will load your scripts inside <head> tag on the same order you've placed it.
If you need some kind of ordering and async approach, you can use gatsby-ssr, across onRenderBody and onPreRenderHTML.

How to import the electron ipcRenderer in a react / webpack 2 setup

using a electron, react (es6 / jsx), sass, pouchdb and webpack 2 setup. I fail to import or require ipcRenderer to make communication between main and renderer process possible. My setup can be found here: https://github.com/wende60/timeTracker
Any hints how to get the ipcRenderer into a react component?
Cheers, jo
const electron = window.require('electron');
const ipcRenderer = electron.ipcRenderer;
I think it is the better solution because it avoid ejecting the React app.
I had the same problem. This solved that issue for me:
Add in the webpack.config.js:
const webpack = require("webpack");
module.exports = {
plugins: [
new webpack.ExternalsPlugin('commonjs', [
'electron'
])
]
...
}
Then you can use it with
import {ipcRenderer} from "electron";
I suggest you read my response here.
You'll want to set up your app like this:
main.js
const {
app,
BrowserWindow,
ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
async function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false, // is default value after Electron v5
contextIsolation: true, // protect against prototype pollution
enableRemoteModule: false, // turn off remote
preload: path.join(__dirname, "preload.js") // use a preload script
}
});
// Load app
win.loadFile(path.join(__dirname, "dist/index.html"));
// rest of code..
}
app.on("ready", createWindow);
ipcMain.on("toMain", (event, args) => {
fs.readFile("path/to/file", (error, data) => {
// Do something with file contents
// Send result back to renderer process
win.webContents.send("fromMain", responseObj);
});
});
preload.js
** Update: DO NOT use send key value as property name. It will overwrite on win.webContents.send method and comes to do nothing when you try to call win.webContents.send('your_channel_name') inside your main process main.js. Better to use better names like request and response.
const {
contextBridge,
ipcRenderer
} = require("electron");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
"api", {
//send: (channel, data) => {
request: (channel, data) => {
// whitelist channels
let validChannels = ["toMain"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
//receive: (channel, func) => {
response: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
}
);
index.html
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8"/>
<title>Title</title>
</head>
<body>
<script>
window.api.response("fromMain", (data) => {
console.log(`Received ${data} from main process`);
});
window.api.request("toMain", "some data");
</script>
</body>
</html>
As of May 2020, I think Erik Martín Jordán has said it best:
Create a preload.js file:
window.ipcRenderer = require('electron').ipcRenderer;
On main.js:
// Create the browser window.
mainWindow = new BrowserWindow({
alwaysOnTop: true,
frame: false,
fullscreenable: false,
transparent: true,
titleBarStyle: 'customButtonsOnHover',
show: false,
width: 300,
height: 350,
webPreferences: {
// UPDATE: for electron > V12 consider setting contextIsolation and see: https://github.com/electron/electron/issues/9920#issuecomment-797491175
nodeIntegration: true,
preload: __dirname + '/preload.js'
}
});
// Blur window when close o loses focus
mainWindow.webContents.on('did-finish-load', () => mainWindow.webContents.send('ping', '🤘') );
mainWindow variable on this file will preload the preload.js file. Now the React component can call the window.ipcRenderer method.
In the React app.js:
import React, { useEffect, useState } from 'react';
import './App.css';
function App() {
useEffect( () => {
window.ipcRenderer.on('ping', (event, message) => {
console.log(message)
});
}, []);
return (
<div className = 'App'></div>
);
}
export default App;
I've been looking into this topic just recently and I found a solution for doing some some ipc between electrons main.js and the React part of the application. Since both, import {ipcRenderer} from 'electron'; after adding the plugin to the webpack modules and const ipc = require('electron').ipcRenderer; produced some errors I ended up requiring electron in the resulting page and adding it to the window.
In the index.html I did something like this
<body>
...
<script>
window.ipc = require('electron').ipcRenderer;
</script>
<div id="root">
</div>
...
</body>
In reacts index.js I did something like this:
import React from 'react';
import ReactDOM from 'react-dom';
// ...
if(window.ipc)
ipc.on("some-event", (event, someParameter) => {
ReactDOM.render(
<SomeElement value={someParameter} />,
document.getElementById("root")
);
})
// ...
In order to make this work i started the react page from the electron app, in the main.js I did something like that.
const {app, BrowserWindow} = require("electron"};
const exec = require("child_process").exec;
let main;
app.on("ready", () => {
exec("node start", (err, stdout, stderr) => {
if(err) console.log(err);
console.log("" + stdout);
console.log("" + stderr);
});
main = new BrowserWindow();
main.loadURL("http://localhost:3006");
main.on("close", () => {main = null});
});
because electron is running on the same port I added a .env file to my project that contained
PORT=3006
I used the create-react-app my-prj (npm install -g create-react-app) command for my base project it looked something like this
my-prj
|-package.json
|-main.js
|-.env
|-node_modules/
|-public/
|-index.html
|-src/
|-index.js
Hope this post was of any help.
Found a good solution for this issue using webpack-target-electron-renderer So I can develop the web-part in a localhost environment with hot-reloading. electron is required only in the electron environment.
You can see a working example here:
https://github.com/wende60/webpack-web-and-electron-example, forked from acao's webpack-web-and-electron-example and updated for webpack 2 and hot-replacement.
If you are interested in a webpack, electron, react, sass and pouchdb setup have a look here:
https://github.com/wende60/timeTracker
Work is still in progress...
import { ipcRenderer } from "electron"
import { Component } from "react"
...
class MyComponent extends Component {
render(){
ipcRenderer.send("event", "some data")
return (<div>Some JSX</div>)
}
}

contentful api markdown conversion to HTML

Is there any simple way to convert markdown text from contentful api to render into html code to be display on html page. I have tried using pagedown and some similar techniques , but none seem to work for me .
I'm a customer success manager at Contentful -
You can check out a list of recommended parsers by language on the our FAQ.
Also, feel free to send us messages on Intercom via our UI by clicking the 'Talk to Us' link :)
I know I'm late but here's the solution using handlebars:
var marked = require('marked');
marked.setOptions({
renderer: new marked.Renderer(),
sanitize: true,
smartLists: true,
smartypants: true
});
//Home
router.get('/', (req, res) => {
client.getEntry('<ENTRY_ID>')
.then( (entry)=> {
entry.fields.body = marked(entry.fields.body);
res.render('static/index',
{
entry: entry,
user: req.user
});
}).catch( (err) => {
console.log(err);
})
});
Then in our index.hbs template we can call the markdown variable in this case (entry.fields.body) by using {{{}}} to prevent escaping.
{{{entry.fields.body}}}
Here's how I did it with React:
class NewsDetail extends React.Component {
render() {
const body = marked(this.props.body || "");
return (
<div className="news-detail">
<h2>{this.props.title}</h2>
<div dangerouslySetInnerHTML={ { __html: body } }></div>
</div>
);
}
}
The markdown content is stored in the body attribute of the NewsDetail tag (via a short function that maps contentful data structure to my app structure).
The HTML page has this script tag to pull in the marked function:
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js"></script>
I have used ReactMarkdown module: in case you also have a react app: https://github.com/rexxars/react-markdown
Example: npm install --save react-markdown
const React = require('react')
const ReactDOM = require('react-dom')
const ReactMarkdown = require('react-markdown')
const input = '# This is a header\n\nAnd this is a paragraph'
ReactDOM.render(
<ReactMarkdown source={input} />,
document.getElementById('container')
)
I am passing markdown through props and using this module inside of my child component.
I also did the same as margarita in a react app but in the child component and I pulled my markdown from contentful.
I installed react-markdown package
with
npm install react-markdown
import React from "react";
import ReactMarkdown from "react-markdown";
const AboutIntro = (props) => {
return (
<div>
<h2 className="about__intro-title">
{props.aboutTitle}
</h2>
<ReactMarkdown>
{props.aboutCopy}
</ReactMarkdown>
</div>
)
}
export default AboutIntro;
hope this helps

Resources