UNPKG

@kiwicom/smart-faq

Version:

198 lines (161 loc) 5.04 kB
// @flow import * as React from 'react'; import EventListener from 'react-event-listener'; import { createMemoryHistory as createHistory } from 'history'; import { Router } from 'react-router'; import type { RouterHistory } from 'react-router-dom'; import { UserContext } from '../context/User'; import type { UserContextType } from '../context/User'; import LogSidebarUsage from '../../components/Log/LogSidebarUsage'; type Props = {| isOpen: boolean, openArticle: ?string, onToggle: (shouldBeOpened: boolean) => void, children: React.Node, |}; type State = {| initialEntry: ?string, |}; class QueryParamRouter extends React.Component<Props, State> { history: RouterHistory; unlisten: () => void; context: UserContextType; static contextType = UserContext; constructor(props: Props, context: UserContextType) { super(props, context); // if user loaded app with specific ?help route, open it const currentPath = this.getLocation(); // but if he is logged in and is trying to open intro page, he should be redirected to FAQs const initialPath = currentPath === '/' && (context.user || context.simpleToken) ? '/faq' : currentPath; // if no help path is present in browser url, check props as last fallback const initialEntry = initialPath ?? this.getInitialEntry(props, context); this.state = { initialEntry, }; const history = createHistory({ initialEntries: initialEntry ? [initialEntry] : [], initialIndex: 0, getUserConfirmation: (message, callback) => // FIXME: do we really need this alert? // eslint-disable-next-line no-alert callback(window.confirm(message)), }); this.unlisten = history.listen(this.onHistoryChange); this.history = history; this.updateUrlParam(initialEntry); } componentDidMount() { if (this.state.initialEntry && !this.props.isOpen) { this.props.onToggle(true); } } componentDidUpdate(prevProps: Props) { const { isOpen, openArticle } = this.props; if (isOpen !== prevProps.isOpen) { if (!this.state.initialEntry && isOpen) { // SmartFAQ is being opened for the first time const initialEntry = this.getInitialEntry(this.props, this.context); if (!initialEntry) { return; } this.history.push(initialEntry); // eslint-disable-next-line react/no-did-update-set-state this.setState({ initialEntry }, () => { this.updateUrlParam(initialEntry); }); return; } // We are opening specific article if (openArticle && isOpen) { const pathname = `/faq/search/article/${openArticle}`; this.history.push(pathname); return; } // SmartFAQ is reopened, last visited page is shown if (isOpen) { this.updateUrlParam(this.history.location.pathname); } if (!isOpen) { this.updateUrlParam(null); } } } componentWillUnmount() { this.unlisten(); } getInitialEntry = (props: Props, context: UserContextType) => { if (props.isOpen) { if (props.openArticle) { return `/faq/search/article/${props.openArticle}`; } return context.user || context.simpleToken ? '/faq' : '/'; } return null; }; getLocation = () => { const location = window.location; const params = new URLSearchParams(location.search); return params.get('help'); }; updateUrlParam = (pathname: ?string) => { if (typeof window === 'undefined') { return; } const location = window.location; const params = new URLSearchParams(location.search); if (pathname === params.get('help')) { return; } if (pathname) { params.set('help', pathname); } else { params.delete('help'); } window.history.pushState( {}, null, `${location.pathname}?${params.toString()}`, ); }; onPopStateChange = () => { let path = this.getLocation(); if (this.history.location?.pathname === '/faq' && path === '/') { // user is logged in & going to intro page if (this.context.user || this.context.simpleToken) { path = null; } } if (typeof path !== 'string') { if (this.props.isOpen) { this.props.onToggle(false); } return; } if (!this.props.isOpen && path) { this.props.onToggle(true); } this.history.push(path); }; onHistoryChange = (location: { pathname: string }) => { this.updateUrlParam(location.pathname); }; render() { const { isOpen } = this.props; const { initialEntry } = this.state; return ( <> <EventListener target="window" onpopstate={this.onPopStateChange} /> {isOpen && initialEntry && ( <> <LogSidebarUsage /> <Router history={this.history}>{this.props.children}</Router> </> )} </> ); } } export default QueryParamRouter;