Add promo fetch and associated logic
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { Button, Col, Panel, Row, Well } from 'react-bootstrap';
|
import { Button, Input, Col, Panel, Row, Well } from 'react-bootstrap';
|
||||||
import { contain } from 'thundercats-react';
|
import { contain } from 'thundercats-react';
|
||||||
|
|
||||||
const paypalIds = {
|
const paypalIds = {
|
||||||
@ -12,14 +12,26 @@ const paypalIds = {
|
|||||||
export default contain(
|
export default contain(
|
||||||
{
|
{
|
||||||
store: 'JobsStore',
|
store: 'JobsStore',
|
||||||
actions: 'JobActions',
|
actions: 'jobActions',
|
||||||
map({
|
map({
|
||||||
job: { id, isHighlighted } = {},
|
job: { id, isHighlighted } = {},
|
||||||
buttonId = paypalIds.regular,
|
buttonId = paypalIds.regular,
|
||||||
price = 200,
|
price = 200,
|
||||||
discountAmount = 0
|
discountAmount = 0,
|
||||||
|
promoCode = '',
|
||||||
|
promoApplied = false,
|
||||||
|
promoName
|
||||||
}) {
|
}) {
|
||||||
return { id, isHighlighted, buttonId, price, discountAmount };
|
return {
|
||||||
|
id,
|
||||||
|
isHighlighted,
|
||||||
|
buttonId,
|
||||||
|
price,
|
||||||
|
discountAmount,
|
||||||
|
promoName,
|
||||||
|
promoCode,
|
||||||
|
promoApplied
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
React.createClass({
|
React.createClass({
|
||||||
@ -30,7 +42,11 @@ export default contain(
|
|||||||
isHighlighted: PropTypes.bool,
|
isHighlighted: PropTypes.bool,
|
||||||
buttonId: PropTypes.string,
|
buttonId: PropTypes.string,
|
||||||
price: PropTypes.number,
|
price: PropTypes.number,
|
||||||
discountAmount: PropTypes.number
|
discountAmount: PropTypes.number,
|
||||||
|
promoName: PropTypes.string,
|
||||||
|
promoCode: PropTypes.string,
|
||||||
|
promoApplied: PropTypes.bool,
|
||||||
|
jobActions: PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
renderDiscount(discountAmount) {
|
renderDiscount(discountAmount) {
|
||||||
@ -42,7 +58,7 @@ export default contain(
|
|||||||
<Col
|
<Col
|
||||||
md={ 3 }
|
md={ 3 }
|
||||||
mdOffset={ 3 }>
|
mdOffset={ 3 }>
|
||||||
<h4>Discount</h4>
|
<h4>Promo Discount</h4>
|
||||||
</Col>
|
</Col>
|
||||||
<Col
|
<Col
|
||||||
md={ 3 }>
|
md={ 3 }>
|
||||||
@ -71,8 +87,75 @@ export default contain(
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
renderPromo() {
|
||||||
|
const {
|
||||||
|
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 }
|
||||||
|
bsSize='large'
|
||||||
|
onClick={ () => {
|
||||||
|
jobActions.applyCode({
|
||||||
|
code: promoCode,
|
||||||
|
type: isHighlighted ? 'isHighlighted' : null
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
Find Promo
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { id, isHighlighted, buttonId, price, discountAmount } = this.props;
|
const {
|
||||||
|
id,
|
||||||
|
isHighlighted,
|
||||||
|
buttonId,
|
||||||
|
price,
|
||||||
|
discountAmount
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Row>
|
<Row>
|
||||||
@ -124,6 +207,7 @@ export default contain(
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Well>
|
</Well>
|
||||||
|
{ this.renderPromo() }
|
||||||
<div className='spacer' />
|
<div className='spacer' />
|
||||||
<Row>
|
<Row>
|
||||||
<Col
|
<Col
|
||||||
|
@ -2,6 +2,7 @@ import { Actions } from 'thundercats';
|
|||||||
import store from 'store';
|
import store from 'store';
|
||||||
import debugFactory from 'debug';
|
import debugFactory from 'debug';
|
||||||
import { jsonp$ } from '../../../../utils/jsonp$';
|
import { jsonp$ } from '../../../../utils/jsonp$';
|
||||||
|
import { postJSON$ } from '../../../../utils/ajax-stream';
|
||||||
|
|
||||||
const debug = debugFactory('freecc:jobs:actions');
|
const debug = debugFactory('freecc:jobs:actions');
|
||||||
const assign = Object.assign;
|
const assign = Object.assign;
|
||||||
@ -65,6 +66,26 @@ export default Actions({
|
|||||||
getFollowers: null,
|
getFollowers: null,
|
||||||
setFollowersCount(numOfFollowers) {
|
setFollowersCount(numOfFollowers) {
|
||||||
return { numOfFollowers };
|
return { numOfFollowers };
|
||||||
|
},
|
||||||
|
setPromoCode({ target: { value = '' }} = {}) {
|
||||||
|
return { promoCode: value.replace(/[^\d\w\s]/, '') };
|
||||||
|
},
|
||||||
|
applyCode: null,
|
||||||
|
applyPromo({
|
||||||
|
fullPrice: price,
|
||||||
|
buttonId,
|
||||||
|
discountAmount,
|
||||||
|
code: promoCode,
|
||||||
|
name: promoName
|
||||||
|
} = {}) {
|
||||||
|
return {
|
||||||
|
price,
|
||||||
|
buttonId,
|
||||||
|
discountAmount,
|
||||||
|
promoCode,
|
||||||
|
promoApplied: true,
|
||||||
|
promoName
|
||||||
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.refs({ displayName: 'JobActions' })
|
.refs({ displayName: 'JobActions' })
|
||||||
@ -139,5 +160,23 @@ export default Actions({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jobActions.applyCode.subscribe(({ code = '', type = null}) => {
|
||||||
|
const body = { code: code.replace(/[^\d\w\s]/, '') };
|
||||||
|
if (type) {
|
||||||
|
body.type = type;
|
||||||
|
}
|
||||||
|
postJSON$('/api/promos/getButton', body)
|
||||||
|
.pluck('response')
|
||||||
|
.subscribe(
|
||||||
|
({ promo }) => {
|
||||||
|
if (promo && promo.buttonId) {
|
||||||
|
jobActions.applyPromo(promo);
|
||||||
|
}
|
||||||
|
jobActions.setError(new Error('no promo found'));
|
||||||
|
},
|
||||||
|
jobActions.setError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return jobActions;
|
return jobActions;
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,9 @@ export default Store({
|
|||||||
closeModal,
|
closeModal,
|
||||||
handleForm,
|
handleForm,
|
||||||
setForm,
|
setForm,
|
||||||
setFollowersCount
|
setFollowersCount,
|
||||||
|
setPromoCode,
|
||||||
|
applyPromo
|
||||||
} = cat.getActions('JobActions');
|
} = cat.getActions('JobActions');
|
||||||
const register = createRegistrar(jobsStore);
|
const register = createRegistrar(jobsStore);
|
||||||
register(setter(setJobs));
|
register(setter(setJobs));
|
||||||
@ -28,6 +30,8 @@ export default Store({
|
|||||||
register(setter(openModal));
|
register(setter(openModal));
|
||||||
register(setter(closeModal));
|
register(setter(closeModal));
|
||||||
register(setter(setForm));
|
register(setter(setForm));
|
||||||
|
register(setter(setPromoCode));
|
||||||
|
register(setter(applyPromo));
|
||||||
register(setter(setFollowersCount));
|
register(setter(setFollowersCount));
|
||||||
|
|
||||||
register(transformer(findJob));
|
register(transformer(findJob));
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { isAlphanumeric } from 'validator';
|
import { isAlphanumeric } from 'validator';
|
||||||
|
|
||||||
export default function promo(Promo) {
|
export default function promo(Promo) {
|
||||||
Promo.getButton = function getButton(code, type = null) {
|
Promo.getButton = function getButton(code, type = 'isNot') {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isAlphanumeric(code) &&
|
!isAlphanumeric(code) &&
|
||||||
type &&
|
type &&
|
||||||
@ -15,8 +14,7 @@ export default function promo(Promo) {
|
|||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
where: {
|
where: {
|
||||||
code,
|
and: [{ code }, { type }]
|
||||||
type
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,6 +255,7 @@ export function postJSON$(url, body) {
|
|||||||
url,
|
url,
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
responseType: 'json',
|
||||||
headers: { 'Content-Type': 'application/json' }
|
headers: { 'Content-Type': 'application/json' }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -277,10 +278,7 @@ export function get$(url) {
|
|||||||
* @returns {Observable} The observable sequence which contains the parsed JSON
|
* @returns {Observable} The observable sequence which contains the parsed JSON
|
||||||
*/
|
*/
|
||||||
export function getJSON$(url) {
|
export function getJSON$(url) {
|
||||||
if (!root.JSON && typeof root.JSON.parse !== 'function') {
|
return ajax$({ url: url, responseType: 'json' }).map(function(x) {
|
||||||
throw new TypeError('JSON is not supported in your runtime.');
|
|
||||||
}
|
|
||||||
return ajax$({url: url, responseType: 'json'}).map(function(x) {
|
|
||||||
return x.response;
|
return x.response;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user