Add promo fetch and associated logic

This commit is contained in:
Berkeley Martinez
2015-10-26 17:39:38 -07:00
parent b4c57e3b5f
commit 81c40ddeeb
5 changed files with 140 additions and 17 deletions

View File

@ -1,5 +1,5 @@
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';
const paypalIds = {
@ -12,14 +12,26 @@ const paypalIds = {
export default contain(
{
store: 'JobsStore',
actions: 'JobActions',
actions: 'jobActions',
map({
job: { id, isHighlighted } = {},
buttonId = paypalIds.regular,
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({
@ -30,7 +42,11 @@ export default contain(
isHighlighted: PropTypes.bool,
buttonId: PropTypes.string,
price: PropTypes.number,
discountAmount: PropTypes.number
discountAmount: PropTypes.number,
promoName: PropTypes.string,
promoCode: PropTypes.string,
promoApplied: PropTypes.bool,
jobActions: PropTypes.object
},
renderDiscount(discountAmount) {
@ -42,7 +58,7 @@ export default contain(
<Col
md={ 3 }
mdOffset={ 3 }>
<h4>Discount</h4>
<h4>Promo Discount</h4>
</Col>
<Col
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() {
const { id, isHighlighted, buttonId, price, discountAmount } = this.props;
const {
id,
isHighlighted,
buttonId,
price,
discountAmount
} = this.props;
return (
<div>
<Row>
@ -124,6 +207,7 @@ export default contain(
</Col>
</Row>
</Well>
{ this.renderPromo() }
<div className='spacer' />
<Row>
<Col

View File

@ -2,6 +2,7 @@ import { Actions } from 'thundercats';
import store from 'store';
import debugFactory from 'debug';
import { jsonp$ } from '../../../../utils/jsonp$';
import { postJSON$ } from '../../../../utils/ajax-stream';
const debug = debugFactory('freecc:jobs:actions');
const assign = Object.assign;
@ -65,6 +66,26 @@ export default Actions({
getFollowers: null,
setFollowersCount(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' })
@ -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;
});

View File

@ -20,7 +20,9 @@ export default Store({
closeModal,
handleForm,
setForm,
setFollowersCount
setFollowersCount,
setPromoCode,
applyPromo
} = cat.getActions('JobActions');
const register = createRegistrar(jobsStore);
register(setter(setJobs));
@ -28,6 +30,8 @@ export default Store({
register(setter(openModal));
register(setter(closeModal));
register(setter(setForm));
register(setter(setPromoCode));
register(setter(applyPromo));
register(setter(setFollowersCount));
register(transformer(findJob));

View File

@ -1,8 +1,7 @@
import { isAlphanumeric } from 'validator';
export default function promo(Promo) {
Promo.getButton = function getButton(code, type = null) {
Promo.getButton = function getButton(code, type = 'isNot') {
if (
!isAlphanumeric(code) &&
type &&
@ -15,8 +14,7 @@ export default function promo(Promo) {
const query = {
where: {
code,
type
and: [{ code }, { type }]
}
};

View File

@ -255,6 +255,7 @@ export function postJSON$(url, body) {
url,
body: JSON.stringify(body),
method: 'POST',
responseType: 'json',
headers: { 'Content-Type': 'application/json' }
});
}
@ -277,9 +278,6 @@ export function get$(url) {
* @returns {Observable} The observable sequence which contains the parsed JSON
*/
export function getJSON$(url) {
if (!root.JSON && typeof root.JSON.parse !== 'function') {
throw new TypeError('JSON is not supported in your runtime.');
}
return ajax$({ url: url, responseType: 'json' }).map(function(x) {
return x.response;
});