UNPKG

@kiwicom/smart-faq

Version:

Smart FAQ

315 lines (286 loc) 8.96 kB
// @flow import * as React from 'react'; import App, { Container } from 'next/app'; import reactTreeWalker from '@jaredlunde/react-tree-walker'; import { fetchQuery, ReactRelayContext } from 'react-relay'; import { Environment } from 'relay-runtime'; import { getTokens } from '@kiwicom/orbit-design-tokens'; import NavBar from '@kiwicom/nitro/lib/components/NavBar'; import Heading from '@kiwicom/orbit-components/lib/Heading'; import Translate from '@kiwicom/nitro/lib/components/Translate'; import InputField from '@kiwicom/orbit-components/lib/InputField'; import Search from '@kiwicom/orbit-components/lib/icons/Search'; import Stack from '@kiwicom/orbit-components/lib/Stack'; import { Consumer as IntlConsumer } from '@kiwicom/nitro/lib/services/intl/context'; import MobileDetect from 'mobile-detect'; import fallbackTranslations from '../translations/enKeys.json'; import { langInfos } from '../translations/langInfos'; import createEnvironment from '../shared/relay/environment'; import Contexts from '../shared/ssr/Contexts'; import { isBrowser } from '../shared/helpers'; import SSRContext from '../shared/ssr/SSRContext'; import countries from '../../data/countries.json'; import languages from '../../data/languages.json'; import airlines from '../../data/airlines.json'; import continents from '../../data/continents.json'; import brands from '../../data/brands.json'; import brandLanguages from '../../data/brandLanguages.json'; import GlobalStyles from '../FullPage/GlobalStyles'; const TRANSLATION_FILES = require('../../data/translationsFiles.json'); export const theme = { orbit: getTokens() }; const userContext = { user: null, brand: 'kiwicom', loginToken: null, simpleToken: null, kwAuthToken: null, onLogin: () => {}, onLogout: () => Promise.resolve(null), }; const collectQueryDefinitions = async ( Component: React.ComponentType<Object>, location, screenWidth, ): Promise<Array<Object>> => { const fetchers = []; const WrappedComponent = () => ( <Contexts location={location} lng="en" userContext={userContext} theme={theme} currencyId="" countries={{}} brand={{}} language={{}} fetched={{}} intl={{}} screenWidth={screenWidth} > <Component /> </Contexts> ); await reactTreeWalker(<WrappedComponent />, (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 fullPath = isBrowser() ? window.location.pathname : ctx?.req?.url; const location = fullPath.slice(3); const device = new MobileDetect(ctx.req.headers['user-agent']); const screenWidth = device.is('mobile') ? 320 : device.is('tablet') ? 640 : 1280; const queryDefinitions = await collectQueryDefinitions( Component, location, screenWidth, ); const Props = { location, pageProps: await this.getPageProps(Component, ctx), screenWidth, ...(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, location, screenWidth } = this.props; const langInfo = langInfos[this.props.lng]; const translations = this.props.translations ? this.props.translations : fallbackTranslations; const intl = { language: langInfo, translations }; const brandId = 'kiwicom'; const localeId = 'en'; const brand = brands[brandId]; const language = languages[localeId]; const fetched = { brandLanguage: brandLanguages[brandId][localeId], countries, airlines, continents, }; const currencyId = 'eur'; return ( <Container> <ReactRelayContext.Provider value={{ environment: this.environment, variables: this.props.variablesFromSSR, }} > <SSRContext.Provider value={{ data: this.props.dataProps, }} > <Contexts location={location} lng={this.props.lng} userContext={userContext} theme={theme} currencyId={currencyId} language={language} countries={countries} brand={brand} fetched={fetched} intl={intl} screenWidth={screenWidth} > <div> <NavBar headerLinks={<div />} chat={<h1>Chat</h1>} subscription={<h1>Subscription</h1>} debug={<h1>Debug</h1>} portal="modal-portal" starred="" onOpenFaq={() => undefined} onSetModal={() => undefined} onLogoClick={() => undefined} onSaveLanguage={() => undefined} onSelectTrip={() => undefined} /> <div className="SmartFAQ"> <Stack spaceAfter="largest"> <Heading type="display" element="h1" spaceAfter="medium"> <Translate t={__('smartfaq.full_page.how_can_we_help_you')} /> </Heading> <IntlConsumer> {intl => ( <InputField size="small" type="text" value="" onChange={() => {}} placeholder={intl.translate( __('smartfaq.full_page.search.placeholder'), )} prefix={<Search />} /> )} </IntlConsumer> </Stack> <Component {...pageProps} /> </div> <GlobalStyles /> </div> </Contexts> <div id="modal-portal" /> </SSRContext.Provider> </ReactRelayContext.Provider> </Container> ); } } export default MyApp;