Saving configuration in PivotTable js react - react-hooks

I am trying to create pivot table using pivottable.js, my Pivot Options are
import PivotTableUI from "react-pivottable/PivotTableUI"
import TableRenderers from "react-pivottable/TableRenderers"
import "react-pivottable/pivottable.css"
import Plot from 'react-plotly.js'
const PlotlyRenderers = createPlotlyRenderers(Plot)
const [pivotTableUIConfig, setPivotTableUIConfig] = useState({})
const pivotPresets = {
rendererName,
aggregatorName,
plotlyOptions: {width: 900, height: 500},
plotlyConfig: {},
rendererOptions: {
table: {
clickCallback(e, value, filters, pivotData) {
const names = []
pivotData.forEachMatchingRecord(filters,
function(record) { names.push(record.TaskID) })
alert(names.join("\n"))
}
}
}
}
My UI for react is
<PivotTableUI data={data} onChange={(s) => {
setPivotTableUIConfig(s)
setdata(s)
}} unusedOrientationCutoff={Infinity} {...pivotPresets}
renderers={Object.assign({}, TableRenderers, PlotlyRenderers)} {...pivotTableUIConfig} />
I want to save my filter configuration in cookie but there is no documentation of how to do it in react js.
It's availiable in Jquery https://pivottable.js.org/examples/save_restore.html
Please help thanks.

Related

Why calling fit() is rezing the window wrongly?

I'm getting this resize error when I get out the tab then get back:
I did notice that this happens when I call FitAddon.Fit() inside my ResizeObserver. I was using onSize to call .fit() but I did notice that when I used <Resizable>, the onSize event didn't fire so I went to use ResizeObserver and called .fit() from ResizeObserver's callback so the resize error begun.
my code look like this:
import { useEffect, useRef } from "react";
import { Terminal as TerminalType } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import { WebLinksAddon } from 'xterm-addon-web-links';
import 'xterm/css/xterm.css';
export const Terminal = () => {
const id = 'xterm-container';
useEffect(() => {
const container = document.getElementById(id) as HTMLElement;
const terminal = new TerminalType({
cursorBlink: true,
cursorStyle: window.api.isWindows ? "bar" : "underline",
cols: DefaultTerminalSize.cols,
rows: DefaultTerminalSize.rows
});
const fitAddon = new FitAddon();
terminal.loadAddon(fitAddon);
terminal.loadAddon(new WebLinksAddon());
const resizeObserver = new ResizeObserver(entries => {
fitAddon.fit();
});
resizeObserver.observe(container);
terminal.open(container);
terminal.onData(key => {
window.api.send('terminal.data', key);
});
terminal.onResize(size => {
window.api.send('terminal.resize', {
cols: size.cols,
rows: size.rows
});
});
fitAddon.fit();
return () => {
resizeObserver.unobserve(container);
}
}, []);
return (
<div
id={id}
style={{height: '100%',
width: '100%',
}}
>
</div>
)
}

Can't use React useEffect and also build failed using Gatsby

