Initial Job move to redux
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from 'redux';
|
||||||
|
import { reducer as formReducer } from 'redux-form';
|
||||||
|
|
||||||
import { reducer as app } from './redux';
|
import { reducer as app } from './redux';
|
||||||
import { reducer as hikesApp } from './routes/Hikes/redux';
|
import { reducer as hikesApp } from './routes/Hikes/redux';
|
||||||
@ -7,6 +8,7 @@ export default function createReducer(sideReducers = {}) {
|
|||||||
return combineReducers({
|
return combineReducers({
|
||||||
...sideReducers,
|
...sideReducers,
|
||||||
app,
|
app,
|
||||||
hikesApp
|
hikesApp,
|
||||||
|
form: formReducer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,277 +0,0 @@
|
|||||||
import React, { PropTypes } from 'react';
|
|
||||||
import { Button, Input, Col, Row, Well } from 'react-bootstrap';
|
|
||||||
import { contain } from 'thundercats-react';
|
|
||||||
|
|
||||||
// real paypal buttons
|
|
||||||
// will take your money
|
|
||||||
const paypalIds = {
|
|
||||||
regular: 'Q8Z82ZLAX3Q8N',
|
|
||||||
highlighted: 'VC8QPSKCYMZLN'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default contain(
|
|
||||||
{
|
|
||||||
store: 'appStore',
|
|
||||||
actions: [
|
|
||||||
'jobActions',
|
|
||||||
'appActions'
|
|
||||||
],
|
|
||||||
map({ jobsApp: {
|
|
||||||
currentJob: { id, isHighlighted } = {},
|
|
||||||
buttonId = isHighlighted ?
|
|
||||||
paypalIds.highlighted :
|
|
||||||
paypalIds.regular,
|
|
||||||
price = 1000,
|
|
||||||
discountAmount = 0,
|
|
||||||
promoCode = '',
|
|
||||||
promoApplied = false,
|
|
||||||
promoName = ''
|
|
||||||
}}) {
|
|
||||||
return {
|
|
||||||
id,
|
|
||||||
isHighlighted,
|
|
||||||
buttonId,
|
|
||||||
price,
|
|
||||||
discountAmount,
|
|
||||||
promoName,
|
|
||||||
promoCode,
|
|
||||||
promoApplied
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
React.createClass({
|
|
||||||
displayName: 'GoToPayPal',
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
appActions: PropTypes.object,
|
|
||||||
id: PropTypes.string,
|
|
||||||
isHighlighted: PropTypes.bool,
|
|
||||||
buttonId: PropTypes.string,
|
|
||||||
price: PropTypes.number,
|
|
||||||
discountAmount: PropTypes.number,
|
|
||||||
promoName: PropTypes.string,
|
|
||||||
promoCode: PropTypes.string,
|
|
||||||
promoApplied: PropTypes.bool,
|
|
||||||
jobActions: PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const { jobActions } = this.props;
|
|
||||||
jobActions.clearPromo();
|
|
||||||
},
|
|
||||||
|
|
||||||
goToJobBoard() {
|
|
||||||
const { appActions } = this.props;
|
|
||||||
setTimeout(() => appActions.goTo('/jobs'), 0);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderDiscount(discountAmount) {
|
|
||||||
if (!discountAmount) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 3 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
<h4>Promo Discount</h4>
|
|
||||||
</Col>
|
|
||||||
<Col
|
|
||||||
md={ 3 }>
|
|
||||||
<h4>-{ discountAmount }</h4>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderHighlightPrice(isHighlighted) {
|
|
||||||
if (!isHighlighted) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 3 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
<h4>Highlighting</h4>
|
|
||||||
</Col>
|
|
||||||
<Col
|
|
||||||
md={ 3 }>
|
|
||||||
<h4>+ 250</h4>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderPromo() {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
promoApplied,
|
|
||||||
promoCode,
|
|
||||||
promoName,
|
|
||||||
isHighlighted,
|
|
||||||
jobActions
|
|
||||||
} = this.props;
|
|
||||||
if (promoApplied) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className='spacer' />
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 3 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
{ promoName } applied
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className='spacer' />
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 3 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
Have a promo code?
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 3 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
<Input
|
|
||||||
onChange={ jobActions.setPromoCode }
|
|
||||||
type='text'
|
|
||||||
value={ promoCode } />
|
|
||||||
</Col>
|
|
||||||
<Col
|
|
||||||
md={ 3 }>
|
|
||||||
<Button
|
|
||||||
block={ true }
|
|
||||||
onClick={ () => {
|
|
||||||
jobActions.applyCode({
|
|
||||||
id,
|
|
||||||
code: promoCode,
|
|
||||||
type: isHighlighted ? 'isHighlighted' : null
|
|
||||||
});
|
|
||||||
}}>
|
|
||||||
Apply Promo Code
|
|
||||||
</Button>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
isHighlighted,
|
|
||||||
buttonId,
|
|
||||||
price,
|
|
||||||
discountAmount
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 10 }
|
|
||||||
mdOffset={ 1 }
|
|
||||||
sm={ 8 }
|
|
||||||
smOffset={ 2 }
|
|
||||||
xs={ 12 }>
|
|
||||||
<div>
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 6 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
<h2 className='text-center'>
|
|
||||||
One more step
|
|
||||||
</h2>
|
|
||||||
<div className='spacer' />
|
|
||||||
You're Awesome! just one more step to go.
|
|
||||||
Clicking on the link below will redirect to paypal.
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<div className='spacer' />
|
|
||||||
<Well>
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 3 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
<h4>Job Posting</h4>
|
|
||||||
</Col>
|
|
||||||
<Col
|
|
||||||
md={ 6 }>
|
|
||||||
<h4>+ { price }</h4>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
{ this.renderHighlightPrice(isHighlighted) }
|
|
||||||
{ this.renderDiscount(discountAmount) }
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 3 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
<h4>Total</h4>
|
|
||||||
</Col>
|
|
||||||
<Col
|
|
||||||
md={ 6 }>
|
|
||||||
<h4>${
|
|
||||||
price - discountAmount + (isHighlighted ? 250 : 0)
|
|
||||||
}</h4>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Well>
|
|
||||||
{ this.renderPromo() }
|
|
||||||
<div className='spacer' />
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 6 }
|
|
||||||
mdOffset={ 3 }>
|
|
||||||
<form
|
|
||||||
action='https://www.paypal.com/cgi-bin/webscr'
|
|
||||||
method='post'
|
|
||||||
onClick={ this.goToJobBoard }
|
|
||||||
target='_blank'>
|
|
||||||
<input
|
|
||||||
name='cmd'
|
|
||||||
type='hidden'
|
|
||||||
value='_s-xclick' />
|
|
||||||
<input
|
|
||||||
name='hosted_button_id'
|
|
||||||
type='hidden'
|
|
||||||
value={ buttonId } />
|
|
||||||
<input
|
|
||||||
name='custom'
|
|
||||||
type='hidden'
|
|
||||||
value={ '' + id } />
|
|
||||||
<Button
|
|
||||||
block={ true }
|
|
||||||
bsSize='large'
|
|
||||||
className='signup-btn'
|
|
||||||
type='submit'>
|
|
||||||
<i className='fa fa-paypal' />
|
|
||||||
Continue to PayPal
|
|
||||||
</Button>
|
|
||||||
<div className='spacer' />
|
|
||||||
<img
|
|
||||||
alt='An array of credit cards'
|
|
||||||
border='0'
|
|
||||||
src='http://i.imgur.com/Q2SdSZG.png'
|
|
||||||
style={{
|
|
||||||
width: '100%'
|
|
||||||
}} />
|
|
||||||
</form>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<div className='spacer' />
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
@ -2,8 +2,12 @@ import React from 'react';
|
|||||||
import { LinkContainer } from 'react-router-bootstrap';
|
import { LinkContainer } from 'react-router-bootstrap';
|
||||||
import { Button, Row, Col } from 'react-bootstrap';
|
import { Button, Row, Col } from 'react-bootstrap';
|
||||||
|
|
||||||
export default React.createClass({
|
export default class extends React.Component {
|
||||||
displayName: 'NoJobFound',
|
static displayName = 'NoJobFound';
|
||||||
|
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@ -28,4 +32,4 @@ export default React.createClass({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
284
common/app/routes/Jobs/components/JobTotal.jsx
Normal file
284
common/app/routes/Jobs/components/JobTotal.jsx
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
import React, { PropTypes } from 'react';
|
||||||
|
import { Button, Input, Col, Row, Well } from 'react-bootstrap';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PureComponent from 'react-pure-render/component';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
// real paypal buttons
|
||||||
|
// will take your money
|
||||||
|
const paypalIds = {
|
||||||
|
regular: 'Q8Z82ZLAX3Q8N',
|
||||||
|
highlighted: 'VC8QPSKCYMZLN'
|
||||||
|
};
|
||||||
|
|
||||||
|
const bindableActions = {
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = createSelector(
|
||||||
|
state => state.jobsApp.currentJob,
|
||||||
|
state => state.jobsApp,
|
||||||
|
(
|
||||||
|
{ id, isHighlighted } = {},
|
||||||
|
{
|
||||||
|
buttonId,
|
||||||
|
price = 1000,
|
||||||
|
discountAmount = 0,
|
||||||
|
promoCode = '',
|
||||||
|
promoApplied = false,
|
||||||
|
promoName = ''
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
if (!buttonId) {
|
||||||
|
buttonId = isHighlighted ?
|
||||||
|
paypalIds.highlighted :
|
||||||
|
paypalIds.regular;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
isHighlighted,
|
||||||
|
price,
|
||||||
|
discountAmount,
|
||||||
|
promoName,
|
||||||
|
promoCode,
|
||||||
|
promoApplied
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export class JobTotal extends PureComponent {
|
||||||
|
static displayName = 'JobTotal';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
id: PropTypes.string,
|
||||||
|
isHighlighted: PropTypes.bool,
|
||||||
|
buttonId: PropTypes.string,
|
||||||
|
price: PropTypes.number,
|
||||||
|
discountAmount: PropTypes.number,
|
||||||
|
promoName: PropTypes.string,
|
||||||
|
promoCode: PropTypes.string,
|
||||||
|
promoApplied: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { jobActions } = this.props;
|
||||||
|
jobActions.clearPromo();
|
||||||
|
}
|
||||||
|
|
||||||
|
goToJobBoard() {
|
||||||
|
const { appActions } = this.props;
|
||||||
|
setTimeout(() => appActions.goTo('/jobs'), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDiscount(discountAmount) {
|
||||||
|
if (!discountAmount) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 3 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
<h4>Promo Discount</h4>
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
md={ 3 }>
|
||||||
|
<h4>-{ discountAmount }</h4>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHighlightPrice(isHighlighted) {
|
||||||
|
if (!isHighlighted) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 3 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
<h4>Highlighting</h4>
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
md={ 3 }>
|
||||||
|
<h4>+ 250</h4>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPromo() {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
promoApplied,
|
||||||
|
promoCode,
|
||||||
|
promoName,
|
||||||
|
isHighlighted,
|
||||||
|
jobActions
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (promoApplied) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className='spacer' />
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 3 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
{ promoName } applied
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className='spacer' />
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 3 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
Have a promo code?
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 3 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
<Input
|
||||||
|
onChange={ jobActions.setPromoCode }
|
||||||
|
type='text'
|
||||||
|
value={ promoCode } />
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
md={ 3 }>
|
||||||
|
<Button
|
||||||
|
block={ true }
|
||||||
|
onClick={ () => {
|
||||||
|
jobActions.applyCode({
|
||||||
|
id,
|
||||||
|
code: promoCode,
|
||||||
|
type: isHighlighted ? 'isHighlighted' : null
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
Apply Promo Code
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
isHighlighted,
|
||||||
|
buttonId,
|
||||||
|
price,
|
||||||
|
discountAmount
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 10 }
|
||||||
|
mdOffset={ 1 }
|
||||||
|
sm={ 8 }
|
||||||
|
smOffset={ 2 }
|
||||||
|
xs={ 12 }>
|
||||||
|
<div>
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 6 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
<h2 className='text-center'>
|
||||||
|
One more step
|
||||||
|
</h2>
|
||||||
|
<div className='spacer' />
|
||||||
|
You're Awesome! just one more step to go.
|
||||||
|
Clicking on the link below will redirect to paypal.
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<div className='spacer' />
|
||||||
|
<Well>
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 3 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
<h4>Job Posting</h4>
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
md={ 6 }>
|
||||||
|
<h4>+ { price }</h4>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{ this.renderHighlightPrice(isHighlighted) }
|
||||||
|
{ this.renderDiscount(discountAmount) }
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 3 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
<h4>Total</h4>
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
md={ 6 }>
|
||||||
|
<h4>${
|
||||||
|
price - discountAmount + (isHighlighted ? 250 : 0)
|
||||||
|
}</h4>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Well>
|
||||||
|
{ this.renderPromo() }
|
||||||
|
<div className='spacer' />
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 6 }
|
||||||
|
mdOffset={ 3 }>
|
||||||
|
<form
|
||||||
|
action='https://www.paypal.com/cgi-bin/webscr'
|
||||||
|
method='post'
|
||||||
|
onClick={ this.goToJobBoard }
|
||||||
|
target='_blank'>
|
||||||
|
<input
|
||||||
|
name='cmd'
|
||||||
|
type='hidden'
|
||||||
|
value='_s-xclick' />
|
||||||
|
<input
|
||||||
|
name='hosted_button_id'
|
||||||
|
type='hidden'
|
||||||
|
value={ buttonId } />
|
||||||
|
<input
|
||||||
|
name='custom'
|
||||||
|
type='hidden'
|
||||||
|
value={ '' + id } />
|
||||||
|
<Button
|
||||||
|
block={ true }
|
||||||
|
bsSize='large'
|
||||||
|
className='signup-btn'
|
||||||
|
type='submit'>
|
||||||
|
<i className='fa fa-paypal' />
|
||||||
|
Continue to PayPal
|
||||||
|
</Button>
|
||||||
|
<div className='spacer' />
|
||||||
|
<img
|
||||||
|
alt='An array of credit cards'
|
||||||
|
border='0'
|
||||||
|
src='http://i.imgur.com/Q2SdSZG.png'
|
||||||
|
style={{
|
||||||
|
width: '100%'
|
||||||
|
}} />
|
||||||
|
</form>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<div className='spacer' />
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, bindableActions)(JobTotal);
|
@ -1,132 +1,156 @@
|
|||||||
import React, { cloneElement, PropTypes } from 'react';
|
import React, { cloneElement, PropTypes } from 'react';
|
||||||
import { contain } from 'thundercats-react';
|
import { connect, compose } from 'redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import { push } from 'react-router-redux';
|
||||||
|
|
||||||
|
import PureComponent from 'react-pure-render/component';
|
||||||
import { Button, Row, Col } from 'react-bootstrap';
|
import { Button, Row, Col } from 'react-bootstrap';
|
||||||
|
|
||||||
|
import contain from '../../../utils/professor-x';
|
||||||
import ListJobs from './List.jsx';
|
import ListJobs from './List.jsx';
|
||||||
|
|
||||||
export default contain(
|
import {
|
||||||
{
|
findJob,
|
||||||
store: 'appStore',
|
fetchJobs
|
||||||
map({ jobsApp: { jobs, showModal }}) {
|
} from '../redux/actions';
|
||||||
return { jobs, showModal };
|
|
||||||
},
|
|
||||||
fetchAction: 'jobActions.getJobs',
|
|
||||||
isPrimed({ jobs = [] }) {
|
|
||||||
return !!jobs.length;
|
|
||||||
},
|
|
||||||
actions: [
|
|
||||||
'appActions',
|
|
||||||
'jobActions'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
React.createClass({
|
|
||||||
displayName: 'Jobs',
|
|
||||||
|
|
||||||
propTypes: {
|
const mapSateToProps = createSelector(
|
||||||
children: PropTypes.element,
|
state => state.jobsApp.jobs.entities,
|
||||||
appActions: PropTypes.object,
|
state => state.jobsApp.jobs.results,
|
||||||
jobActions: PropTypes.object,
|
state => state.jobsApp,
|
||||||
jobs: PropTypes.array,
|
(jobsMap, jobsById) => {
|
||||||
showModal: PropTypes.bool
|
return jobsById.map(id => jobsMap[id]);
|
||||||
},
|
}
|
||||||
|
);
|
||||||
|
|
||||||
handleJobClick(id) {
|
const bindableActions = {
|
||||||
const { appActions, jobActions } = this.props;
|
findJob,
|
||||||
if (!id) {
|
fetchJobs,
|
||||||
return null;
|
push
|
||||||
}
|
};
|
||||||
jobActions.findJob(id);
|
|
||||||
appActions.goTo(`/jobs/${id}`);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderList(handleJobClick, jobs) {
|
const fetchOptions = {
|
||||||
return (
|
fetchAction: 'fetchJobs',
|
||||||
<ListJobs
|
isPrimed({ jobs }) {
|
||||||
handleClick={ handleJobClick }
|
return !!jobs.results.length;
|
||||||
jobs={ jobs }/>
|
}
|
||||||
);
|
};
|
||||||
},
|
|
||||||
|
|
||||||
renderChild(child, jobs) {
|
export class Jobs extends PureComponent {
|
||||||
if (!child) {
|
static displayName = 'Jobs';
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return cloneElement(
|
|
||||||
child,
|
|
||||||
{ jobs }
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
static propTypes = {
|
||||||
const {
|
push: PropTypes.func,
|
||||||
children,
|
findJob: PropTypes.func,
|
||||||
jobs,
|
fetchJobs: PropTypes.func,
|
||||||
appActions
|
children: PropTypes.element,
|
||||||
} = this.props;
|
jobs: PropTypes.array,
|
||||||
|
showModal: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
createJobClickHandler(id) {
|
||||||
|
const { findJob, push } = this.props;
|
||||||
|
if (!id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id => {
|
||||||
|
findJob(id);
|
||||||
|
push(`/jobs/${id}`);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
renderList(handleJobClick, jobs) {
|
||||||
|
return (
|
||||||
|
<ListJobs
|
||||||
|
handleClick={ handleJobClick }
|
||||||
|
jobs={ jobs }/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderChild(child, jobs) {
|
||||||
|
if (!child) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return cloneElement(
|
||||||
|
child,
|
||||||
|
{ jobs }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
children,
|
||||||
|
jobs
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 10 }
|
||||||
|
mdOffset= { 1 }
|
||||||
|
xs={ 12 }>
|
||||||
|
<h1 className='text-center'>
|
||||||
|
Hire a JavaScript engineer who's experienced in HTML5,
|
||||||
|
Node.js, MongoDB, and Agile Development.
|
||||||
|
</h1>
|
||||||
|
<div className='spacer' />
|
||||||
|
<Row className='text-center'>
|
||||||
|
<Col
|
||||||
|
sm={ 8 }
|
||||||
|
smOffset={ 2 }
|
||||||
|
xs={ 12 }>
|
||||||
|
<Button
|
||||||
|
className='signup-btn btn-block btn-cta'
|
||||||
|
onClick={ ()=> {
|
||||||
|
push('/jobs/new');
|
||||||
|
}}>
|
||||||
|
Post a job: $1,000
|
||||||
|
</Button>
|
||||||
|
<div className='spacer' />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<div className='spacer' />
|
||||||
<Row>
|
<Row>
|
||||||
<Col
|
<Col
|
||||||
md={ 10 }
|
md={ 2 }
|
||||||
mdOffset= { 1 }
|
xs={ 4 }>
|
||||||
xs={ 12 }>
|
<img
|
||||||
<h1 className='text-center'>
|
alt={`
|
||||||
Hire a JavaScript engineer who's experienced in HTML5,
|
a photo of Michael Gai, who recently hired a software
|
||||||
Node.js, MongoDB, and Agile Development.
|
engineer through Free Code Camp
|
||||||
</h1>
|
`}
|
||||||
<div className='spacer' />
|
className='img-responsive testimonial-image-jobs img-center'
|
||||||
<Row className='text-center'>
|
src='http://i.imgur.com/tGcAA8H.jpg' />
|
||||||
<Col
|
</Col>
|
||||||
sm={ 8 }
|
<Col
|
||||||
smOffset={ 2 }
|
md={ 10 }
|
||||||
xs={ 12 }>
|
xs={ 8 }>
|
||||||
<Button
|
<blockquote>
|
||||||
className='signup-btn btn-block btn-cta'
|
<p>
|
||||||
onClick={ ()=> {
|
We hired our last developer out of Free Code Camp
|
||||||
appActions.goTo('/jobs/new');
|
and couldn't be happier. Free Code Camp is now
|
||||||
}}>
|
our go-to way to bring on pre-screened candidates
|
||||||
Post a job: $1,000
|
who are enthusiastic about learning quickly and
|
||||||
</Button>
|
becoming immediately productive in their new career.
|
||||||
<div className='spacer' />
|
</p>
|
||||||
</Col>
|
<footer>
|
||||||
</Row>
|
Michael Gai, <cite>CEO at CoNarrative</cite>
|
||||||
<div className='spacer' />
|
</footer>
|
||||||
<Row>
|
</blockquote>
|
||||||
<Col
|
</Col>
|
||||||
md={ 2 }
|
</Row>
|
||||||
xs={ 4 }>
|
<Row>
|
||||||
<img
|
|
||||||
alt={`
|
|
||||||
a photo of Michael Gai, who recently hired a software
|
|
||||||
engineer through Free Code Camp
|
|
||||||
`}
|
|
||||||
className='img-responsive testimonial-image-jobs img-center'
|
|
||||||
src='http://i.imgur.com/tGcAA8H.jpg' />
|
|
||||||
</Col>
|
|
||||||
<Col
|
|
||||||
md={ 10 }
|
|
||||||
xs={ 8 }>
|
|
||||||
<blockquote>
|
|
||||||
<p>
|
|
||||||
We hired our last developer out of Free Code Camp
|
|
||||||
and couldn't be happier. Free Code Camp is now
|
|
||||||
our go-to way to bring on pre-screened candidates
|
|
||||||
who are enthusiastic about learning quickly and
|
|
||||||
becoming immediately productive in their new career.
|
|
||||||
</p>
|
|
||||||
<footer>
|
|
||||||
Michael Gai, <cite>CEO at CoNarrative</cite>
|
|
||||||
</footer>
|
|
||||||
</blockquote>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
{ this.renderChild(children, jobs) ||
|
{ this.renderChild(children, jobs) ||
|
||||||
this.renderList(this.handleJobClick, jobs) }
|
this.renderList(this.createJobClickHandler(), jobs) }
|
||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
);
|
|
||||||
|
export default compose(
|
||||||
|
connect(mapSateToProps, bindableActions),
|
||||||
|
contain(fetchOptions)
|
||||||
|
)(Jobs);
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { ListGroup, ListGroupItem } from 'react-bootstrap';
|
import { ListGroup, ListGroupItem } from 'react-bootstrap';
|
||||||
|
import PureComponent from 'react-pure-render/component';
|
||||||
|
|
||||||
export default React.createClass({
|
export default class ListJobs extends PureComponent {
|
||||||
displayName: 'ListJobs',
|
static displayName = 'ListJobs';
|
||||||
|
|
||||||
propTypes: {
|
static propTypes = {
|
||||||
handleClick: PropTypes.func,
|
handleClick: PropTypes.func,
|
||||||
jobs: PropTypes.array
|
jobs: PropTypes.array
|
||||||
},
|
};
|
||||||
|
|
||||||
addLocation(locale) {
|
addLocation(locale) {
|
||||||
if (!locale) {
|
if (!locale) {
|
||||||
@ -19,50 +20,50 @@ export default React.createClass({
|
|||||||
{ locale }
|
{ locale }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
renderJobs(handleClick, jobs = []) {
|
renderJobs(handleClick, jobs = []) {
|
||||||
return jobs
|
return jobs
|
||||||
.filter(({ isPaid, isApproved, isFilled }) => {
|
.filter(({ isPaid, isApproved, isFilled }) => {
|
||||||
return isPaid && isApproved && !isFilled;
|
return isPaid && isApproved && !isFilled;
|
||||||
})
|
})
|
||||||
.map(({
|
.map(({
|
||||||
id,
|
id,
|
||||||
company,
|
company,
|
||||||
position,
|
position,
|
||||||
isHighlighted,
|
isHighlighted,
|
||||||
locale
|
locale
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const className = classnames({
|
const className = classnames({
|
||||||
'jobs-list': true,
|
'jobs-list': true,
|
||||||
'col-xs-12': true,
|
'col-xs-12': true,
|
||||||
'jobs-list-highlight': isHighlighted
|
'jobs-list-highlight': isHighlighted
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ListGroupItem
|
|
||||||
className={ className }
|
|
||||||
key={ id }
|
|
||||||
onClick={ () => handleClick(id) }>
|
|
||||||
<div>
|
|
||||||
<h4 className='pull-left' style={{ display: 'inline-block' }}>
|
|
||||||
<bold>{ company }</bold>
|
|
||||||
{' '}
|
|
||||||
<span className='hidden-xs hidden-sm'>
|
|
||||||
- { position }
|
|
||||||
</span>
|
|
||||||
</h4>
|
|
||||||
<h4
|
|
||||||
className='pull-right'
|
|
||||||
style={{ display: 'inline-block' }}>
|
|
||||||
{ this.addLocation(locale) }
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
</ListGroupItem>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
return (
|
||||||
|
<ListGroupItem
|
||||||
|
className={ className }
|
||||||
|
key={ id }
|
||||||
|
onClick={ () => handleClick(id) }>
|
||||||
|
<div>
|
||||||
|
<h4 className='pull-left' style={{ display: 'inline-block' }}>
|
||||||
|
<bold>{ company }</bold>
|
||||||
|
{' '}
|
||||||
|
<span className='hidden-xs hidden-sm'>
|
||||||
|
- { position }
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
|
<h4
|
||||||
|
className='pull-right'
|
||||||
|
style={{ display: 'inline-block' }}>
|
||||||
|
{ this.addLocation(locale) }
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</ListGroupItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
@ -76,4 +77,4 @@ export default React.createClass({
|
|||||||
</ListGroup>
|
</ListGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
@ -2,8 +2,8 @@ import React from 'react';
|
|||||||
import { LinkContainer } from 'react-router-bootstrap';
|
import { LinkContainer } from 'react-router-bootstrap';
|
||||||
import { Button, Col, Row } from 'react-bootstrap';
|
import { Button, Col, Row } from 'react-bootstrap';
|
||||||
|
|
||||||
export default React.createClass({
|
export default class extends React.createClass {
|
||||||
displayName: 'NewJobCompleted',
|
static displayName = 'NewJobCompleted';
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@ -36,4 +36,4 @@ export default React.createClass({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
@ -1,79 +1,84 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { Button, Row, Col } from 'react-bootstrap';
|
import { Button, Row, Col } from 'react-bootstrap';
|
||||||
import { contain } from 'thundercats-react';
|
import { connect } from 'redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import PureComponent from 'react-pure-render/component';
|
||||||
|
import { goBack, push } from 'react-router-redux';
|
||||||
|
|
||||||
import ShowJob from './ShowJob.jsx';
|
import ShowJob from './ShowJob.jsx';
|
||||||
import JobNotFound from './JobNotFound.jsx';
|
import JobNotFound from './JobNotFound.jsx';
|
||||||
|
|
||||||
export default contain(
|
import { clearSavedForm, saveJobToDb } from '../redux/actions';
|
||||||
{
|
|
||||||
store: 'appStore',
|
const mapStateToProps = createSelector(
|
||||||
actions: [
|
state => state.jobsApp.form,
|
||||||
'appActions',
|
(job = {}) => ({ job })
|
||||||
'jobActions'
|
);
|
||||||
],
|
|
||||||
map({ jobsApp: { form: job = {} } }) {
|
const bindableActions = {
|
||||||
return { job };
|
goBack,
|
||||||
|
push,
|
||||||
|
clearSavedForm,
|
||||||
|
saveJobToDb
|
||||||
|
};
|
||||||
|
|
||||||
|
export class JobPreview extends PureComponent {
|
||||||
|
static displayName = 'Preview';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
job: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { push, job } = this.props;
|
||||||
|
// redirect user in client
|
||||||
|
if (!job || !job.position || !job.description) {
|
||||||
|
push('/jobs/new');
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
React.createClass({
|
|
||||||
displayName: 'Preview',
|
|
||||||
|
|
||||||
propTypes: {
|
render() {
|
||||||
appActions: PropTypes.object,
|
const { job, goBack, clearSavedForm, saveJobToDb } = this.props;
|
||||||
job: PropTypes.object,
|
|
||||||
jobActions: PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount() {
|
if (!job || !job.position || !job.description) {
|
||||||
const { appActions, job } = this.props;
|
return <JobNotFound />;
|
||||||
// redirect user in client
|
}
|
||||||
if (!job || !job.position || !job.description) {
|
|
||||||
appActions.goTo('/jobs/new');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { appActions, job, jobActions } = this.props;
|
<div>
|
||||||
|
<ShowJob job={ job } />
|
||||||
|
<div className='spacer'></div>
|
||||||
|
<hr />
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={ 10 }
|
||||||
|
mdOffset={ 1 }
|
||||||
|
xs={ 12 }>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
block={ true }
|
||||||
|
className='signup-btn'
|
||||||
|
onClick={ () => {
|
||||||
|
clearSavedForm();
|
||||||
|
saveJobToDb({
|
||||||
|
goTo: '/jobs/new/check-out',
|
||||||
|
job
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
|
||||||
if (!job || !job.position || !job.description) {
|
Looks great! Let's Check Out
|
||||||
return <JobNotFound />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<ShowJob job={ job } />
|
|
||||||
<div className='spacer'></div>
|
|
||||||
<hr />
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={ 10 }
|
|
||||||
mdOffset={ 1 }
|
|
||||||
xs={ 12 }>
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
block={ true }
|
|
||||||
className='signup-btn'
|
|
||||||
onClick={ () => {
|
|
||||||
jobActions.clearSavedForm();
|
|
||||||
jobActions.saveJobToDb({
|
|
||||||
goTo: '/jobs/new/check-out',
|
|
||||||
job
|
|
||||||
});
|
|
||||||
}}>
|
|
||||||
|
|
||||||
Looks great! Let's Check Out
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
block={ true }
|
block={ true }
|
||||||
onClick={ () => appActions.goBack() } >
|
onClick={ goBack } >
|
||||||
Head back and make edits
|
Head back and make edits
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
);
|
|
||||||
|
export default connect(mapStateToProps, bindableActions)(JobPreview);
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { History } from 'react-router';
|
import { connect, compose } from 'redux';
|
||||||
import { contain } from 'thundercats-react';
|
import { push } from 'react-router-redux';
|
||||||
|
import PureComponent from 'react-pure-render/component';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
import contain from '../../../utils/professor-x';
|
||||||
|
import { fetchJob } from '../redux/actions';
|
||||||
|
|
||||||
import ShowJob from './ShowJob.jsx';
|
import ShowJob from './ShowJob.jsx';
|
||||||
import JobNotFound from './JobNotFound.jsx';
|
import JobNotFound from './JobNotFound.jsx';
|
||||||
@ -51,86 +56,89 @@ function generateMessage(
|
|||||||
"You've earned it, so feel free to apply.";
|
"You've earned it, so feel free to apply.";
|
||||||
}
|
}
|
||||||
|
|
||||||
export default contain(
|
const mapStateToProps = createSelector(
|
||||||
{
|
state => state.app,
|
||||||
store: 'appStore',
|
state => state.jobsApp.currentJob,
|
||||||
fetchAction: 'jobActions.getJob',
|
({ username, isFrontEndCert, isBackEndCert }, job = {}) => ({
|
||||||
map({
|
username,
|
||||||
username,
|
isFrontEndCert,
|
||||||
isFrontEndCert,
|
isBackEndCert,
|
||||||
isBackEndCert,
|
job
|
||||||
jobsApp: { currentJob }
|
|
||||||
}) {
|
|
||||||
return {
|
|
||||||
username,
|
|
||||||
job: currentJob,
|
|
||||||
isFrontEndCert,
|
|
||||||
isBackEndCert
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getPayload({ params: { id } }) {
|
|
||||||
return id;
|
|
||||||
},
|
|
||||||
isPrimed({ params: { id } = {}, job = {} }) {
|
|
||||||
return job.id === id;
|
|
||||||
},
|
|
||||||
// using es6 destructuring
|
|
||||||
shouldContainerFetch({ job = {} }, { params: { id } }
|
|
||||||
) {
|
|
||||||
return job.id !== id;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
React.createClass({
|
|
||||||
displayName: 'Show',
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
job: PropTypes.object,
|
|
||||||
isBackEndCert: PropTypes.bool,
|
|
||||||
isFrontEndCert: PropTypes.bool,
|
|
||||||
username: PropTypes.string
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [History],
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const { job } = this.props;
|
|
||||||
// redirect user in client
|
|
||||||
if (!isJobValid(job)) {
|
|
||||||
this.history.pushState(null, '/jobs');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
isBackEndCert,
|
|
||||||
isFrontEndCert,
|
|
||||||
job,
|
|
||||||
username
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if (!isJobValid(job)) {
|
|
||||||
return <JobNotFound />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSignedIn = !!username;
|
|
||||||
|
|
||||||
const showApply = shouldShowApply(
|
|
||||||
job,
|
|
||||||
{ isFrontEndCert, isBackEndCert }
|
|
||||||
);
|
|
||||||
|
|
||||||
const message = generateMessage(
|
|
||||||
job,
|
|
||||||
{ isFrontEndCert, isBackEndCert, isSignedIn }
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ShowJob
|
|
||||||
message={ message }
|
|
||||||
preview={ false }
|
|
||||||
showApply={ showApply }
|
|
||||||
{ ...this.props }/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const bindableActions = {
|
||||||
|
push,
|
||||||
|
fetchJob
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchOptions = {
|
||||||
|
fetchAction: 'fetchJob',
|
||||||
|
getActionArgs({ params: { id } }) {
|
||||||
|
return [ id ];
|
||||||
|
},
|
||||||
|
isPrimed({ params: { id } = {}, job = {} }) {
|
||||||
|
return job.id === id;
|
||||||
|
},
|
||||||
|
// using es6 destructuring
|
||||||
|
shouldRefetch({ job }, { params: { id } }) {
|
||||||
|
return job.id !== id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Show extends PureComponent {
|
||||||
|
static displayName = 'Show';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
job: PropTypes.object,
|
||||||
|
isBackEndCert: PropTypes.bool,
|
||||||
|
isFrontEndCert: PropTypes.bool,
|
||||||
|
username: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { job, push } = this.props;
|
||||||
|
// redirect user in client
|
||||||
|
if (!isJobValid(job)) {
|
||||||
|
push('/jobs');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
isBackEndCert,
|
||||||
|
isFrontEndCert,
|
||||||
|
job,
|
||||||
|
username
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (!isJobValid(job)) {
|
||||||
|
return <JobNotFound />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSignedIn = !!username;
|
||||||
|
|
||||||
|
const showApply = shouldShowApply(
|
||||||
|
job,
|
||||||
|
{ isFrontEndCert, isBackEndCert }
|
||||||
|
);
|
||||||
|
|
||||||
|
const message = generateMessage(
|
||||||
|
job,
|
||||||
|
{ isFrontEndCert, isBackEndCert, isSignedIn }
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ShowJob
|
||||||
|
message={ message }
|
||||||
|
preview={ false }
|
||||||
|
showApply={ showApply }
|
||||||
|
{ ...this.props }/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
connect(mapStateToProps, bindableActions),
|
||||||
|
contain(fetchOptions)
|
||||||
|
)(Show);
|
||||||
|
0
common/app/routes/Jobs/redux/actions.js
Normal file
0
common/app/routes/Jobs/redux/actions.js
Normal file
7
common/app/routes/Jobs/redux/fetch-jobs-saga.js
Normal file
7
common/app/routes/Jobs/redux/fetch-jobs-saga.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { fetchJobs, fetchJobsCompleted } from './types';
|
||||||
|
|
||||||
|
export default ({ services }) => ({ dispatch, getState }) => next => {
|
||||||
|
return function fetchJobsSaga(action) {
|
||||||
|
return next(action);
|
||||||
|
};
|
||||||
|
};
|
0
common/app/routes/Jobs/redux/reducer.js
Normal file
0
common/app/routes/Jobs/redux/reducer.js
Normal file
18
common/app/routes/Jobs/redux/types.js
Normal file
18
common/app/routes/Jobs/redux/types.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
const types = [
|
||||||
|
'fetchJobs',
|
||||||
|
'fetchJobsCompleted',
|
||||||
|
|
||||||
|
'findJob',
|
||||||
|
|
||||||
|
'saveJob',
|
||||||
|
'getJob',
|
||||||
|
'getJobs',
|
||||||
|
'openModal',
|
||||||
|
'closeModal',
|
||||||
|
'handleFormUpdate',
|
||||||
|
'saveForm',
|
||||||
|
'clear'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default types
|
||||||
|
.reduce((types, type) => ({ ...types, [type]: `jobs.${type}` }), {});
|
Reference in New Issue
Block a user