import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; import * as React from 'react'; import DocumentTitle = require('react-document-title'); import { scroller, } from 'react-scroll'; import {TopBar} from 'ts/components/top_bar'; import {MarkdownSection} from 'ts/pages/shared/markdown_section'; import {NestedSidebarMenu} from 'ts/pages/shared/nested_sidebar_menu'; import {SectionHeader} from 'ts/pages/shared/section_header'; import {Article, ArticlesBySection, HeaderSizes, Styles, WebsitePaths} from 'ts/types'; import {colors} from 'ts/utils/colors'; import {configs} from 'ts/utils/configs'; import {constants} from 'ts/utils/constants'; import {utils} from 'ts/utils/utils'; const WIKI_NOT_READY_BACKOUT_TIMEOUT_MS = 5000; export interface WikiProps { source: string; location: Location; } interface WikiState { articlesBySection: ArticlesBySection; } const styles: Styles = { mainContainers: { position: 'absolute', top: 1, left: 0, bottom: 0, right: 0, overflowZ: 'hidden', overflowY: 'scroll', minHeight: 'calc(100vh - 1px)', WebkitOverflowScrolling: 'touch', }, menuContainer: { borderColor: colors.grey300, maxWidth: 330, marginLeft: 20, }, }; export class Wiki extends React.Component { private _wikiBackoffTimeoutId: number; constructor(props: WikiProps) { super(props); this.state = { articlesBySection: undefined, }; } public componentWillMount() { // tslint:disable-next-line:no-floating-promises this._fetchArticlesBySectionAsync(); } public componentWillUnmount() { clearTimeout(this._wikiBackoffTimeoutId); } public render() { const menuSubsectionsBySection = _.isUndefined(this.state.articlesBySection) ? {} : this._getMenuSubsectionsBySection(this.state.articlesBySection); return (
{_.isUndefined(this.state.articlesBySection) ?
Loading wiki...
:

0x Protocol Wiki

{this._renderWikiArticles()}
}
); } private _renderWikiArticles(): React.ReactNode { const sectionNames = _.keys(this.state.articlesBySection); const sections = _.map(sectionNames, sectionName => this._renderSection(sectionName)); return sections; } private _renderSection(sectionName: string) { const articles = this.state.articlesBySection[sectionName]; const renderedArticles = _.map(articles, (article: Article) => { const githubLink = `${constants.URL_GITHUB_WIKI}/edit/master/${sectionName}/${article.fileName}`; return (
See a way to make this article better?{' '} Edit here →
); }); return (
{renderedArticles}
); } private _scrollToHash(): void { const hashWithPrefix = this.props.location.hash; let hash = hashWithPrefix.slice(1); if (_.isEmpty(hash)) { hash = '0xProtocolWiki'; // scroll to the top } scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'}); } private async _fetchArticlesBySectionAsync(): Promise { const endpoint = `${configs.BACKEND_BASE_URL}${WebsitePaths.Wiki}`; const response = await fetch(endpoint); if (response.status === constants.HTTP_NO_CONTENT_STATUS_CODE) { // We need to backoff and try fetching again later this._wikiBackoffTimeoutId = window.setTimeout(() => { // tslint:disable-next-line:no-floating-promises this._fetchArticlesBySectionAsync(); }, WIKI_NOT_READY_BACKOUT_TIMEOUT_MS); return; } if (response.status !== 200) { // TODO: Show the user an error message when the wiki fail to load const errMsg = await response.text(); utils.consoleLog(`Failed to load wiki: ${response.status} ${errMsg}`); return; } const articlesBySection = await response.json(); this.setState({ articlesBySection, }, () => { this._scrollToHash(); }); } private _getMenuSubsectionsBySection(articlesBySection: ArticlesBySection) { const sectionNames = _.keys(articlesBySection); const menuSubsectionsBySection: {[section: string]: string[]} = {}; for (const sectionName of sectionNames) { const articles = articlesBySection[sectionName]; const articleNames = _.map(articles, article => article.title); menuSubsectionsBySection[sectionName] = articleNames; } return menuSubsectionsBySection; } }