From dfed1538c7cf331c5e5622e1e15b6c8a75e9f53c Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Thu, 10 Sep 2015 16:26:41 -0700 Subject: [PATCH] render individual job on request and window transition --- common/app/routes/Jobs/components/Jobs.jsx | 24 ++++++++++-- common/app/routes/Jobs/components/List.jsx | 45 ++++++++++++---------- common/app/routes/Jobs/components/Show.jsx | 17 ++++---- common/app/routes/Jobs/flux/Actions.js | 42 +++++++++++++++++++- common/app/routes/Jobs/flux/Store.js | 13 +++++-- server/services/job.js | 6 ++- 6 files changed, 109 insertions(+), 38 deletions(-) diff --git a/common/app/routes/Jobs/components/Jobs.jsx b/common/app/routes/Jobs/components/Jobs.jsx index 4b37571eb2..a6bc6a9a9f 100644 --- a/common/app/routes/Jobs/components/Jobs.jsx +++ b/common/app/routes/Jobs/components/Jobs.jsx @@ -1,23 +1,39 @@ import React, { cloneElement, PropTypes } from 'react'; import { contain } from 'thundercats-react'; +import { Navigation } from 'react-router'; import { Button, Jumbotron, Row } from 'react-bootstrap'; import ListJobs from './List.jsx'; export default contain( { store: 'jobsStore', - fetchAction: 'jobActions.getJobs' + fetchAction: 'jobActions.getJobs', + actions: 'jobActions' }, React.createClass({ displayName: 'Jobs', + propTypes: { children: PropTypes.element, + jobActions: PropTypes.object, jobs: PropTypes.array }, + mixins: [Navigation], - renderList(jobs) { + handleJobClick(id) { + const { jobActions } = this.props; + if (!id) { + return null; + } + jobActions.findJob(id); + this.transitionTo(`/jobs/${id}`); + }, + + renderList(handleJobClick, jobs) { return ( - + ); }, @@ -53,7 +69,7 @@ export default contain( { this.renderChild(children, jobs) || - this.renderList(jobs) } + this.renderList(this.handleJobClick, jobs) } ); diff --git a/common/app/routes/Jobs/components/List.jsx b/common/app/routes/Jobs/components/List.jsx index a01c70b1d4..ec8325a98b 100644 --- a/common/app/routes/Jobs/components/List.jsx +++ b/common/app/routes/Jobs/components/List.jsx @@ -1,5 +1,4 @@ import React, { PropTypes } from 'react'; -import { Link } from 'react-router'; import { PanelGroup, Thumbnail, Panel, Well } from 'react-bootstrap'; import moment from 'moment'; @@ -7,15 +6,17 @@ export default React.createClass({ displayName: 'ListJobs', propTypes: { + handleClick: PropTypes.func, jobs: PropTypes.array }, - renderJobs(jobs =[]) { + renderJobs(handleClick, jobs =[]) { const thumbnailStyle = { backgroundColor: 'white', maxHeight: '100px', maxWidth: '100px' }; + return jobs.map(( { id, @@ -47,33 +48,35 @@ export default React.createClass({ eventKey={ index } header={ header } key={ id }> - - - - - Position: { position } - Location: { city }, { state } -
- Contact: { email || phone || 'N/A' } -
- Posted On: { moment(postedOn).format('MMMM Do, YYYY') } -
-

{ description }

-
- + + + + Position: { position } + Location: { city }, { state } +
+ Contact: { email || phone || 'N/A' } +
+ Posted On: { moment(postedOn).format('MMMM Do, YYYY') } +
+

handleClick(id) }>{ description }

+
); }); }, render() { - const { jobs } = this.props; + const { + handleClick, + jobs + } = this.props; + return ( - { this.renderJobs(jobs) } + { this.renderJobs(handleClick, jobs) } ); } diff --git a/common/app/routes/Jobs/components/Show.jsx b/common/app/routes/Jobs/components/Show.jsx index 99f473d14f..0baedb82b3 100644 --- a/common/app/routes/Jobs/components/Show.jsx +++ b/common/app/routes/Jobs/components/Show.jsx @@ -14,15 +14,18 @@ export default contain( store: 'jobsStore', fetchAction: 'jobActions.getJob', map({ currentJob }) { + return { job: currentJob }; + }, + getPayload({ params: { id }, job = {} }) { return { - job: currentJob + id, + isPrimed: job.id === id }; }, - getPayload({ params }) { - return { id: params.id }; - }, - shouldContainerFetch({ currentJob = {} }, { currentJob: nextJob = {}}) { - return currentJob.id !== nextJob.id; + // using es6 destructuring + shouldContainerFetch({ job = {} }, { params: { id } } + ) { + return job.id !== id; } }, React.createClass({ @@ -46,7 +49,7 @@ export default contain( }, render() { - const { job } = this.props; + const { job = {} } = this.props; const { logo, position, diff --git a/common/app/routes/Jobs/flux/Actions.js b/common/app/routes/Jobs/flux/Actions.js index f74c8092a4..4df2ae42c6 100644 --- a/common/app/routes/Jobs/flux/Actions.js +++ b/common/app/routes/Jobs/flux/Actions.js @@ -5,6 +5,29 @@ const debug = debugFactory('freecc:jobs:actions'); export default Actions({ setJobs: null, + // findJob assumes that the job is already in the list of jobs + findJob(id) { + return oldState => { + const { currentJob = {}, jobs = [] } = oldState; + // currentJob already set + // do nothing + if (currentJob.id === id) { + return null; + } + const foundJob = jobs.reduce((newJob, job) => { + if (job.id === id) { + return job; + } + return newJob; + }, null); + + // if no job found this will be null which is a op noop + return foundJob ? + Object.assign({}, oldState, { currentJob: foundJob }) : + null; + }; + }, + setError: null, getJob: null, getJobs(params) { return { params }; @@ -13,13 +36,28 @@ export default Actions({ .refs({ displayName: 'JobActions' }) .init(({ instance: jobActions, args: [services] }) => { jobActions.getJobs.subscribe(() => { - services.read('job', null, null, (err, jobs) => { + services.read('jobs', null, null, (err, jobs) => { if (err) { debug('job services experienced an issue', err); - jobActions.setJobs({ jobs: [] }); + return jobActions.setError({ err }); } jobActions.setJobs({ jobs }); }); }); + + jobActions.getJob.subscribe(({ id, isPrimed }) => { + // job is already set, do nothing. + if (isPrimed) { + debug('job is primed'); + return; + } + services.read('jobs', { id }, null, (err, job) => { + if (err) { + debug('job services experienced an issue', err); + return jobActions.setError({ err }); + } + jobActions.setJobs({ currentJob: job }); + }); + }); return jobActions; }); diff --git a/common/app/routes/Jobs/flux/Store.js b/common/app/routes/Jobs/flux/Store.js index 803bc7b0bd..2fdfa50207 100644 --- a/common/app/routes/Jobs/flux/Store.js +++ b/common/app/routes/Jobs/flux/Store.js @@ -1,10 +1,17 @@ import { Store } from 'thundercats'; -const { setter } = Store; +const { + createRegistrar, + setter, + transformer +} = Store; export default Store() .refs({ displayName: 'JobsStore' }) .init(({ instance: jobsStore, args: [cat] }) => { - let jobActions = cat.getActions('JobActions'); - jobsStore.register(setter(jobActions.setJobs)); + const { setJobs, findJob, setError } = cat.getActions('JobActions'); + const register = createRegistrar(jobsStore); + register(setter(setJobs)); + register(transformer(findJob)); + register(setter(setError)); }); diff --git a/server/services/job.js b/server/services/job.js index 8c38a3661a..fe54d0064c 100644 --- a/server/services/job.js +++ b/server/services/job.js @@ -2,8 +2,12 @@ export default function getJobServices(app) { const { Job } = app.models; return { - name: 'job', + name: 'jobs', read: (req, resource, params, config, cb) => { + const id = params ? params.id : null; + if (id) { + return Job.findById(id, cb); + } Job.find({}, (err, jobs) => { cb(err, jobs); });