@kiwicom/smart-faq
Version:
198 lines (161 loc) • 5.04 kB
JavaScript
// @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;