aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/website/ts/components/relayer_index/relayer_index.tsx32
-rw-r--r--packages/website/ts/components/ui/retry.tsx33
-rw-r--r--packages/website/ts/pages/jobs/benefits.tsx2
-rw-r--r--packages/website/ts/pages/jobs/mission.tsx2
-rw-r--r--packages/website/ts/pages/jobs/open_positions.tsx196
-rw-r--r--packages/website/ts/pages/jobs/teams.tsx2
-rw-r--r--packages/website/ts/style/colors.ts3
-rw-r--r--packages/website/ts/types.ts8
-rw-r--r--packages/website/ts/utils/backend_client.ts13
9 files changed, 187 insertions, 104 deletions
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx
index 683f7084b..69a7cada1 100644
--- a/packages/website/ts/components/relayer_index/relayer_index.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_index.tsx
@@ -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>
-);
diff --git a/packages/website/ts/components/ui/retry.tsx b/packages/website/ts/components/ui/retry.tsx
new file mode 100644
index 000000000..f18b5abac
--- /dev/null
+++ b/packages/website/ts/components/ui/retry.tsx
@@ -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>
+);
diff --git a/packages/website/ts/pages/jobs/benefits.tsx b/packages/website/ts/pages/jobs/benefits.tsx
index ce261592f..a7cc23503 100644
--- a/packages/website/ts/pages/jobs/benefits.tsx
+++ b/packages/website/ts/pages/jobs/benefits.tsx
@@ -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>
);
diff --git a/packages/website/ts/pages/jobs/mission.tsx b/packages/website/ts/pages/jobs/mission.tsx
index a3584e5f6..b4d294623 100644
--- a/packages/website/ts/pages/jobs/mission.tsx
+++ b/packages/website/ts/pages/jobs/mission.tsx
@@ -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>
diff --git a/packages/website/ts/pages/jobs/open_positions.tsx b/packages/website/ts/pages/jobs/open_positions.tsx
index f9c37d36f..5eb8e429d 100644
--- a/packages/website/ts/pages/jobs/open_positions.tsx
+++ b/packages/website/ts/pages/jobs/open_positions.tsx
@@ -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>
+);
diff --git a/packages/website/ts/pages/jobs/teams.tsx b/packages/website/ts/pages/jobs/teams.tsx
index 3d953c993..465bae7f4 100644
--- a/packages/website/ts/pages/jobs/teams.tsx
+++ b/packages/website/ts/pages/jobs/teams.tsx
@@ -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>
diff --git a/packages/website/ts/style/colors.ts b/packages/website/ts/style/colors.ts
index 002318e14..539f3e125 100644
--- a/packages/website/ts/style/colors.ts
+++ b/packages/website/ts/style/colors.ts
@@ -11,7 +11,8 @@ const appColors = {
wrapEtherConfirmationButton: sharedColors.mediumBlue,
drawerMenuBackground: '#4a4a4a',
menuItemDefaultSelectedBackground: '#424242',
- jobsPageGrey: '#fafafa',
+ jobsPageBackground: '#fafafa',
+ jobsPageOpenPositionRow: '#f5f5f5',
};
export const colors = {
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index 15444e517..24e86a901 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -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
diff --git a/packages/website/ts/utils/backend_client.ts b/packages/website/ts/utils/backend_client.ts
index 6b16aea6b..835a6ef4d 100644
--- a/packages/website/ts/utils/backend_client.ts
+++ b/packages/website/ts/utils/backend_client.ts
@@ -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 {};