import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; import * as React from 'react'; import { Retry } from 'ts/components/ui/retry'; import { Text } from 'ts/components/ui/text'; import { HeaderItem } from 'ts/pages/jobs/list/header_item'; import { ListItem } from 'ts/pages/jobs/list/list_item'; import { colors } from 'ts/style/colors'; import { styled } from 'ts/style/theme'; import { ScreenWidths, WebsiteBackendJobInfo } from 'ts/types'; import { backendClient } from 'ts/utils/backend_client'; import { utils } from 'ts/utils/utils'; const labelStyle = { fontFamily: 'Roboto Mono', fontSize: 18 }; const HEADER_TEXT = 'Open Positions'; const TABLE_ROW_MIN_HEIGHT = 100; export interface OpenPositionsProps { hash: string; screenWidth: ScreenWidths; } export interface OpenPositionsState { jobInfos?: WebsiteBackendJobInfo[]; error?: Error; } export class OpenPositions extends React.Component { private _isUnmounted: boolean; constructor(props: OpenPositionsProps) { super(props); this._isUnmounted = false; this.state = { jobInfos: undefined, error: undefined, }; } public componentWillMount(): void { // tslint:disable-next-line:no-floating-promises this._fetchJobInfosAsync(); } public componentWillUnmount(): void { this._isUnmounted = true; } public render(): React.ReactNode { const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.jobInfos); return (
{isReadyToRender ? this._renderBody() : this._renderLoading()}
); } private _renderBody(): React.ReactNode { const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; return isSmallScreen ? this._renderList() : this._renderTable(); } private _renderLoading(): React.ReactNode { return ( // TODO: consolidate this loading component with the one in portal and RelayerIndex // TODO: possibly refactor into a generic loading container with spinner and retry UI
{_.isUndefined(this.state.error) ? ( ) : ( )}
); } private _renderList(): React.ReactNode { return (
{_.map(this.state.jobInfos, jobInfo => ( ))}
); } private _renderTable(): React.ReactNode { return (
Position Department Office {_.map(this.state.jobInfos, jobInfo => { return this._renderJobInfoTableRow(jobInfo); })}
); } private _renderJobInfoTableRow(jobInfo: WebsiteBackendJobInfo): React.ReactNode { return ( {jobInfo.title} {jobInfo.department} {jobInfo.office} ); } private async _fetchJobInfosAsync(): Promise { try { if (!this._isUnmounted) { this.setState({ jobInfos: undefined, error: undefined, }); } const jobInfos = await backendClient.getJobInfosAsync(); if (!this._isUnmounted) { this.setState({ jobInfos, }); } } catch (error) { if (!this._isUnmounted) { this.setState({ error, }); } } } private _onCellClick(rowNumber: number): void { if (_.isUndefined(this.state.jobInfos)) { return; } const jobInfo = this.state.jobInfos[rowNumber]; this._openJobInfoUrl(jobInfo); } private _openJobInfoUrl(jobInfo: WebsiteBackendJobInfo): void { const url = jobInfo.url; utils.openUrl(url); } } export interface JobInfoListItemProps { title?: string; description?: string; onClick?: (event: React.MouseEvent) => void; } const PlainJobInfoListItem: React.StatelessComponent = ({ title, description, onClick }) => (
{title + ' ›'} {description}
); export const JobInfoListItem = styled(PlainJobInfoListItem)` cursor: pointer; &:hover { opacity: 0.5; } `;