aboutsummaryrefslogblamecommitdiffstats
path: root/packages/website/ts/pages/wiki/wiki.tsx
blob: c3c1600a58e9dfb77414cd159a09242d5b61f060 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
        
          
           

                                 
         
                    
                         

                                      
                            
                                                            
                               
                                                                           
                                                                      
                                                 
                                                       
                                                                        
                                                 
                                                                               
                                                        
                                               
                                               
                                       





                                               

                           
                              



                                         
                               

 
                                                                 
                                          
                                  

                                   
                                  

                                         
                                     

          
                                       
                                                        
                                            
     
                                         
                                 
                                                 
     
                                      
                                                                              
                
                                                                        







                                                                              
                                                                         


                                                                       


                                                                                       
                                                    
              
          
                










                                                     








                                                                                   
                                               









                                                                                       
                                                                       





                                                                                        










                                                                       

          
                                                    
                                                                  
                                                                                              

                        
                                                                  

                                                                        
                                                                                                             







                                                               


                      
                                                                            
     
                                                                 







                                                                                          
                                                      














                                                                                            
         
     
                                                                                              
                                                       
                                                          

                                                            



                                                                 


                                                           
         
                                  

     
import {
    ALink,
    colors,
    constants as sharedConstants,
    HeaderSizes,
    Link,
    MarkdownSection,
    utils as sharedUtils,
} from '@0x/react-shared';
import { ObjectMap } from '@0x/types';
import * as _ from 'lodash';
import CircularProgress from 'material-ui/CircularProgress';
import * as React from 'react';
import { SidebarHeader } from 'ts/components/documentation/sidebar_header';
import { NestedSidebarMenu } from 'ts/components/nested_sidebar_menu';
import { Button } from 'ts/components/ui/button';
import { Container } from 'ts/components/ui/container';
import { DevelopersPage } from 'ts/pages/documentation/developers_page';
import { Dispatcher } from 'ts/redux/dispatcher';
import { Article, ArticlesBySection, Deco, Key, ScreenWidths } from 'ts/types';
import { backendClient } from 'ts/utils/backend_client';
import { constants } from 'ts/utils/constants';
import { Translate } from 'ts/utils/translate';
import { utils } from 'ts/utils/utils';

const WIKI_NOT_READY_BACKOUT_TIMEOUT_MS = 5000;

export interface WikiProps {
    source: string;
    location: Location;
    dispatcher: Dispatcher;
    translate: Translate;
    screenWidth: ScreenWidths;
}

interface WikiState {
    articlesBySection: ArticlesBySection;
    isHoveringSidebar: boolean;
}

export class Wiki extends React.Component<WikiProps, WikiState> {
    private _wikiBackoffTimeoutId: number;
    private _isUnmounted: boolean;
    constructor(props: WikiProps) {
        super(props);
        this._isUnmounted = false;
        this.state = {
            articlesBySection: undefined,
            isHoveringSidebar: false,
        };
    }
    public componentWillMount(): void {
        // tslint:disable-next-line:no-floating-promises
        this._fetchArticlesBySectionAsync();
    }
    public componentWillUnmount(): void {
        this._isUnmounted = true;
        clearTimeout(this._wikiBackoffTimeoutId);
    }
    public render(): React.ReactNode {
        const sectionNameToLinks = _.isUndefined(this.state.articlesBySection)
            ? {}
            : this._getSectionNameToLinks(this.state.articlesBySection);

        const mainContent = _.isUndefined(this.state.articlesBySection) ? (
            <div className="flex justify-center">{this._renderLoading()}</div>
        ) : (
            <div id="wiki" style={{ paddingRight: 2 }}>
                {this._renderWikiArticles()}
            </div>
        );
        const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm;
        const sidebar = _.isUndefined(this.state.articlesBySection) ? (
            <div />
        ) : (
            <NestedSidebarMenu
                sidebarHeader={isSmallScreen ? this._renderSidebarHeader() : undefined}
                sectionNameToLinks={sectionNameToLinks}
                screenWidth={this.props.screenWidth}
            />
        );
        return (
            <DevelopersPage
                sidebar={sidebar}
                mainContent={mainContent}
                location={this.props.location}
                screenWidth={this.props.screenWidth}
                translate={this.props.translate}
                dispatcher={this.props.dispatcher}
            />
        );
    }
    private _renderSidebarHeader(): React.ReactNode {
        const menuItems = _.map(constants.DEVELOPER_TOPBAR_LINKS, menuItemInfo => {
            return (
                <Link
                    key={`menu-item-${menuItemInfo.title}`}
                    to={menuItemInfo.to}
                    shouldOpenInNewTab={menuItemInfo.shouldOpenInNewTab}
                >
                    <Button
                        borderRadius="4px"
                        padding="0.4em 0.375em"
                        width="100%"
                        fontColor={colors.grey800}
                        fontSize="14px"
                        textAlign="left"
                    >
                        {this.props.translate.get(menuItemInfo.title as Key, Deco.Cap)}
                    </Button>
                </Link>
            );
        });
        const wikiTitle = this.props.translate.get(Key.Wiki, Deco.Cap);
        return (
            <Container>
                <SidebarHeader screenWidth={this.props.screenWidth} title={wikiTitle} />
                {menuItems}
            </Container>
        );
    }
    private _renderLoading(): React.ReactNode {
        return (
            <Container className="pt4">
                <Container className="center pb2">
                    <CircularProgress size={40} thickness={5} />
                </Container>
                <Container className="center pt2" paddingBottom="11px">
                    Loading wiki...
                </Container>
            </Container>
        );
    }
    private _renderWikiArticles(): React.ReactNode {
        const sectionNames = _.keys(this.state.articlesBySection);
        const sections = _.map(sectionNames, sectionName => this._renderSection(sectionName));
        return sections;
    }
    private _renderSection(sectionName: string): React.ReactNode {
        const articles = this.state.articlesBySection[sectionName];
        const renderedArticles = _.map(articles, (article: Article) => {
            const githubLink = `${constants.URL_GITHUB_WIKI}/edit/master/${sectionName}/${article.fileName}`;
            return (
                <div key={`markdown-section-${article.title}`}>
                    <MarkdownSection
                        sectionName={article.title}
                        markdownContent={article.content}
                        headerSize={HeaderSizes.H2}
                        githubLink={githubLink}
                    />
                </div>
            );
        });
        return <div key={`section-${sectionName}`}>{renderedArticles}</div>;
    }
    private async _fetchArticlesBySectionAsync(): Promise<void> {
        try {
            const articlesBySection = await backendClient.getWikiArticlesBySectionAsync();
            if (!this._isUnmounted) {
                this.setState(
                    {
                        articlesBySection,
                    },
                    async () => {
                        await utils.onPageLoadPromise;
                        const hash = this.props.location.hash.slice(1);
                        sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID);
                    },
                );
            }
        } catch (err) {
            const errMsg = `${err}`;
            if (_.includes(errMsg, `${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;
            }
        }
    }
    private _getSectionNameToLinks(articlesBySection: ArticlesBySection): ObjectMap<ALink[]> {
        const sectionNames = _.keys(articlesBySection);
        const sectionNameToLinks: ObjectMap<ALink[]> = {};
        for (const sectionName of sectionNames) {
            const articles = articlesBySection[sectionName];
            const articleLinks = _.map(articles, article => {
                return {
                    to: sharedUtils.getIdFromName(article.title),
                    title: article.title,
                };
            });
            sectionNameToLinks[sectionName] = articleLinks;
        }
        return sectionNameToLinks;
    }
}