Add twitter follower button to board
This commit is contained in:
@ -959,7 +959,6 @@ code {
|
||||
z-index: 20000 !important;
|
||||
}
|
||||
|
||||
@import "jobs.less";
|
||||
|
||||
//uncomment this to see the dimensions of all elements outlined in red
|
||||
//* {
|
||||
@ -1070,3 +1069,4 @@ code {
|
||||
}
|
||||
|
||||
@import "chat.less";
|
||||
@import "jobs.less";
|
||||
|
@ -3,6 +3,7 @@ import { contain } from 'thundercats-react';
|
||||
import { Button, Panel, Row, Col } from 'react-bootstrap';
|
||||
|
||||
import ListJobs from './List.jsx';
|
||||
import TwitterBtn from './TwitterBtn.jsx';
|
||||
|
||||
export default contain(
|
||||
{
|
||||
@ -18,12 +19,18 @@ export default contain(
|
||||
|
||||
propTypes: {
|
||||
children: PropTypes.element,
|
||||
numOfFollowers: PropTypes.number,
|
||||
appActions: PropTypes.object,
|
||||
jobActions: PropTypes.object,
|
||||
jobs: PropTypes.array,
|
||||
showModal: PropTypes.bool
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
const { jobActions } = this.props;
|
||||
jobActions.getFollowers();
|
||||
},
|
||||
|
||||
handleJobClick(id) {
|
||||
const { appActions, jobActions } = this.props;
|
||||
if (!id) {
|
||||
@ -54,6 +61,7 @@ export default contain(
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
numOfFollowers,
|
||||
jobs,
|
||||
appActions
|
||||
} = this.props;
|
||||
@ -88,13 +96,7 @@ export default contain(
|
||||
Post a job: $200 for 30 days + weekly tweets
|
||||
</Button>
|
||||
<div className='button-spacer' />
|
||||
<a
|
||||
className='twitter-follow-button'
|
||||
data-show-count='false'
|
||||
data-size='large'
|
||||
href='https://twitter.com/CamperJobs'>
|
||||
Follow @CamperJobs
|
||||
</a>
|
||||
<TwitterBtn count={ numOfFollowers || 0 } />
|
||||
<div className='spacer' />
|
||||
</Col>
|
||||
</Row>
|
||||
|
33
common/app/routes/Jobs/components/TwitterBtn.jsx
Normal file
33
common/app/routes/Jobs/components/TwitterBtn.jsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React, { createClass, PropTypes } from 'react';
|
||||
import { Button } from 'react-bootstrap';
|
||||
|
||||
const followLink = 'https://twitter.com/intent/follow?' +
|
||||
'ref_src=twsrc%5Etfw&region=follow_link&screen_name=CamperJobs&' +
|
||||
'amp;tw_p=followbutton';
|
||||
|
||||
function commify(count) {
|
||||
return Number(count).toLocaleString('en');
|
||||
}
|
||||
|
||||
export default createClass({
|
||||
|
||||
displayName: 'FollowButton',
|
||||
|
||||
propTypes: {
|
||||
count: PropTypes.number
|
||||
},
|
||||
|
||||
render() {
|
||||
const { count } = this.props;
|
||||
return (
|
||||
<Button
|
||||
block={ true }
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
href={ followLink }
|
||||
target='__blank'>
|
||||
Join { commify(count) } followers who see our job postings on Twitter.
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
import { Actions } from 'thundercats';
|
||||
import store from 'store';
|
||||
import debugFactory from 'debug';
|
||||
import { jsonp$ } from '../../../../utils/jsonp$';
|
||||
|
||||
const debug = debugFactory('freecc:jobs:actions');
|
||||
const assign = Object.assign;
|
||||
@ -59,6 +60,10 @@ export default Actions({
|
||||
getSavedForm: null,
|
||||
setForm(form) {
|
||||
return { form };
|
||||
},
|
||||
getFollowers: null,
|
||||
setFollowersCount(numOfFollowers) {
|
||||
return { numOfFollowers };
|
||||
}
|
||||
})
|
||||
.refs({ displayName: 'JobActions' })
|
||||
@ -113,5 +118,20 @@ export default Actions({
|
||||
appActions.goTo(goTo);
|
||||
});
|
||||
});
|
||||
|
||||
jobActions.getFollowers.subscribe(() => {
|
||||
const url = 'https://cdn.syndication.twimg.com/widgets/followbutton/' +
|
||||
'info.json?lang=en&screen_names=CamperJobs' +
|
||||
'&callback=JSONPCallback';
|
||||
|
||||
jsonp$(url)
|
||||
.map(({ response }) => {
|
||||
return response[0]['followers_count'];
|
||||
})
|
||||
.subscribe(
|
||||
count => jobActions.setFollowersCount(count),
|
||||
err => jobActions.setError(err)
|
||||
);
|
||||
});
|
||||
return jobActions;
|
||||
});
|
||||
|
@ -19,7 +19,8 @@ export default Store({
|
||||
openModal,
|
||||
closeModal,
|
||||
handleForm,
|
||||
setForm
|
||||
setForm,
|
||||
setFollowersCount
|
||||
} = cat.getActions('JobActions');
|
||||
const register = createRegistrar(jobsStore);
|
||||
register(setter(setJobs));
|
||||
@ -27,6 +28,7 @@ export default Store({
|
||||
register(setter(openModal));
|
||||
register(setter(closeModal));
|
||||
register(setter(setForm));
|
||||
register(setter(setFollowersCount));
|
||||
|
||||
register(transformer(findJob));
|
||||
register(handleForm);
|
||||
|
77
common/utils/jsonp$.js
Normal file
77
common/utils/jsonp$.js
Normal file
@ -0,0 +1,77 @@
|
||||
import { AnonymousObservable, Disposable } from 'rx';
|
||||
|
||||
const root = typeof window !== 'undefined' ? window : {};
|
||||
const trash = 'document' in root && root.document.createElement('div');
|
||||
|
||||
function destroy(element) {
|
||||
trash.appendChild(element);
|
||||
trash.innerHTML = '';
|
||||
}
|
||||
|
||||
export function jsonp$(options) {
|
||||
let id = 0;
|
||||
if (typeof options === 'string') {
|
||||
options = { url: options };
|
||||
}
|
||||
|
||||
return new AnonymousObservable(function(o) {
|
||||
const settings = Object.assign(
|
||||
{},
|
||||
{
|
||||
jsonp: 'JSONPCallback',
|
||||
async: true,
|
||||
jsonpCallback: 'rxjsjsonpCallbackscallback_' + (id++).toString(36)
|
||||
},
|
||||
options
|
||||
);
|
||||
|
||||
let script = root.document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.async = settings.async;
|
||||
script.src = settings.url.replace(settings.jsonp, settings.jsonpCallback);
|
||||
|
||||
root[settings.jsonpCallback] = function(data) {
|
||||
root[settings.jsonpCallback].called = true;
|
||||
root[settings.jsonpCallback].data = data;
|
||||
};
|
||||
|
||||
const handler = function(e) {
|
||||
if (e.type === 'load' && !root[settings.jsonpCallback].called) {
|
||||
e = { type: 'error' };
|
||||
}
|
||||
const status = e.type === 'error' ? 400 : 200;
|
||||
const data = root[settings.jsonpCallback].data;
|
||||
|
||||
if (status === 200) {
|
||||
o.onNext({
|
||||
status: status,
|
||||
responseType: 'jsonp',
|
||||
response: data,
|
||||
originalEvent: e
|
||||
});
|
||||
|
||||
o.onCompleted();
|
||||
} else {
|
||||
o.onError({
|
||||
type: 'error',
|
||||
status: status,
|
||||
originalEvent: e
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
script.onload = script.onreadystatechanged = script.onerror = handler;
|
||||
|
||||
const head = root.document.getElementsByTagName('head')[0] ||
|
||||
root.document.documentElement;
|
||||
|
||||
head.insertBefore(script, head.firstChild);
|
||||
|
||||
return Disposable.create(() => {
|
||||
script.onload = script.onreadystatechanged = script.onerror = null;
|
||||
|
||||
destroy(script);
|
||||
script = null;
|
||||
});
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user