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; } }