I have a problem with translations in my gatsby site.
I am using the i18n plugin to make translations but if i put in my index.jsx two FormattedMessage tag, it breaks my index.jsx.
I can find my issue in google but i can't figure out how to resolve it.
My index.jsx
import React from 'react'
import { FormattedMessage } from 'react-intl'
import Layout from '../components/Layout'
const IndexPage = ({ pathContext: { locale } }) => (
<Layout locale={locale}>
<FormattedMessage id="hello" />
<FormattedMessage id="hello" />
</Layout>
)
export default IndexPage
and my layout:
import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import { StaticQuery, graphql } from 'gatsby'
import Header from './header'
import './layout.css'
import { IntlProvider, addLocaleData } from 'react-intl'
// Locale data
import enData from 'react-intl/locale-data/en'
import ptData from 'react-intl/locale-data/pt'
import esData from 'react-intl/locale-data/es'
// Messages
import en from '../i18n/en.json'
import pt from '../i18n/pt.json'
import es from '../i18n/es.json'
const messages = { en, pt, es }
addLocaleData([...enData, ...ptData, ...esData])
const Layout = ({ locale, children }) => (
<StaticQuery
query={graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`}
render={data => (
<>
<Helmet
title={data.site.siteMetadata.title}
meta={[
{ name: 'description', content: 'Sample' },
{ name: 'keywords', content: 'sample, something' },
]}
>
<html lang="en" />
</Helmet>
<Header lang="/^\/eng/" />
<div
style={{
margin: '0 auto',
maxWidth: 960,
padding: '0px 1.0875rem 1.45rem',
paddingTop: 0,
}}
>
<IntlProvider locale={locale} messages={messages[locale]}>
{children}
</IntlProvider>
</div>
</>
)}
/>
)
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
I hope you can't help me to use more than one FormattedMessage tag for translations, thank you.
Maybe is not a valid solution for you but. Did you try gatsby-plugin-i18next? My first project with gatsbyjs was a nightmare deal with languages until I found it. In my opinion, it works really well. You must install it with npm/yarn and configure a little bit. You can remove the wrapper IntlProvider and you can take translations wherever you want (pages/templates or components).
Here and example extracted from your code (English & Spanish languages). The plugin take care of the URL, putting /es & /en in every pages/templates:
src/pages/index.jsx
import React from 'react';
import { I18n } from 'react-i18next';
import { withI18next } from 'gatsby-plugin-i18next';
import Layout from '../components/index'
const IndexPage = props => (<I18n>{t => (
<Layout{...props}>
<p>{t('hello')}</p>
<p>{t('hello')}</p>
</Layout>
)}</I18n>);
export const query = graphql`
query($lng: String!){
locales: allLocale(filter: { lng: { eq:$lng }, ns: { eq: "messages" } }) {
...TranslationFragment
}
}
`;
export default withI18next()(IndexPage);
src/components/index.jsx
Note that you must change Helmet as well. I translate the metadata in order to show how can translate in components (not pages neither templates).
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { Head } from 'gatsby-plugin-i18next';
import { StaticQuery, graphql } from 'gatsby'
import Header from './header'
import './layout.css'
const Layout = ({children, t }) => (
<StaticQuery
query={graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`}
render={data => (
<>
<Head hreflang>
<title>{data.site.siteMetadata.title}</title>
<meta name="description" content="{t('metaDescription')}" />
<meta name="keywords" content="{t('metaKeywords')}" />
</Head>
<Header lang="/^\/eng/" />
<div
style={{
margin: '0 auto',
maxWidth: 960,
padding: '0px 1.0875rem 1.45rem',
paddingTop: 0,
}}
>
{children}
</div>
</>
)}
/>
)
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default translate()(Layout)
gatsby-config.js
You can debug the plugin only when you are developing ;)
const defaultLanguage = "en";
const languages: ["en", "es"];
const siteUrl: "https://domain-where-the-gatsby-are-published.com/",
module.exports = {
...,
plugins: [
...,
{
resolve: `gatsby-plugin-i18next`,
options: {
availableLngs: languages,
fallbackLng: defaultLanguage,
debug: process.env.NODE_ENV === 'development',
siteUrl
},
}
],
}
locale/en/messages.json
{
"hello": "Hi!",
"metaDescription": "Sample page with i18n translations",
"metaKeywords": "i18n, gatsbyjs, english"
}
locale/es/messages.json
{
"hello": "Hola!",
"metaDescription": "Página de ejemplo con traducciones i18n",
"metaKeywords": "i18n, gatsbyjs, spanish"
}
As an extra comment:
Remember to change all the links imported from gatsby to
gatsby-plugin-i18next
You must inject the graphql query in every pages/templates
You can see the code of the starter to see how can you create a switcher between the languages
Related
I'm new to gatsby and i'm trying to use gatsby background image plugin but it does not work, the image wont show on screen.
Here's my code :
import * as React from "react"
import { graphql, useStaticQuery } from 'gatsby'
import { createGlobalStyle } from "styled-components"
import BackgroundImage from 'gatsby-background-image'
const GlobalStyle = createGlobalStyle`
body{
background-color: #270A63;
margin : 0px;
display:flex;
}`
const Layout = (props, { children }) => {
const data = useStaticQuery(
graphql`
query {
bgImage : file(relativePath: {eq: "background.png"}) {
childImageSharp {
gatsbyImageData(quality: 90)
}
}
}
`
)
const imageData = data.bgImage.childImageSharp.gatsbyImageData;
return (
<React.Fragment>
<GlobalStyle />
<BackgroundImage
Tag="section"
image={imageData}
>
</BackgroundImage>
</React.Fragment>
)
}
export default Layout
Layout is a custom component that I'm using in index page.
I used console.log to check imageData and it is an object that looks like this :
{bgImage:
childImageSharp:
gatsbyImageData:
backgroundColor: "#680818"
height: 1117
images:
fallback: {src: '/static/32d467ee3060062ab794e34f2002c807/f89cf/background.png', srcSet: '/static/32d467ee3060062ab794e34f2002c807/5829e/bac…60062ab794e34f2002c807/f89cf/background.png 1010w', sizes: '(min-width: 1010px) 1010px, 100vw'}
sources: [{…}]
[[Prototype]]: Object
layout: "constrained"
width: 1010}
I don't understand why it does not work.
Thank you for your help !
As per your GraphQL, you are using a Gatsby version greater or equal than 3. I think your snippet should look like something like:
import React from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import { getImage, GatsbyImage } from "gatsby-plugin-image"
import { convertToBgImage } from "gbimage-bridge"
import BackgroundImage from 'gatsby-background-image'
const GbiBridged = () => {
const { bgImage }= useStaticQuery(
graphql`
query {
bgImage : file(relativePath: {eq: "background.png"}) {
childImageSharp {
gatsbyImageData(quality: 90)
}
}
}
`
)
const image = getImage(bgImage)
const backgroundImage= convertToBgImage(image)
return (
<React.Fragment>
<GlobalStyle />
<BackgroundImage
Tag="section"
{...backgroundImage}
preserveStackingContext
>
<div style={{minHeight: 1000, minWidth: 1000}}>
<GatsbyImage image={image} alt={"testimage"}/>
</div>
</BackgroundImage>
</React.Fragment>
)
}
export default GbiBridged
Modified from: https://www.gatsbyjs.com/plugins/gatsby-background-image/#gatsby-34--gatsby-plugin-image applying your code
Gatsby changed the image plugin from gatsby-image (Gatsby 1 and 2) to gatsby-plugin-image (version 3 onwards). Among other things, it has changed the internal GraphQL nodes of the image data, hence the workaround of using gatsby-background-image has also changed accordingly. In your case, you are using the deprecated version of gatsby-image so your code is not able to display the image.
You can follow the full discussion in this GitHub thread: https://github.com/timhagn/gatsby-background-image/issues/141
I'd recommend not using any external plugins for this but using CSS to achieve this. This way you don't have to learn any new third-party plugins and can use the knowledge you have about CSS. Here's an example from the docs: https://www.gatsbyjs.com/docs/how-to/images-and-media/using-gatsby-plugin-image/#background-images
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"
export function Hero() {
return (
<div style={{ display: "grid" }}>
{/* You can use a GatsbyImage component if the image is dynamic */}
<StaticImage
style={{
gridArea: "1/1",
// You can set a maximum height for the image, if you wish.
// maxHeight: 600,
}}
layout="fullWidth"
// You can optionally force an aspect ratio for the generated image
aspectRatio={3 / 1}
// This is a presentational image, so the alt should be an empty string
alt=""
// Assisi, Perúgia, Itália by Bernardo Ferrari, via Unsplash
src={
"https://images.unsplash.com/photo-1604975999044-188783d54fb3?w=2589"
}
formats={["auto", "webp", "avif"]}
/>
<div
style={{
// By using the same grid area for both, they are stacked on top of each other
gridArea: "1/1",
position: "relative",
// This centers the other elements inside the hero component
placeItems: "center",
display: "grid",
}}
>
{/* Any content here will be centered in the component */}
<h1>Hero text</h1>
</div>
</div>
)
}
I want to display Google Adsense on my gatsby.js site. However, it is not showing up.
LeftSideSection is called in Layout.js.
I am running it in a local environment.
And I don't have a domain for my site.
I don't register my site's domain in GoogleAdsense and
I have created an Ad unit.
export
[
googleAdsense.js
import React from "react"
import * as styles from "./LeftSideSection.module.css";
import {Adsense} from './googleAdsense'
import React, { useEffect } from 'react'
export const Adsense = ({ path }) => {
useEffect(() => {
;(window.adsbygoogle = window.adsbygoogle || []).push({})
}, [path])
return (
<ins
className="adsbygoogle"
style={{ "display": "block" , textAlign: "center",width:`100%` ,height:`100%`}}
data-ad-client="ca-pub-xxxxxxxxx"
data-ad-slot="xxxxxxx"
data-ad-format="auto"
data-full-width-responsive="true"
data-adtest="on"
/>
)
}
LeftSideSection.js
const LeftSideSection = (props) => {
const { title, children } = props;
const path = props.location?.pathname || '';
return (
<section className={styles.container}>
<p>ads</p>
<Adsense path={path} />
</section>
);
};
export default LeftSideSection;
Layout.js
import React from "react";
import Header from "./Header";
import * as styles from "./Layout.module.css";
import 'bootstrap/dist/css/bootstrap.min.css';
import herderImage from '../images/header.png'
import {Navbar} from 'react-bootstrap'
import RightSideSection from "./RightSideSection";
import LeftSideSection from "./LeftSideSection";
import { Link } from "gatsby";
import { useBreakpoint } from 'gatsby-plugin-breakpoints';
import HeaderRss from "./HeaderRss";
const Layout = ({ children }) => {
const breakPoints = useBreakpoint();
return (
breakPoints.pc ?
<>
<Navbar.Brand as={Link} href='/' >
<img src={herderImage} style={{width:`100%`,height:`200px`,}}/>
</Navbar.Brand>
<Header />
<div className={styles.container}>
<div className={styles.LeftSideSection}>
<LeftSideSection />
</div>
<div className={styles.RightSideSection}>
<RightSideSection />
</div>
<div className={styles.mainPane}>
<div className={styles.headerRssContainer}>
<HeaderRss/>
</div>
{children}
</div>
</div>
<footer className={styles.footer}>
© {new Date().getFullYear()},
{`title`}
</footer>
</>:
);
};
export default Layout;
enter image description here
You are not loading the <script> that the console is suggesting. Try using the Helmet component to do something like:
import React from "react"
import * as styles from "./LeftSideSection.module.css";
import {Adsense} from './googleAdsense'
import React, { useEffect } from 'react'
export const Adsense = ({ path }) => {
useEffect(() => {
;(window.adsbygoogle = window.adsbygoogle || []).push({})
}, [path])
return <>
<Helmet>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
</Helmet>
<ins
className="adsbygoogle"
style={{ "display": "block" , textAlign: "center",width:`100%` ,height:`100%`}}
data-ad-client="ca-pub-xxxxxxxxx"
data-ad-slot="xxxxxxx"
data-ad-format="auto"
data-adtest="on"
data-full-width-responsive="true"
/>
</>
}
I still don't know what's import {Adsense} from './googleAdsense', this line may collide with the naming of the component that you are defining (both are Adsense). If the issue persists, try changing the name.
To make the ads available on localhost, set the data-adtest as on.
In addition, you can try using a React-based solution like the one that react-adsense suggests.
Double-check and remove AdBlocks (or similar).
However, the image of the ad did not show up.
This can be caused by the localhost. Try deploying the site to check it in a real domain.
Have spent a couple days on this issue sourcing solutions and ideas from most of SA and Reddit however to no avail..
Upon load both in production and local every load presents the whole html without any styling before then being injected into DOM..
Currently this is my projects key files:
_document.js
import { ServerStyleSheet } from "styled-components";
import Document, { Main, NextScript } from "next/document";
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
render() {
return (
<html lang="en">
<Head>
<title>namesjames</title>
<link rel="icon" href="/favicon.ico" />
<script src="/static/chrome-fix.js" />
<link href="/above-the-fold.css" />
</Head>
<body>
<script src="/noflash.js" />
<Main />
<NextScript />
<script> </script>
</body>
</html>
);
}
}
_app.js
/* eslint-disable class-methods-use-this */
import App from "next/app";
import React from "react";
import { ThemeProvider } from "styled-components";
import { ParallaxProvider } from 'react-scroll-parallax';
import Header from "../components/Header";
import theme from "../theme";
import GlobalStyles from "../GlobalStyles";
import DarkModeToggle from '../components/toggle/toggleMode';
import Footer from '../components/Footer'
import LazyLoad from 'react-lazy-load';
import Router from 'next/router';
import styled from 'styled-components'
// import '../style.css'
const Loaded = styled.div`
opacity: ${(props) => props.loaded ? "1" : "0"};
`
export default class MyApp extends App {
state = { isLoading: false, loaded: false }
componentDidMount() {
// Logging to prove _app.js only mounts once,
// but initializing router events here will also accomplishes
// goal of setting state on route change
console.log('MOUNT');
this.setState({loaded: true})
Router.events.on('routeChangeStart', () => {
this.setState({ isLoading: true });
console.log('loading is true, routechangeStart')
});
Router.events.on('routeChangeComplete', () => {
this.setState({ isLoading: false });
console.log('loading is false, routeChangeComplete')
});
Router.events.on('routeChangeError', () => {
this.setState({ isLoading: false });
console.log('loading is false, routeChangeError')
});
}
render(): JSX.Element {
const { isLoading } = this.state;
const { Component, pageProps, router, loaded } = this.props;
return (
<Loaded loaded={this.state.loaded}>
<ThemeProvider theme={theme}>
<GlobalStyles />
<ParallaxProvider>
<Header />
{isLoading && 'STRING OR LOADING COMPONENT HERE...'}
<Component {...pageProps} key={router.route} />
<LazyLoad offsetVertical={500}>
<Footer />
</LazyLoad>
</ParallaxProvider>
<DarkModeToggle />
</ThemeProvider>
</Loaded>
);
}
}
index.js
import { color } from "styled-system";
import { OffWhite } from "../util/tokens";
import Hero from "../components/Hero";
import Banner from '../components/Banner'
import TitleText from '../components/TitleText'
import HomeTitleCopyScene from '../components/HomeTitleCopyScene'
import TwoCards from '../components/TwoCards'
import LazyLoad from 'react-lazy-load';
function Home(): JSX.Element {
return (
<div className="container">
<Banner />
<HomeTitleCopyScene />
<LazyLoad offsetVertical={1000}>
<TwoCards />
</LazyLoad>
</div>
);
}
export default Home;
As some might see I have tried multiple implementations and am just a bit confused as to what it could be at this stage..
Any help appreciated and I can provide more information upon request.. Many thanks
I found two solutions which helped -->
Was to hard style opacity:0 into the JSX and then upon styling injecting into DOM applying opacity: 1 !important onto any of the components displayed..
<section className="cards-block" style={{opacity:0}}>
Whilst this was effective this morning I discovered at some point during my development I had incorrectly imported Head from next/head and used this in my _document.js rather than using the correct Head from next/documents..
// import Head from "next/head"; --> incorrect
import { ServerStyleSheet } from "styled-components";
import Document, { Head, Main, NextScript } from "next/document";
Ergo -> a correctly rendering and injected element with no FOUC
Hope this helps someone out there
I've found a workaround for my small portfolio project:
just included this inline css to a <head> of my custom _document.js:
{<style dangerouslySetInnerHTML={{__html: `
html {background: #333}
body #__next div {visibility: hidden}
body.loaded #__next div {visibility: visible}
`}}></style>}
The "loaded" class is added to the body in _app.js:
if (process.browser) {
document.body.classList.add("loaded")
}
I'm hot sure if it's a good solution, any advice would be appreciated :)
I am trying to introduce a theme switcher in my app. I have a lot of non-material-ui elements that I need the theme to reflect the changes on them.
The code below shows that I have a state that is called darkState that is set to true. The material ui components in my app reflect those changes but for example the div below does not get the dark color of the dark theme. What is that I am doing wrong in here?
import React, { useState } from "react";
import Header from "./components/Header.js";
import TopBar from "./components/TopBar.js";
import Sequence from "./components/Sequence.js";
import SecondaryWindow from "./components/SecondaryWindow.js";
import { MuiThemeProvider, createMuiTheme, makeStyles } from "#material-ui/core/styles";
import "./App.css";
import { MainContextProvider } from "./contexts/mainContext.js";
function App() {
const [darkState, setDarkState] = useState(true);
const palletType = darkState ? "dark" : "light";
const theme = createMuiTheme({
palette: {
secondary: {
main: "#0069ff",
},
type: palletType,
},
});
const useStyles = makeStyles((theme) => ({
root: {
paddingLeft: 80,
height: "100%",
backgroundColor: theme.palette.background.default,
},
}));
const classes = useStyles();
return (
<MuiThemeProvider theme={theme}>
<MainContextProvider>
<div className={classes.root}>
<Header />
<TopBar />
<Sequence />
<SecondaryWindow />
</div>
</MainContextProvider>
</MuiThemeProvider>
);
}
export default App;
Now I know the answer, in my example, the class root is not able to benefit from the custom-created theme that is provided by MuiThemeProvider. Instead, it uses the original theme that comes in Mui. To solve this, I separated that div into a component. This way, the theme context (custom-theme from MuiThemeProvider) can be accessed by the div. This way when I switch DarkState, colors update on Mui components and HTML elements based on the custom theme palette.
import React, { useContext, useState } from "react";
import Header from "./components/Header.js";
import TopBar from "./components/TopBar.js";
import Sequence from "./components/Sequence.js";
import SecondaryWindow from "./components/SecondaryWindow.js";
import { MuiThemeProvider, createMuiTheme, makeStyles } from "#material-ui/core/styles";
import "./App.css";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { MainContextProvider } from "./contexts/mainContext.js";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
function AppContent() {
const useStyles = makeStyles((theme) => ({
root: {
paddingLeft: 80,
height: "100%",
backgroundColor: theme.palette.background.default,
},
}));
const classes = useStyles();
return (
<div className={classes.root}>
<Header />
<TopBar />
<Sequence />
<SecondaryWindow />
</div>
);
}
function App() {
const [darkState, setDarkState] = useState(true);
const palletType = darkState ? "dark" : "light";
const theme = createMuiTheme({
palette: {
secondary: {
main: "#0069ff",
},
type: palletType,
},
});
return (
<MuiThemeProvider theme={theme}>
<MainContextProvider>
<AppContent />
</MainContextProvider>
</MuiThemeProvider>
);
}
export default App;
It's because you only change the #material component not the CSS, to change the CSS Theme, you need to make variable for CSS for Dark Theme.
on :root declare all the light theme color and div.darkmode all the darkmode:
:root {
--color-bg: #fff;
--color-text: #000;
}
.div.darkmode {
--color-bg: #363636;
--color-text: #d1d1d1;
}
/** Usage */
.div {
color: var(--color-text);
background: var(--color-bg)
}
and make a condition on the div when the dark theme is true a new classname darkmode will be added to dive as you wrote above
<div className={`${classes.root} ${darkState && `darkmode`}`}>
<Header />
<TopBar />
<Sequence />
<SecondaryWindow />
</div>
I created an example for you here.
let us know if anything goes wrong!
workaround 2
if you're not doing any customer style by CSS file then this will work
import React from 'react';
import CssBaseline from '#material-ui/core/CssBaseline';
export default function MyApp() {
return (
<MuiThemeProvider theme={theme}>
<CssBaseline />
{/* The rest of your application */}
</MuiThemeProvider>
);
}
I would declare both variations of your theme as constants above the mounting or rendering. This way you are not literally creating a new theme ever time your theme swaps. I would have a state holding the reference to the MUI-Theme constant.
You can manipulate data-theme attribute to toggle the dark/light theme. Try it on StackBlitz.
Setting up themes
Use data-theme attribute to set the selected theme.
/* default theme (light) */
:root {
--primary-color: #302ae6;
--secondary-color: #536390;
--font-color: #424242;
--bg-color: #fff;
}
/* dark theme */
[data-theme='dark'] {
--primary-color: #9a97f3;
--secondary-color: #818cab;
--font-color: #e1e1ff;
--bg-color: #161625;
}
Switching theme in React Hooks
// App.js
const [theme, setTheme] = useState({
light: true,
});
const handleChangeTheme = (event) => {
setTheme({ ...theme, [event.target.name]: event.target.checked });
};
Set our data-theme attribute accordingly
const currentTheme = theme.light === true ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', currentTheme);
I'm having a hard time trying to make ra-tree-ui-materialui work following this doc :
https://github.com/marmelab/react-admin/blob/master/packages/ra-tree-ui-materialui/README.md
I already have a react-admin backoffice with some fixture data, and I decided, after editing my App.js like explained in link above, to put my tree logic inside SegmentationList.js, which manages display of all Segmentations coming from an APIPlatform backend.
I commented datagrid logic already present in file, to test the tree alone. I kept all imports active and added those needed for the tree like in docs. With this code I manage to have the tree displayed, but with no hierarchy view at all, even when I set a row as child of another by editing, or when I do it via drag and drop.
When I try the latter, I actually view the child row nested inside its parent with collapse button for a few seconds only. Then it comes back to a flat tree.
I have tried to disable JSS in the file to see if style was guilty. I checked if react-dnd was installed and it is. I checked that parent field had value expected in child row by coming back to its edit page. Finally I went to backend side to check if parent field values in DB were consistent with what I saw in frontend, it was. Finally I had a look on this topic : https://github.com/marmelab/react-admin/issues/2980 since I also have the warning "Missing translation for key: "ra.tree.root_target"".
Thanks for your help.
First, here is my App.js file :
import React, {Component} from 'react';
import { Admin, Resource, mergeTranslations } from 'react-admin';
import { reducer as tree } from 'ra-tree-ui-materialui';
import englishMessage from 'ra-language-english';
import treeEnglishMessages from 'ra-tree-language-english';
import parseHydraDocumentation from '#api-platform/api-doc-parser/lib/hydra/parseHydraDocumentation';
import { hydraClient } from '#api-platform/admin';
import Locale from "./Resources/Locale/"
import Segmentation from "./Resources/Segmentation/"
import SegmentationTranslation from "./Resources/SegmentationTranslation/"
import Product from "./Resources/Product/"
import Attribute from "./Resources/Attribute/"
import ProductTranslation from "./Resources/ProductTranslation/"
import translations from './i18n';
import CustomRoute from './routes';
import themeReducer from './themeReducer';
import { Layout } from './layout';
import LocaleRetrieve from './Utils/LocaleRetrieve';
const messages = {
'en': mergeTranslations(englishMessage, treeEnglishMessages),
};
const dataProvider = api => hydraClient(api);
const httpEndpoint = process.env.REACT_APP_XXX_HTTP;
const apiDocumentationParser = httpEndpoint => parseHydraDocumentation(httpEndpoint)
.then(
({ api }) => ({api})
);
const i18nProvider = locale => {
// change of locale after initial call returns a promise
return translations[locale];
}
export default class extends Component {
state = { api: null };
componentDidMount() {
apiDocumentationParser(httpEndpoint).then(({ api }) => {
this.setState({ api });
}).catch((e) => {
console.log(e);
});
console.log(LocaleRetrieve());
};
render() {
if (null === this.state.api) return <div>Loading...</div>;
return (
<Admin api={ this.state.api }
apiDocumentationParser={ apiDocumentationParser }
dataProvider= { dataProvider(this.state.api) }
customReducers={{theme: themeReducer, tree}}
messages={translations}
locale="en"
i18nProvider={i18nProvider}
title="XXX"
customRoutes={CustomRoute}
appLayout={Layout}
>
<Resource name="locales" {...Locale} />
<Resource name="segmentations" {...Segmentation} />
<Resource name="segmentation_translations" {...SegmentationTranslation}/>
<Resource name="products" {...Product}/>
<Resource name="product_translations" {...ProductTranslation}/>
<Resource name="attributes" {...Attribute}/>
</Admin>
)
}
}
and here is my component with tree logic, located in src/Resources/Segmentation/SegmentationList.js :
import React, {Fragment} from 'react';
import {List, Datagrid, TextField, ChipField, BooleanField, ReferenceField, EditButton, ReferenceInput, AutocompleteInput, ShowButton, Filter, TextInput, Labeled, CardActions, ExportButton, RefreshButton, DeleteButton, SaveButton } from 'react-admin';
import LinkToTranslatations from './LinkToTranslations';
import AddChildButton from "./AddChildButton";
import ListChildButton from "./ListChildButton";
import PublishedButtons from './PublishedButtons';
import CreateSegmentationButtons from './CreateSegmentationButtons';
// for tree
import { withStyles } from '#material-ui/core/styles';
import { IgnoreFormProps, Tree, NodeForm, NodeActions, NodeView } from 'ra-tree-ui-materialui';
const styles = {
hash: {
marginLeft: '15px',
fontWeight: 'bold',
marginRight: '15px'
},
type: {
marginLeft: '15px',
marginRight: '15px',
textTransform: 'uppercase'
},
title: {
marginLeft: '15px',
marginRight: '15px'
}
};
// for tree
const SegmentationTreeActions = props => (
<NodeActions {...props}>
<LinkToTranslatations />
<ShowButton />
<IgnoreFormProps>
<EditButton />
<DeleteButton />
</IgnoreFormProps>
</NodeActions>
);
// tree
export const SegmentationList = withStyles(styles)(({ classes, ...props}) => (
<List {...props} perPage={10000}>
<Tree allowDropOnRoot enableDragAndDrop>
<NodeView actions={<SegmentationTreeActions />}>
<TextField source="hash" className={classes.hash} />
<TextField source="type" className={classes.type} />
<TextField source="title" className={classes.title} />
</NodeView>
</Tree>
</List>
));
export default SegmentationList;