Merge pull request #3232 from FreeCodeCamp/feature/jobs
add individual pages to jobs
This commit is contained in:
2
client/es6-shims.js
Normal file
2
client/es6-shims.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
require('object.assign').shim();
|
||||||
|
require('es6-map/implement');
|
@ -1,3 +1,4 @@
|
|||||||
|
import unused from './es6-shims'; // eslint-disable-line
|
||||||
import Rx from 'rx';
|
import Rx from 'rx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Fetchr from 'fetchr';
|
import Fetchr from 'fetchr';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import Rx from 'rx';
|
import Rx from 'rx';
|
||||||
import assign from 'object.assign';
|
|
||||||
import { Router } from 'react-router';
|
import { Router } from 'react-router';
|
||||||
import App from './App.jsx';
|
import App from './App.jsx';
|
||||||
import AppCat from './Cat';
|
import AppCat from './Cat';
|
||||||
@ -8,7 +7,7 @@ import childRoutes from './routes';
|
|||||||
|
|
||||||
const router$ = Rx.Observable.fromNodeCallback(Router.run, Router);
|
const router$ = Rx.Observable.fromNodeCallback(Router.run, Router);
|
||||||
|
|
||||||
const routes = assign({ components: App }, childRoutes);
|
const routes = Object.assign({ components: App }, childRoutes);
|
||||||
|
|
||||||
export default function app$(location) {
|
export default function app$(location) {
|
||||||
return router$(routes, location)
|
return router$(routes, location)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Actions } from 'thundercats';
|
import { Actions } from 'thundercats';
|
||||||
import assign from 'object.assign';
|
|
||||||
import debugFactory from 'debug';
|
import debugFactory from 'debug';
|
||||||
|
|
||||||
const debug = debugFactory('freecc:hikes:actions');
|
const debug = debugFactory('freecc:hikes:actions');
|
||||||
@ -45,7 +44,7 @@ export default Actions({
|
|||||||
dashedName,
|
dashedName,
|
||||||
oldState.currentHike
|
oldState.currentHike
|
||||||
);
|
);
|
||||||
return assign({}, oldState, { currentHike });
|
return Object.assign({}, oldState, { currentHike });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,39 @@
|
|||||||
import React, { cloneElement, PropTypes } from 'react';
|
import React, { cloneElement, PropTypes } from 'react';
|
||||||
import { contain } from 'thundercats-react';
|
import { contain } from 'thundercats-react';
|
||||||
|
import { Navigation } from 'react-router';
|
||||||
import { Button, Jumbotron, Row } from 'react-bootstrap';
|
import { Button, Jumbotron, Row } from 'react-bootstrap';
|
||||||
import ListJobs from './List.jsx';
|
import ListJobs from './List.jsx';
|
||||||
|
|
||||||
export default contain(
|
export default contain(
|
||||||
{
|
{
|
||||||
store: 'jobsStore',
|
store: 'jobsStore',
|
||||||
fetchAction: 'jobActions.getJobs'
|
fetchAction: 'jobActions.getJobs',
|
||||||
|
actions: 'jobActions'
|
||||||
},
|
},
|
||||||
React.createClass({
|
React.createClass({
|
||||||
displayName: 'Jobs',
|
displayName: 'Jobs',
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
children: PropTypes.element,
|
children: PropTypes.element,
|
||||||
|
jobActions: PropTypes.object,
|
||||||
jobs: PropTypes.array
|
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 (
|
return (
|
||||||
<ListJobs jobs={ jobs }/>
|
<ListJobs
|
||||||
|
handleClick={ handleJobClick }
|
||||||
|
jobs={ jobs }/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -53,7 +69,7 @@ export default contain(
|
|||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
{ this.renderChild(children, jobs) ||
|
{ this.renderChild(children, jobs) ||
|
||||||
this.renderList(jobs) }
|
this.renderList(this.handleJobClick, jobs) }
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { contain } from 'thundercats-react';
|
|
||||||
import { PanelGroup, Thumbnail, Panel, Well } from 'react-bootstrap';
|
import { PanelGroup, Thumbnail, Panel, Well } from 'react-bootstrap';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
export default contain(
|
export default React.createClass({
|
||||||
{
|
|
||||||
},
|
|
||||||
React.createClass({
|
|
||||||
displayName: 'ListJobs',
|
displayName: 'ListJobs',
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
handleClick: PropTypes.func,
|
||||||
jobs: PropTypes.array
|
jobs: PropTypes.array
|
||||||
},
|
},
|
||||||
|
|
||||||
renderJobs(jobs =[]) {
|
renderJobs(handleClick, jobs =[]) {
|
||||||
const thumbnailStyle = {
|
const thumbnailStyle = {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
maxHeight: '100px',
|
maxHeight: '100px',
|
||||||
maxWidth: '100px'
|
maxWidth: '100px'
|
||||||
};
|
};
|
||||||
|
|
||||||
return jobs.map((
|
return jobs.map((
|
||||||
{
|
{
|
||||||
id,
|
id,
|
||||||
@ -52,7 +50,8 @@ export default contain(
|
|||||||
key={ id }>
|
key={ id }>
|
||||||
<Well>
|
<Well>
|
||||||
<Thumbnail
|
<Thumbnail
|
||||||
alt='200x200' src={ logo }
|
alt={ company + 'company logo' }
|
||||||
|
src={ logo }
|
||||||
style={ thumbnailStyle } />
|
style={ thumbnailStyle } />
|
||||||
<Panel>
|
<Panel>
|
||||||
Position: { position }
|
Position: { position }
|
||||||
@ -62,7 +61,7 @@ export default contain(
|
|||||||
<br />
|
<br />
|
||||||
Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
|
Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
|
||||||
</Panel>
|
</Panel>
|
||||||
<p>{ description }</p>
|
<p onClick={ () => handleClick(id) }>{ description }</p>
|
||||||
</Well>
|
</Well>
|
||||||
</Panel>
|
</Panel>
|
||||||
);
|
);
|
||||||
@ -70,12 +69,15 @@ export default contain(
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { jobs } = this.props;
|
const {
|
||||||
|
handleClick,
|
||||||
|
jobs
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelGroup>
|
<PanelGroup>
|
||||||
{ this.renderJobs(jobs) }
|
{ this.renderJobs(handleClick, jobs) }
|
||||||
</PanelGroup>
|
</PanelGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
);
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { Thumbnail, Panel, Well } from 'react-bootstrap';
|
import { contain } from 'thundercats-react';
|
||||||
|
import { Row, Thumbnail, Panel, Well } from 'react-bootstrap';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
const thumbnailStyle = {
|
const thumbnailStyle = {
|
||||||
@ -7,10 +8,31 @@ const thumbnailStyle = {
|
|||||||
maxHeight: '100px',
|
maxHeight: '100px',
|
||||||
maxWidth: '100px'
|
maxWidth: '100px'
|
||||||
};
|
};
|
||||||
export default React.createClass({
|
|
||||||
|
export default contain(
|
||||||
|
{
|
||||||
|
store: 'jobsStore',
|
||||||
|
fetchAction: 'jobActions.getJob',
|
||||||
|
map({ currentJob }) {
|
||||||
|
return { job: currentJob };
|
||||||
|
},
|
||||||
|
getPayload({ params: { id }, job = {} }) {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
isPrimed: job.id === id
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// using es6 destructuring
|
||||||
|
shouldContainerFetch({ job = {} }, { params: { id } }
|
||||||
|
) {
|
||||||
|
return job.id !== id;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
React.createClass({
|
||||||
displayName: 'ShowJob',
|
displayName: 'ShowJob',
|
||||||
propTypes: {
|
propTypes: {
|
||||||
job: PropTypes.object
|
job: PropTypes.object,
|
||||||
|
params: PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
renderHeader({ company, position }) {
|
renderHeader({ company, position }) {
|
||||||
@ -27,11 +49,12 @@ export default React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { job } = this.props;
|
const { job = {} } = this.props;
|
||||||
const {
|
const {
|
||||||
logo,
|
logo,
|
||||||
position,
|
position,
|
||||||
city,
|
city,
|
||||||
|
company,
|
||||||
state,
|
state,
|
||||||
email,
|
email,
|
||||||
phone,
|
phone,
|
||||||
@ -40,9 +63,12 @@ export default React.createClass({
|
|||||||
} = job;
|
} = job;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div>
|
||||||
|
<Row>
|
||||||
<Well>
|
<Well>
|
||||||
<Thumbnail
|
<Thumbnail
|
||||||
alt='200x200' src={ logo }
|
alt={ company + 'company logo' }
|
||||||
|
src={ logo }
|
||||||
style={ thumbnailStyle } />
|
style={ thumbnailStyle } />
|
||||||
<Panel>
|
<Panel>
|
||||||
Position: { position }
|
Position: { position }
|
||||||
@ -54,6 +80,9 @@ export default React.createClass({
|
|||||||
</Panel>
|
</Panel>
|
||||||
<p>{ description }</p>
|
<p>{ description }</p>
|
||||||
</Well>
|
</Well>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
);
|
||||||
|
@ -5,9 +5,30 @@ const debug = debugFactory('freecc:jobs:actions');
|
|||||||
|
|
||||||
export default Actions({
|
export default Actions({
|
||||||
setJobs: null,
|
setJobs: null,
|
||||||
getJob(id) {
|
// findJob assumes that the job is already in the list of jobs
|
||||||
return { id };
|
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) {
|
getJobs(params) {
|
||||||
return { params };
|
return { params };
|
||||||
}
|
}
|
||||||
@ -15,13 +36,28 @@ export default Actions({
|
|||||||
.refs({ displayName: 'JobActions' })
|
.refs({ displayName: 'JobActions' })
|
||||||
.init(({ instance: jobActions, args: [services] }) => {
|
.init(({ instance: jobActions, args: [services] }) => {
|
||||||
jobActions.getJobs.subscribe(() => {
|
jobActions.getJobs.subscribe(() => {
|
||||||
services.read('job', null, null, (err, jobs) => {
|
services.read('jobs', null, null, (err, jobs) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
debug('job services experienced an issue', err);
|
debug('job services experienced an issue', err);
|
||||||
jobActions.setJobs({ jobs: [] });
|
return jobActions.setError({ err });
|
||||||
}
|
}
|
||||||
jobActions.setJobs({ jobs });
|
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;
|
return jobActions;
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
import { Store } from 'thundercats';
|
import { Store } from 'thundercats';
|
||||||
|
|
||||||
const { setter } = Store;
|
const {
|
||||||
|
createRegistrar,
|
||||||
|
setter,
|
||||||
|
transformer
|
||||||
|
} = Store;
|
||||||
|
|
||||||
export default Store()
|
export default Store()
|
||||||
.refs({ displayName: 'JobsStore' })
|
.refs({ displayName: 'JobsStore' })
|
||||||
.init(({ instance: jobsStore, args: [cat] }) => {
|
.init(({ instance: jobsStore, args: [cat] }) => {
|
||||||
let jobActions = cat.getActions('JobActions');
|
const { setJobs, findJob, setError } = cat.getActions('JobActions');
|
||||||
jobsStore.register(setter(jobActions.setJobs));
|
const register = createRegistrar(jobsStore);
|
||||||
|
register(setter(setJobs));
|
||||||
|
register(transformer(findJob));
|
||||||
|
register(setter(setError));
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import Jobs from './components/Jobs.jsx';
|
import Jobs from './components/Jobs.jsx';
|
||||||
|
import Show from './components/Show.jsx';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* show: /jobs
|
* index: /jobs list jobs
|
||||||
* showOne: /jobs/:id
|
* show: /jobs/:id show one job
|
||||||
* edit /jobs/:id
|
* create /jobs/new create a new job
|
||||||
* delete /jobs/:id
|
|
||||||
* createOne /jobs/new
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
path: 'jobs',
|
childRoutes: [{
|
||||||
|
path: '/jobs',
|
||||||
component: Jobs
|
component: Jobs
|
||||||
|
}, {
|
||||||
|
path: 'jobs/:id',
|
||||||
|
component: Show
|
||||||
|
}]
|
||||||
};
|
};
|
||||||
|
142
gulpfile.js
142
gulpfile.js
@ -1,3 +1,6 @@
|
|||||||
|
// enable debug for gulp
|
||||||
|
process.env.DEBUG = process.env.DEBUG || 'freecc:*';
|
||||||
|
|
||||||
require('babel-core/register');
|
require('babel-core/register');
|
||||||
var Rx = require('rx'),
|
var Rx = require('rx'),
|
||||||
gulp = require('gulp'),
|
gulp = require('gulp'),
|
||||||
@ -6,6 +9,7 @@ var Rx = require('rx'),
|
|||||||
// utils
|
// utils
|
||||||
plumber = require('gulp-plumber'),
|
plumber = require('gulp-plumber'),
|
||||||
notify = require('gulp-notify'),
|
notify = require('gulp-notify'),
|
||||||
|
gutil = require('gulp-util'),
|
||||||
reduce = require('gulp-reduce-file'),
|
reduce = require('gulp-reduce-file'),
|
||||||
sortKeys = require('sort-keys'),
|
sortKeys = require('sort-keys'),
|
||||||
debug = require('debug')('freecc:gulp'),
|
debug = require('debug')('freecc:gulp'),
|
||||||
@ -25,6 +29,7 @@ var Rx = require('rx'),
|
|||||||
// rev
|
// rev
|
||||||
rev = require('gulp-rev'),
|
rev = require('gulp-rev'),
|
||||||
revReplace = require('gulp-rev-replace'),
|
revReplace = require('gulp-rev-replace'),
|
||||||
|
revDel = require('rev-del'),
|
||||||
|
|
||||||
// lint
|
// lint
|
||||||
jsonlint = require('gulp-jsonlint'),
|
jsonlint = require('gulp-jsonlint'),
|
||||||
@ -33,6 +38,7 @@ var Rx = require('rx'),
|
|||||||
|
|
||||||
Rx.config.longStackSupport = true;
|
Rx.config.longStackSupport = true;
|
||||||
|
|
||||||
|
var __DEV__ = process.env.NODE_ENV !== 'production';
|
||||||
var reloadDelay = 1000;
|
var reloadDelay = 1000;
|
||||||
var reload = sync.reload;
|
var reload = sync.reload;
|
||||||
var paths = {
|
var paths = {
|
||||||
@ -43,6 +49,7 @@ var paths = {
|
|||||||
'!public/js/bundle*',
|
'!public/js/bundle*',
|
||||||
'node_modules/',
|
'node_modules/',
|
||||||
'client/',
|
'client/',
|
||||||
|
'server/manifests/*.json',
|
||||||
'server/rev-manifest.json'
|
'server/rev-manifest.json'
|
||||||
],
|
],
|
||||||
|
|
||||||
@ -67,8 +74,7 @@ var paths = {
|
|||||||
],
|
],
|
||||||
|
|
||||||
dependents: [
|
dependents: [
|
||||||
'client/commonFramework.js',
|
'client/commonFramework.js'
|
||||||
'client/sandbox.js'
|
|
||||||
],
|
],
|
||||||
|
|
||||||
less: './client/less/main.less',
|
less: './client/less/main.less',
|
||||||
@ -107,11 +113,22 @@ function errorHandler() {
|
|||||||
this.emit('end');
|
this.emit('end');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function delRev(dest, manifestName) {
|
||||||
|
// in production do not delete old revisions
|
||||||
|
if (!__DEV__) {
|
||||||
|
return gutil.noop();
|
||||||
|
}
|
||||||
|
return revDel({
|
||||||
|
oldManifest: path.join(paths.manifest, manifestName),
|
||||||
|
dest: dest
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
gulp.task('serve', function(cb) {
|
gulp.task('serve', function(cb) {
|
||||||
var called = false;
|
var called = false;
|
||||||
nodemon({
|
nodemon({
|
||||||
script: paths.server,
|
script: paths.server,
|
||||||
ext: '.js .json',
|
ext: '.jsx .js .json',
|
||||||
ignore: paths.serverIgnore,
|
ignore: paths.serverIgnore,
|
||||||
exec: path.join(__dirname, 'node_modules/.bin/babel-node'),
|
exec: path.join(__dirname, 'node_modules/.bin/babel-node'),
|
||||||
env: {
|
env: {
|
||||||
@ -143,7 +160,7 @@ var syncDepenedents = [
|
|||||||
'js',
|
'js',
|
||||||
'less',
|
'less',
|
||||||
'dependents',
|
'dependents',
|
||||||
'pack-client',
|
'pack-watch',
|
||||||
'build-manifest'
|
'build-manifest'
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -173,6 +190,9 @@ gulp.task('lint-json', function() {
|
|||||||
gulp.task('test-challenges', ['lint-json']);
|
gulp.task('test-challenges', ['lint-json']);
|
||||||
|
|
||||||
gulp.task('pack-client', function() {
|
gulp.task('pack-client', function() {
|
||||||
|
var manifestName = 'react-manifest.json';
|
||||||
|
var dest = webpackConfig.output.path;
|
||||||
|
|
||||||
return gulp.src(webpackConfig.entry)
|
return gulp.src(webpackConfig.entry)
|
||||||
.pipe(plumber({ errorHandler: errorHandler }))
|
.pipe(plumber({ errorHandler: errorHandler }))
|
||||||
.pipe(webpack(Object.assign(
|
.pipe(webpack(Object.assign(
|
||||||
@ -180,30 +200,73 @@ gulp.task('pack-client', function() {
|
|||||||
webpackConfig,
|
webpackConfig,
|
||||||
webpackOptions
|
webpackOptions
|
||||||
)))
|
)))
|
||||||
.pipe(gulp.dest(webpackConfig.output.path))
|
.pipe(gulp.dest(dest))
|
||||||
.pipe(rev())
|
.pipe(rev())
|
||||||
// copy files to public
|
// copy files to public
|
||||||
.pipe(gulp.dest(webpackConfig.output.path))
|
.pipe(gulp.dest(dest))
|
||||||
// create and merge manifest
|
// create manifest
|
||||||
.pipe(rev.manifest('react-manifest.json'))
|
.pipe(rev.manifest(manifestName))
|
||||||
|
// delete old rev
|
||||||
|
.pipe(delRev(
|
||||||
|
dest,
|
||||||
|
manifestName
|
||||||
|
))
|
||||||
.pipe(gulp.dest(paths.manifest));
|
.pipe(gulp.dest(paths.manifest));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('pack-watch', function() {
|
var defaultStatsOptions = {
|
||||||
return gulp.src(webpackConfig.entry)
|
colors: gutil.colors.supportsColor,
|
||||||
|
hash: false,
|
||||||
|
timings: false,
|
||||||
|
chunks: false,
|
||||||
|
chunkModules: false,
|
||||||
|
modules: false,
|
||||||
|
children: true,
|
||||||
|
version: true,
|
||||||
|
cached: false,
|
||||||
|
cachedAssets: false,
|
||||||
|
reasons: false,
|
||||||
|
source: false,
|
||||||
|
errorDetails: false
|
||||||
|
};
|
||||||
|
|
||||||
|
gulp.task('pack-watch', function(cb) {
|
||||||
|
var called = false;
|
||||||
|
gulp.src(webpackConfig.entry)
|
||||||
.pipe(plumber({ errorHandler: errorHandler }))
|
.pipe(plumber({ errorHandler: errorHandler }))
|
||||||
.pipe(webpack(Object.assign(
|
.pipe(webpack(Object.assign(
|
||||||
{},
|
{},
|
||||||
webpackConfig,
|
webpackConfig,
|
||||||
webpackOptions,
|
webpackOptions,
|
||||||
{ watch: true }
|
{ watch: true }
|
||||||
)))
|
), null, function(notUsed, stats) {
|
||||||
.pipe(gulp.dest(webpackConfig.output.path))
|
if (stats) {
|
||||||
|
gutil.log(stats.toString(defaultStatsOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!called) {
|
||||||
|
debug('webpack watch completed');
|
||||||
|
called = true;
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
|
||||||
|
}))
|
||||||
|
.pipe(gulp.dest(webpackConfig.output.path));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('pack-watch-manifest', function() {
|
||||||
|
var manifestName = 'react-manifest.json';
|
||||||
|
var dest = webpackConfig.output.path;
|
||||||
|
return gulp.src(dest + '/bundle.js')
|
||||||
.pipe(rev())
|
.pipe(rev())
|
||||||
// copy files to public
|
// copy files to public
|
||||||
.pipe(gulp.dest(webpackConfig.output.path))
|
.pipe(gulp.dest(dest))
|
||||||
// create manifest
|
// create manifest
|
||||||
.pipe(rev.manifest('react-manifest.json'))
|
.pipe(rev.manifest(manifestName))
|
||||||
|
.pipe(delRev(
|
||||||
|
dest,
|
||||||
|
manifestName
|
||||||
|
))
|
||||||
.pipe(gulp.dest(paths.manifest));
|
.pipe(gulp.dest(paths.manifest));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -217,32 +280,45 @@ gulp.task('pack-node', function() {
|
|||||||
gulp.task('pack', ['pack-client', 'pack-node']);
|
gulp.task('pack', ['pack-client', 'pack-node']);
|
||||||
|
|
||||||
gulp.task('less', function() {
|
gulp.task('less', function() {
|
||||||
|
var manifestName = 'css-manifest.json';
|
||||||
|
var dest = paths.css;
|
||||||
return gulp.src(paths.less)
|
return gulp.src(paths.less)
|
||||||
.pipe(plumber({ errorHandler: errorHandler }))
|
.pipe(plumber({ errorHandler: errorHandler }))
|
||||||
// copile
|
// copile
|
||||||
.pipe(less({
|
.pipe(less({
|
||||||
paths: [ path.join(__dirname, 'less', 'includes') ]
|
paths: [ path.join(__dirname, 'less', 'includes') ]
|
||||||
}))
|
}))
|
||||||
.pipe(gulp.dest(paths.css))
|
.pipe(gulp.dest(dest))
|
||||||
// add revision
|
// add revision
|
||||||
.pipe(rev())
|
.pipe(rev())
|
||||||
// copy files to public
|
// copy files to public
|
||||||
.pipe(gulp.dest(paths.css))
|
.pipe(gulp.dest(dest))
|
||||||
// create and merge manifest
|
// create and merge manifest
|
||||||
.pipe(rev.manifest('css-manifest.json'))
|
.pipe(rev.manifest(manifestName))
|
||||||
|
.pipe(delRev(
|
||||||
|
dest,
|
||||||
|
manifestName
|
||||||
|
))
|
||||||
.pipe(gulp.dest(paths.manifest));
|
.pipe(gulp.dest(paths.manifest));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('js', function() {
|
gulp.task('js', function() {
|
||||||
|
var manifestName = 'js-manifest.json';
|
||||||
|
var dest = paths.publicJs;
|
||||||
|
|
||||||
return gulp.src(paths.js)
|
return gulp.src(paths.js)
|
||||||
.pipe(plumber({ errorHandler: errorHandler }))
|
.pipe(plumber({ errorHandler: errorHandler }))
|
||||||
.pipe(gulp.dest(paths.publicJs))
|
.pipe(gulp.dest(dest))
|
||||||
// create registry file
|
// create registry file
|
||||||
.pipe(rev())
|
.pipe(rev())
|
||||||
// copy revisioned assets to dest
|
// copy revisioned assets to dest
|
||||||
.pipe(gulp.dest(paths.publicJs))
|
.pipe(gulp.dest(dest))
|
||||||
// create manifest file
|
// create manifest file
|
||||||
.pipe(rev.manifest('js-manifest.json'))
|
.pipe(rev.manifest(manifestName))
|
||||||
|
.pipe(delRev(
|
||||||
|
dest,
|
||||||
|
manifestName
|
||||||
|
))
|
||||||
// copy manifest file to dest
|
// copy manifest file to dest
|
||||||
.pipe(gulp.dest(paths.manifest));
|
.pipe(gulp.dest(paths.manifest));
|
||||||
});
|
});
|
||||||
@ -250,6 +326,9 @@ gulp.task('js', function() {
|
|||||||
// commonFramework depend on iFrameScripts
|
// commonFramework depend on iFrameScripts
|
||||||
// sandbox depends on plugin
|
// sandbox depends on plugin
|
||||||
gulp.task('dependents', ['js'], function() {
|
gulp.task('dependents', ['js'], function() {
|
||||||
|
var manifestName = 'dependents-manifest.json';
|
||||||
|
var dest = paths.publicJs;
|
||||||
|
|
||||||
var manifest = gulp.src(
|
var manifest = gulp.src(
|
||||||
path.join(__dirname, paths.manifest, 'js-manifest.json')
|
path.join(__dirname, paths.manifest, 'js-manifest.json')
|
||||||
);
|
);
|
||||||
@ -257,9 +336,14 @@ gulp.task('dependents', ['js'], function() {
|
|||||||
return gulp.src(paths.dependents)
|
return gulp.src(paths.dependents)
|
||||||
.pipe(plumber({ errorHandler: errorHandler }))
|
.pipe(plumber({ errorHandler: errorHandler }))
|
||||||
.pipe(revReplace({ manifest: manifest }))
|
.pipe(revReplace({ manifest: manifest }))
|
||||||
|
.pipe(gulp.dest(dest))
|
||||||
.pipe(rev())
|
.pipe(rev())
|
||||||
.pipe(gulp.dest(paths.publicJs))
|
.pipe(gulp.dest(dest))
|
||||||
.pipe(rev.manifest('dependents-manifest.json'))
|
.pipe(rev.manifest(manifestName))
|
||||||
|
.pipe(delRev(
|
||||||
|
dest,
|
||||||
|
manifestName
|
||||||
|
))
|
||||||
.pipe(gulp.dest(paths.manifest));
|
.pipe(gulp.dest(paths.manifest));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -301,7 +385,9 @@ var watchDependents = [
|
|||||||
'dependents',
|
'dependents',
|
||||||
'serve',
|
'serve',
|
||||||
'sync',
|
'sync',
|
||||||
'build-manifest'
|
'build-manifest',
|
||||||
|
'pack-watch',
|
||||||
|
'pack-watch-manifest'
|
||||||
];
|
];
|
||||||
|
|
||||||
gulp.task('watch', watchDependents, function() {
|
gulp.task('watch', watchDependents, function() {
|
||||||
@ -311,7 +397,15 @@ gulp.task('watch', watchDependents, function() {
|
|||||||
gulp.watch(paths.js, ['js', 'dependents']);
|
gulp.watch(paths.js, ['js', 'dependents']);
|
||||||
gulp.watch(paths.dependents, ['dependents']);
|
gulp.watch(paths.dependents, ['dependents']);
|
||||||
gulp.watch(paths.manifest + '/*.json', ['build-manifest-watch']);
|
gulp.watch(paths.manifest + '/*.json', ['build-manifest-watch']);
|
||||||
|
gulp.watch(webpackConfig.output.path + '/bundle.js', ['pack-watch-manifest']);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('default', ['less', 'serve', 'sync', 'watch', 'pack-watch']);
|
gulp.task('default', [
|
||||||
|
'less',
|
||||||
|
'serve',
|
||||||
|
'pack-watch',
|
||||||
|
'pack-watch-manifest',
|
||||||
|
'watch',
|
||||||
|
'sync'
|
||||||
|
]);
|
||||||
|
|
||||||
|
14
package.json
14
package.json
@ -17,9 +17,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "~1.2.5",
|
"accepts": "~1.2.5",
|
||||||
"async": "~0.9.0",
|
"async": "~0.9.0",
|
||||||
"babel": "5.6.14",
|
"babel": "5.8.23",
|
||||||
"babel-core": "5.6.15",
|
"babel-core": "5.8.23",
|
||||||
"babel-eslint": "^4.0.5",
|
"babel-eslint": "4.1.1",
|
||||||
"babel-loader": "5.2.2",
|
"babel-loader": "5.2.2",
|
||||||
"bcrypt-nodejs": "~0.0.3",
|
"bcrypt-nodejs": "~0.0.3",
|
||||||
"body-parser": "^1.13.2",
|
"body-parser": "^1.13.2",
|
||||||
@ -36,6 +36,7 @@
|
|||||||
"dedent": "^0.4.0",
|
"dedent": "^0.4.0",
|
||||||
"dotenv": "~0.4.0",
|
"dotenv": "~0.4.0",
|
||||||
"errorhandler": "~1.3.0",
|
"errorhandler": "~1.3.0",
|
||||||
|
"es6-map": "^0.1.1",
|
||||||
"eslint": "^1.1.0",
|
"eslint": "^1.1.0",
|
||||||
"eslint-plugin-react": "^3.2.1",
|
"eslint-plugin-react": "^3.2.1",
|
||||||
"express": "~4.10.4",
|
"express": "~4.10.4",
|
||||||
@ -53,6 +54,7 @@
|
|||||||
"gulp-reduce-file": "0.0.1",
|
"gulp-reduce-file": "0.0.1",
|
||||||
"gulp-rev": "^6.0.1",
|
"gulp-rev": "^6.0.1",
|
||||||
"gulp-rev-replace": "^0.4.2",
|
"gulp-rev-replace": "^0.4.2",
|
||||||
|
"gulp-util": "^3.0.6",
|
||||||
"gulp-webpack": "^1.5.0",
|
"gulp-webpack": "^1.5.0",
|
||||||
"helmet": "~0.9.0",
|
"helmet": "~0.9.0",
|
||||||
"helmet-csp": "^0.2.3",
|
"helmet-csp": "^0.2.3",
|
||||||
@ -85,11 +87,12 @@
|
|||||||
"pmx": "^0.3.16",
|
"pmx": "^0.3.16",
|
||||||
"ramda": "~0.10.0",
|
"ramda": "~0.10.0",
|
||||||
"react": "^0.13.3",
|
"react": "^0.13.3",
|
||||||
"react-bootstrap": "^0.23.7",
|
"react-bootstrap": "~0.23.7",
|
||||||
"react-motion": "~0.1.0",
|
"react-motion": "~0.1.0",
|
||||||
"react-router": "https://github.com/BerkeleyTrue/react-router#freecodecamp",
|
"react-router": "https://github.com/BerkeleyTrue/react-router#freecodecamp",
|
||||||
"react-vimeo": "^0.0.3",
|
"react-vimeo": "^0.0.3",
|
||||||
"request": "~2.53.0",
|
"request": "~2.53.0",
|
||||||
|
"rev-del": "^1.0.5",
|
||||||
"rx": "^2.5.3",
|
"rx": "^2.5.3",
|
||||||
"sanitize-html": "~1.6.1",
|
"sanitize-html": "~1.6.1",
|
||||||
"sort-keys": "^1.1.1",
|
"sort-keys": "^1.1.1",
|
||||||
@ -103,15 +106,12 @@
|
|||||||
"yui": "~3.18.1"
|
"yui": "~3.18.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^3.1.7",
|
|
||||||
"blessed": "~0.0.37",
|
"blessed": "~0.0.37",
|
||||||
"bower-main-files": "~0.0.4",
|
"bower-main-files": "~0.0.4",
|
||||||
"browser-sync": "~1.8.1",
|
"browser-sync": "~1.8.1",
|
||||||
"browserify": "^10.2.4",
|
"browserify": "^10.2.4",
|
||||||
"chai": "~1.10.0",
|
"chai": "~1.10.0",
|
||||||
"envify": "^3.4.0",
|
"envify": "^3.4.0",
|
||||||
"eslint": "^0.21.2",
|
|
||||||
"eslint-plugin-react": "^2.3.0",
|
|
||||||
"gulp": "~3.8.8",
|
"gulp": "~3.8.8",
|
||||||
"gulp-eslint": "~0.9.0",
|
"gulp-eslint": "~0.9.0",
|
||||||
"gulp-inject": "~1.0.2",
|
"gulp-inject": "~1.0.2",
|
||||||
|
@ -13,7 +13,8 @@ const debug = debugFactory('freecc:react-server');
|
|||||||
const routes = [
|
const routes = [
|
||||||
'/hikes',
|
'/hikes',
|
||||||
'/hikes/*',
|
'/hikes/*',
|
||||||
'/jobs'
|
'/jobs',
|
||||||
|
'/jobs/*'
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function reactSubRouter(app) {
|
export default function reactSubRouter(app) {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import manifest from '../rev-manifest.json';
|
import manifest from '../rev-manifest.json';
|
||||||
|
|
||||||
const __DEV__ = process.env.NODE_ENV === 'development';
|
const __DEV__ = process.env.NODE_ENV === 'development';
|
||||||
|
const manifestPath = '../rev-manifest.json';
|
||||||
|
|
||||||
export default function({ globalPrepend = '' } = {}) {
|
export default function({ globalPrepend = '' } = {}) {
|
||||||
|
|
||||||
function rev(manifest, scopedPrepend, asset) {
|
function rev(manifest, scopedPrepend, asset) {
|
||||||
@ -13,7 +15,10 @@ export default function({ globalPrepend = '' } = {}) {
|
|||||||
// this means we do not need to restart server on every change to
|
// this means we do not need to restart server on every change to
|
||||||
// client code
|
// client code
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
const manifest = require('../rev-manifest.json');
|
// we first need to remove the manifest from require cache
|
||||||
|
delete require.cache[require.resolve(manifestPath)];
|
||||||
|
// and re-require
|
||||||
|
const manifest = require(manifestPath);
|
||||||
res.locals.rev = rev.bind(null, manifest);
|
res.locals.rev = rev.bind(null, manifest);
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,12 @@ export default function getJobServices(app) {
|
|||||||
const { Job } = app.models;
|
const { Job } = app.models;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'job',
|
name: 'jobs',
|
||||||
read: (req, resource, params, config, cb) => {
|
read: (req, resource, params, config, cb) => {
|
||||||
|
const id = params ? params.id : null;
|
||||||
|
if (id) {
|
||||||
|
return Job.findById(id, cb);
|
||||||
|
}
|
||||||
Job.find({}, (err, jobs) => {
|
Job.find({}, (err, jobs) => {
|
||||||
cb(err, jobs);
|
cb(err, jobs);
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user