UNPKG

@kiwicom/smart-faq

Version:

Smart FAQ

203 lines (178 loc) 5.35 kB
// @flow import * as React from 'react'; import App, { Container } from 'next/app'; import reactTreeWalker from 'react-tree-walker'; import { fetchQuery } from 'react-relay'; import { Environment } from 'relay-runtime'; import { MemoryRouter } from 'react-router-dom'; import { ThemeProvider } from 'styled-components'; import { getTokens } from '@kiwicom/orbit-design-tokens'; import * as intlContext from '@kiwicom/nitro/lib/services/intl/context'; import InitIntl from '@kiwicom/nitro/lib/components/InitIntl'; import SSRContext from '../shared/ssr/SSRContext'; import { isBrowser } from '../shared/helpers'; import RelayProvider from '../shared/ssr/RelayProvider'; import createEnvironment from '../shared/relay/environment'; import { langInfos } from '../translations/langInfos'; import fallbackTranslations from '../translations/enKeys.json'; const TRANSLATION_FILES = require('../../data/translationsFiles.json'); export const theme = { orbit: getTokens() }; const collectQueryDefinitions = async ( Component: React.ComponentType<Object>, ): Promise<Array<Object>> => { const fetchers = []; await reactTreeWalker(<Component />, (element, instance) => { const fetcher = (value => value && value.fetchSSRData)(instance || element); if (fetcher) { fetchers.push(fetcher); } }); return fetchers.map(fetcher => fetcher()); }; const getTranslations = (phraseAppLanguageCode: string) => { // eslint-disable-next-line import/no-dynamic-require return require(`../../data/${TRANSLATION_FILES[phraseAppLanguageCode]}`); }; type QueryDefinition = {| query: string, variables: { [string]: mixed, }, |}; class MyApp extends App { static async fetchData( environment: Environment, query: string, variablesMap: Object, ) { try { return await fetchQuery(environment, query, variablesMap); } catch (e) { console.warn('GraphQL error:', e); // eslint-disable-line no-console return { relayFetchError: true }; } } static async getStaticInitialProps( environment: Environment, Props: { [string]: mixed }, ) { return { dataProps: {}, variablesFromSSR: {}, recordStoreFromSSR: isBrowser() ? {} : environment .getStore() .getSource() .toJSON(), ...Props, }; } static async getDynamicInitialProps( queryDefinitions: Array<QueryDefinition>, environment: Environment, ctx: Object, Props: { [string]: mixed }, ) { const { variables } = queryDefinitions[0]; const dataProps = await this.fetchData( environment, queryDefinitions[0].query, variables, ); if (dataProps.relayFetchError && ctx.res) { ctx.res.status(500); } return { dataProps, variablesFromSSR: variables, recordStoreFromSSR: isBrowser() ? {} : environment .getStore() .getSource() .toJSON(), ...Props, }; } static getPhraseAppLanguageCode(lng: string) { try { return langInfos[lng].phraseApp; } catch (e) { return 'en-GB'; } } static async getTranslationData(ctx: Object) { const lng = ctx.query.lng || 'en'; const phraseAppLanguageCode = this.getPhraseAppLanguageCode(lng); return { lng, phraseAppLanguageCode, translations: getTranslations(phraseAppLanguageCode), }; } static async getInitialProps({ Component, ctx }: Object) { const queryDefinitions = await collectQueryDefinitions(Component); const Props = { pageProps: await this.getPageProps(Component, ctx), ...(await this.getTranslationData(ctx)), }; const environment = createEnvironment(null, null, Props.lng); if (queryDefinitions.length === 0) { return await this.getStaticInitialProps(environment, Props); } return await this.getDynamicInitialProps( queryDefinitions, environment, ctx, Props, ); } static async getPageProps(Component: Object, ctx: Object) { if (Component.getInitialProps) { return Component.getInitialProps(ctx); } return {}; } environment = createEnvironment( null, null, this.props.lng, this.props.recordStoreFromSSR, ); render() { const { Component, pageProps } = this.props; const langInfo = langInfos[this.props.lng]; const translations = this.props.translations ? this.props.translations : fallbackTranslations; const intl = { language: langInfo, translations }; return ( <Container> <RelayProvider environment={this.environment} variables={this.props.variablesFromSSR} > <SSRContext.Provider value={{ data: this.props.dataProps, }} > <InitIntl raw={intl}> {intl => ( <intlContext.Provider value={intl}> <MemoryRouter> <ThemeProvider theme={theme}> <Component {...pageProps} /> </ThemeProvider> </MemoryRouter> </intlContext.Provider> )} </InitIntl> </SSRContext.Provider> </RelayProvider> </Container> ); } } export default MyApp;