Implement large screen open positions

This commit is contained in:
Brandon Millman
2018-06-11 12:38:25 -07:00
parent bc36c0faed
commit 679d60cd5a
9 changed files with 187 additions and 104 deletions

View File

@@ -6,6 +6,7 @@ import { GridList } from 'material-ui/GridList';
import * as React from 'react';
import { RelayerGridTile } from 'ts/components/relayer_index/relayer_grid_tile';
import { Retry } from 'ts/components/ui/retry';
import { colors } from 'ts/style/colors';
import { ScreenWidths, WebsiteBackendRelayerInfo } from 'ts/types';
import { backendClient } from 'ts/utils/backend_client';
@@ -63,7 +64,8 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
const isReadyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
if (!isReadyToRender) {
return (
// TODO: consolidate this loading component with the one in portal
// TODO: consolidate this loading component with the one in portal and OpenPositions
// TODO: possibly refactor into a generic loading container with spinner and retry UI
<div className="center">
{_.isUndefined(this.state.error) ? (
<CircularProgress size={40} thickness={5} />
@@ -124,31 +126,3 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
}
}
}
interface RetryProps {
onRetry: () => void;
}
const Retry = (props: RetryProps) => (
<div className="clearfix center" style={{ color: colors.black }}>
<div className="mx-auto inline-block align-middle" style={{ lineHeight: '44px', textAlign: 'center' }}>
<div className="h2" style={{ fontFamily: 'Roboto Mono' }}>
Something went wrong.
</div>
<div className="py3">
<FlatButton
label={'reload'}
backgroundColor={colors.black}
labelStyle={{
fontSize: 18,
fontFamily: 'Roboto Mono',
fontWeight: 'lighter',
color: colors.white,
textTransform: 'lowercase',
}}
style={{ width: 280, height: 62, borderRadius: 5 }}
onClick={props.onRetry}
/>
</div>
</div>
</div>
);

View File

@@ -0,0 +1,33 @@
import FlatButton from 'material-ui/FlatButton';
import { GridList } from 'material-ui/GridList';
import * as React from 'react';
import { colors } from 'ts/style/colors';
export interface RetryProps {
onRetry: () => void;
}
export const Retry = (props: RetryProps) => (
<div className="clearfix center" style={{ color: colors.black }}>
<div className="mx-auto inline-block align-middle" style={{ lineHeight: '44px', textAlign: 'center' }}>
<div className="h2" style={{ fontFamily: 'Roboto Mono' }}>
Something went wrong.
</div>
<div className="py3">
<FlatButton
label={'reload'}
backgroundColor={colors.black}
labelStyle={{
fontSize: 18,
fontFamily: 'Roboto Mono',
fontWeight: 'lighter',
color: colors.white,
textTransform: 'lowercase',
}}
style={{ width: 280, height: 62, borderRadius: 5 }}
onClick={props.onRetry}
/>
</div>
</div>
</div>
);

View File

@@ -41,7 +41,7 @@ export interface BenefitsProps {
}
export const Benefits = (props: BenefitsProps) => (
<div style={{ backgroundColor: colors.jobsPageGrey }}>
<div style={{ backgroundColor: colors.jobsPageBackground }}>
{props.screenWidth === ScreenWidths.Sm ? <SmallLayout /> : <LargeLayout />}
</div>
);

View File

@@ -35,7 +35,7 @@ export const Mission = (props: MissionProps) => {
</div>
);
return (
<div className="container lg-py4 md-py4" style={{ backgroundColor: colors.jobsPageGrey, color: colors.black }}>
<div className="container lg-py4 md-py4" style={{ backgroundColor: colors.jobsPageBackground, color: colors.black }}>
<div className="mx-auto clearfix sm-py4">
{isSmallScreen ? (
<div>

View File

@@ -1,80 +1,136 @@
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';
const POSITIONS = [
{
name: 'Community Director',
department: 'Marketing',
office: 'Remote / San Francisco',
},
{
name: 'Data Scientist / Data Engineer',
department: 'Engineering',
office: 'Remote / San Francisco',
},
{
name: 'Executive Assitant / Office Manager',
department: 'Operations',
office: 'Remote / San Francisco',
},
{
name: 'Research Fellow - Economics / Governance',
department: 'Engineering',
office: 'Remote / San Francisco',
},
{
name: 'Software Engineer - Blockchain',
department: 'Engineer',
office: 'Remote / San Francisco',
},
{
name: 'Software Engineer - Full-stack',
department: 'Marketing',
office: 'Remote / San Francisco',
},
];
import { Retry } from 'ts/components/ui/retry';
import { colors } from 'ts/style/colors';
import { WebsiteBackendJobInfo } from 'ts/types';
import { backendClient } from 'ts/utils/backend_client';
const labelStyle = { fontFamily: 'Roboto Mono', fontSize: 18 };
export interface OpenPositionsProps {
hash: string;
}
export interface OpenPositionsState {
jobInfos?: WebsiteBackendJobInfo[];
error?: Error;
}
export const OpenPositions = (props: OpenPositionsProps) => {
const labelStyle = { fontFamily: 'Roboto Mono', fontSize: 18 };
return (
<div id={props.hash} className="py4" style={{ paddingLeft: 200, paddingRight: 200 }}>
<Table selectable={false}>
<TableHeader displaySelectAll={false} adjustForCheckbox={false}>
<TableRow>
<TableHeaderColumn colSpan={6} style={labelStyle}>
Position
</TableHeaderColumn>
<TableHeaderColumn colSpan={3} style={labelStyle}>
Department
</TableHeaderColumn>
<TableHeaderColumn colSpan={3} style={labelStyle}>
Office
</TableHeaderColumn>
</TableRow>
</TableHeader>
<TableBody displayRowCheckbox={false} showRowHover={true}>
{_.map(POSITIONS, position => {
return (
<TableRow hoverable={true} displayBorder={false} style={{ height: 100, border: 2 }}>
<TableRowColumn colSpan={6} style={labelStyle}>
{position.name}
</TableRowColumn>
<TableRowColumn colSpan={3} style={labelStyle}>
{position.department}
</TableRowColumn>
<TableRowColumn colSpan={3} style={labelStyle}>
{position.office}
</TableRowColumn>
export class OpenPositions extends React.Component<OpenPositionsProps, OpenPositionsState> {
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);
if (!isReadyToRender) {
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
<div className="center">
{_.isUndefined(this.state.error) ? (
<CircularProgress size={40} thickness={5} />
) : (
<Retry onRetry={this._fetchJobInfosAsync.bind(this)} />
)}
</div>
);
} else {
return (
<div id={this.props.hash} className="mx-auto max-width-4">
<Title />
<Table selectable={false} onCellClick={this._onCellClick.bind(this)}>
<TableHeader displaySelectAll={false} adjustForCheckbox={false}>
<TableRow>
<TableHeaderColumn colSpan={5} style={labelStyle}>
Position
</TableHeaderColumn>
<TableHeaderColumn colSpan={3} style={labelStyle}>
Department
</TableHeaderColumn>
<TableHeaderColumn colSpan={4} style={labelStyle}>
Office
</TableHeaderColumn>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
};
</TableHeader>
<TableBody displayRowCheckbox={false} showRowHover={true}>
{_.map(this.state.jobInfos, jobInfo => {
return this._renderJobInfo(jobInfo);
})}
</TableBody>
</Table>
</div>
);
}
}
private _renderJobInfo(jobInfo: WebsiteBackendJobInfo): React.ReactNode {
return (
<TableRow key={jobInfo.id} hoverable={true} displayBorder={false} style={{ height: 100, border: 2 }}>
<TableRowColumn colSpan={5} style={labelStyle}>
{jobInfo.title}
</TableRowColumn>
<TableRowColumn colSpan={3} style={labelStyle}>
{jobInfo.department}
</TableRowColumn>
<TableRowColumn colSpan={4} style={labelStyle}>
{jobInfo.office}
</TableRowColumn>
</TableRow>
);
}
private async _fetchJobInfosAsync(): Promise<void> {
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 url = this.state.jobInfos[rowNumber].url;
window.open(url, '_blank');
}
}
const Title = () => (
<div
className="h2 lg-py4 md-py4 sm-py3"
style={{
paddingLeft: 90,
fontFamily: 'Roboto Mono',
}}
>
{'Open Positions'}
</div>
);

View File

@@ -42,7 +42,7 @@ export interface TeamsProps {
export const Teams = (props: TeamsProps) => (props.screenWidth === ScreenWidths.Sm ? <SmallLayout /> : <LargeLayout />);
const LargeLayout = () => (
<div className="mx-auto max-width-4 clearfix">
<div className="mx-auto max-width-4 clearfix pb4">
<div className="col lg-col-6 md-col-6 col-12">
<BulletedItemList headerText={HEADER_TEXT} bulletedItemInfos={ITEMS_COLUMN1} />
</div>

View File

@@ -11,7 +11,8 @@ const appColors = {
wrapEtherConfirmationButton: sharedColors.mediumBlue,
drawerMenuBackground: '#4a4a4a',
menuItemDefaultSelectedBackground: '#424242',
jobsPageGrey: '#fafafa',
jobsPageBackground: '#fafafa',
jobsPageOpenPositionRow: '#f5f5f5',
};
export const colors = {

View File

@@ -536,4 +536,12 @@ export interface WebsiteBackendTokenInfo {
export interface WebsiteBackendGasInfo {
average: number;
}
export interface WebsiteBackendJobInfo {
id: number;
title: string;
department: string;
office: string;
url: string;
}
// tslint:disable:max-file-line-count

View File

@@ -1,10 +1,17 @@
import * as _ from 'lodash';
import { ArticlesBySection, WebsiteBackendGasInfo, WebsiteBackendPriceInfo, WebsiteBackendRelayerInfo } from 'ts/types';
import {
ArticlesBySection,
WebsiteBackendGasInfo,
WebsiteBackendJobInfo,
WebsiteBackendPriceInfo,
WebsiteBackendRelayerInfo,
} from 'ts/types';
import { fetchUtils } from 'ts/utils/fetch_utils';
import { utils } from 'ts/utils/utils';
const ETH_GAS_STATION_ENDPOINT = '/eth_gas_station';
const JOBS_ENDPOINT = '/jobs';
const PRICES_ENDPOINT = '/prices';
const RELAYERS_ENDPOINT = '/relayers';
const WIKI_ENDPOINT = '/wiki';
@@ -15,6 +22,10 @@ export const backendClient = {
const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), ETH_GAS_STATION_ENDPOINT);
return result;
},
async getJobInfosAsync(): Promise<WebsiteBackendJobInfo[]> {
const result = await fetchUtils.requestAsync(utils.getBackendBaseUrl(), JOBS_ENDPOINT);
return result;
},
async getPriceInfoAsync(tokenSymbols: string[]): Promise<WebsiteBackendPriceInfo> {
if (_.isEmpty(tokenSymbols)) {
return {};