I am building a headless eCommerce website using Nacelle, Gatsby, and Shopify plus.
My problem is that I integrated Okendo API to fetch product reviews and can't build the project.
Actually, as you know, headless eCommerce is a new technology to us, but it is mostly close to Gatsby and SSR.
I tried to go 2 ways, one is to include the script to head using gatsby-react-helmet, and another one is to call window api inside useEffect or useLayoutEffect.
1. Including the script to head tag using gatsby-plugin-react-helmet.
ProductReview.js
import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet';
import transformProductId from '../../utils/transformProductId';
import { PRODUCT_REVIEW_METAFIELD_KEY, OKENDO_SUBSCRIBER_ID } from '../../constants';
const ProductReview = ({
product
}) => {
const OkendoSettings = {
filtersEnabled: true,
omitMicrodata: true,
subscriberId: OKENDO_SUBSCRIBER_ID,
widgetTemplateId: "default"
}
return (
<>
<Helmet>
<script type="application/javascript" src="../plugins/okendo/index.js" />
<script type="application/json" id="oke-reviews-settings">
{JSON.stringify(OkendoSettings)}
</script>
<script type="application/javascript" src="../plugins/okendo/initAPI.js" />
</Helmet>
<div
data-oke-reviews-widget
data-oke-reviews-product-id={transformProductId(product.id)}
/>
</>
);
};
export default React.memo(ProductReview);
/plugin/okendo/index.js
(function () {
function asyncLoad() {
var urls = ['https:\/\/d3hw6dc1ow8pp2.cloudfront.net\/reviewsWidget.min.js?shop=example.myshopify.com'];
for (var i = 0; i < urls.length; i++) {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = urls[i];
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
}
}
if (window.attachEvent) {
window.attachEvent('onload', asyncLoad);
} else {
window.addEventListener('load', asyncLoad, false);
}
})();
/plugin/okendo/initAPI.js
window.okeReviewsWidgetOnInit = function (okeInitApi) {};
If I include the Okendo scripts to head tag, it works all fine.
But when I try to build on vercel, it says "error Building static HTML failed for path /products/example-product-slug".
2. Calling window.init api inside useEffect.
ProductReview.js
import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet';
import transformProductId from '../../utils/transformProductId';
import { PRODUCT_REVIEW_METAFIELD_KEY, OKENDO_SUBSCRIBER_ID } from '../../constants';
const ProductReview = ({
product
}) => {
const OkendoSettings = {
filtersEnabled: true,
omitMicrodata: true,
subscriberId: OKENDO_SUBSCRIBER_ID,
widgetTemplateId: "default"
}
useEffect(() => {
if (typeof window !== `undefined` && window.okendoInitApi) {
const reviewsWidget = window.document.querySelector('#oke-reviews-widget');
window.okendoInitApi.initReviewsWidget(reviewsWidget);
}
}, [product.id]);
return (
<>
<Helmet>
<script type="application/javascript" src="../plugins/okendo/index.js" />
<script type="application/json" id="oke-reviews-settings">
{JSON.stringify(OkendoSettings)}
</script>
{/* <script type="application/javascript" src="../plugins/okendo/initAPI.js" /> */}
</Helmet>
<div
id="oke-reviews-widget"
data-oke-reviews-widget
data-oke-reviews-product-id={transformProductId(product.id)}
/>
</>
);
};
export default React.memo(ProductReview);
While I am using useEffect to initialize Okendo api, it works only when the page refresh, not work if I open a page.
And if I try to build it, it says "error "window" is not available during server side rendering.".
I know useEffect doesn’t run unless it’s in the browser, but still I don't get what the solution is.
Hope to hear a good news.
Thank you.
UPDATE: The product id is generated from Shopify product graphql data named handle.
gatsby-node.js
exports.createPages = async ({ graphql, actions: { createPage } }) => {
// Fetch all products
const products = await graphql(`
{
allNacelleProduct (filter: { availableForSale: {eq: true} }) {
edges {
node {
handle
}
}
}
}
`);
products.data.allNacelleProduct.edges.forEach((product) =>
createPage({
// Build a Product Detail Page (PDP) for each product
path: `/products/${product.node.handle}`,
component: path.resolve('./src/templates/product-detail.js'),
context: {
handle: product.node.handle
}
})
);
...

React.js using context api to implement the dark/light theme, is it possible to get data in App component when I am using contextprovider?

I am using the context api to give my application the toggling ability between the dark/light mode, I managed to toggle the mode in all the children components of App component but when I tried to implement it to the component itself I failed I guess this related the fact the I am using the contextProvider within this component, code below for :
import React from 'react'
import styles from './App.module.css'
import { Card, CountryPicker, Chart } from './components/index'
import { fetchData } from './api/index'
import ThemeContextProvider, { ThemeContext } from './contexts/ThemeContext'
import ToggleTheme from './components/ToggleTheme/ToggleTheme'
export default class App extends React.Component {
static contextType = ThemeContext
state = {
data: {},
country: '',
}
handleCountryChange = async (country) => {
// console.log(country)
const Data = await fetchData(country)
// console.log(Data)
this.setState({ data: Data, country })
// console.log(this.state.data, this.state.country)
}
async componentDidMount() {
const data = await fetchData();
this.setState({ data })
}
render() {
const { data, country } = this.state;
// problem here
const { isLightTheme, dark, light } = this.context;
return (
<ThemeContextProvider>
<div className={styles.container} >
<ToggleTheme />
<Card data={data} />
<CountryPicker handleCountryChange={this.handleCountryChange} />
<Chart data={data} country={country} />
</div>
</ThemeContextProvider>
)
}
}
I figured it out,the solution was very simple, just importing the App component into other componentMain and wrapping it with <ContextProvider></ContextProvider> and import in the index.js

How to add custom completer in react ace editor from outside of language_tools

How to add custom completer in react based ace editor from index.js using functions like addCompleter or setCompleter
import { render } from "react-dom";
import AceEditor from "../src/ace";
import "brace/mode/jsx";
import 'brace/mode/HCPCustomCalcs'
import 'brace/theme/monokai'
import "brace/snippets/HCPCustomCalcs";
import "brace/ext/language_tools";
const defaultValue = `function onLoad(editor) {
console.log("i've loaded");
}`;
class App extends Component {
constructor(props, context) {
super(props, context);
this.onChange = this.onChange.bind(this);
}
onChange(newValue) {
console.log('changes:', newValue);
}
render() {
return (
<div>
<AceEditor
mode="HCPCustomCalcs"
theme="monokai"
width={ '100%' }
height={ '100vh' }
onChange={this.onChange}
name="UNIQUE_ID_OF_DIV"
editorProps={{
$blockScrolling: true
}}
enableBasicAutocompletion={true}
enableLiveAutocompletion={true}
enableSnippets={true}
/>
</div>
);
}
}
render(<App />, document.getElementById("example"));
i want to add my custom completer from here.my completer is something like this
var myCompleter ={
getCompletions: function(editor, session, pos, prefix, callback) {
var completions = [];
["word1", "word2"].forEach(function(w) {
completions.push({
value: w,
meta: "my completion",
});
});
callback(null, completions);
}
})}
In normal Ace-editor it was straight forward.By simply calling
var langTools = ace.require("ace/ext/language_tools")
langTools.addCompleter(myCompleter1);```
You can do something very similar to the normal Ace-editor.
const langTools = ace.acequire('ace/ext/language_tools');
langTools.addCompleter(myCompleter);
Using ace.acequire allows you to access hidden ACE features. Some documentation here: https://github.com/thlorenz/brace/wiki/Advanced:-Accessing-somewhat-hidden-ACE-features

Rendering JSON with GraphQL in GatsbyJS

I've been stuck for hours and I have no idea what's wrong. I'm new to GraphQL and Gatsby.
I have a JSON file that I'm trying to render. Each object has its own url path. I'm able to query the data with GraphQL, set up CreatePages in my gatsby-node.js file and then query again in my template file, but for some reason I'm only getting null in the template file.
I'm pretty sure I'm using gatsby-plugin-transformer-json correctly too. I'm at a loss right now. Any help is much appreciated.
gatsby-node.js
/**
* Implement Gatsby's Node APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/node-apis/
*/
// You can delete this file if you're not using it
const path = require('path');
exports.createPages = ({actions, graphql}) => {
const { createPage } = actions;
const postTemplate = path.resolve(`src/templates/post.js`);
const projectTemplate = path.resolve(`src/templates/project.js`);
return graphql(`{
allProjectsJson {
edges {
node {
id
name
description
path
}
}
}
allMarkdownRemark {
edges {
node {
html
id
frontmatter {
path
title
date
}
}
}
}
}`)
.then(res => {
if(res.errors) {
return Promise.reject(res.errors);
}
// blogs
res.data.allMarkdownRemark.edges.forEach(({node}) => {
createPage({
path: node.frontmatter.path,
component: postTemplate
})
})
// projects
res.data.allProjectsJson.edges.forEach(({node}) => {
createPage({
path: node.path,
component: projectTemplate
})
})
})
}
templates/project.js
import React from 'react';
import { graphql } from 'gatsby'
import Layout from "../components/layout"
// import Helmet from 'react-helmet';
export default function Project({data}) {
const { projectsJson: project } = data;
// this results in null???
console.log(data)
return (
<Layout>
<div>
<h1>Projects!!!</h1>
<p>One single</p>
</div>
</Layout>
);
}
export const projectQuery = graphql`
query ProjectByPath($path: String!) {
projectsJson(path: { eq: $path }) {
name
path
description
}
}
`
I decided to simply list the projects rather than be able to link to each one. With that, I simply had to query in the file rather than pass each object through gatsby-node.js and grab the right one in the template file.
import React from "react"
// import { Link } from "gatsby"
import { graphql } from 'gatsby'
import Layout from "../components/layout"
import SEO from "../components/seo"
const Projects = ({data}) => (
<Layout>
<SEO title="Projects" />
<h1>Personal Projects</h1>
{data.allProjectsJson.edges.map((project, index) => {
console.log(project)
return (
<a
key={index}
style={projectContainerStyles}
href={project.node.url}
target="_blank"
rel="noopener noreferrer"
>
<h2>{project.node.name}</h2>
{project.node.description}
</a>
)
})}
<p>You can see my external portfolio
<a
href="https://anthonyzamarro.github.io/az_portfolio/"
target="_blank"
rel="noopener noreferrer">
here!
</a>
</p>
</Layout>
)
const projectContainerStyles = {
marginBottom: '2rem',
background: 'turquoise',
padding: '8px',
borderRadius: '5px',
boxShadow: '1px 3px 2px rgb(155,155,155)',
'display': 'block',
'color': '#000',
textDecoration: 'none'
}
export const projectQuery = graphql`
query projectQuery {
allProjectsJson {
edges {
node {
id
name
description
url
}
}
}
}`
export default Projects

Resources