Skip to content

Mission planner #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ node_modules
.idea
dist
coverage
.tmp
32 changes: 26 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## DSP app
# dsp-fronted

## Requirements
* node v6 (https://nodejs.org)
Expand All @@ -11,7 +11,7 @@


## Configuration
Configuration files are located under `config` dir.
Configuration files are located under `config` dir.
See Guild https://github.com/lorenwest/node-config/wiki/Configuration-Files

|Name|Description|
Expand All @@ -32,7 +32,27 @@ See Guild https://github.com/lorenwest/node-config/wiki/Configuration-Files
|`dev`|Start app in the dev mode.|
|`lint`|Lint all `.js` files.|
|`lint:fix`|Lint and fix all `.js` files. [Read more on this](http://eslint.org/docs/user-guide/command-line-interface.html#fix).|


## Video
http://take.ms/WZkTO
|`test`|Run tests using [mocha-webpack](https://github.com/webpack/mocha-loader) for all `*.spec.(js|jsx)` files in the `src` dir.|

## Google Map
In this project module [react-google-maps](https://github.com/tomchentw/react-google-maps) is used to work with google maps. So it can be used for any new functionality.

# Challenges

## [30055900](https://www.topcoder.com/challenge-details/30055900)
## DONE
- All modules were rewritten almost from the scratch because the previous code was very buggy, hard to support and too far from the redux way which is used in the new project. This was the biggest job. Current code is much more robust and is 99% stateless.
- For most important parts detailed unit tests are written.
- Redrawing mission on the map was optimised, no unnecessary redrawing.
- Readme file was cleaned and updated with information about tests and module used to implement google maps for future developers.

## ADDITIONALLY
- These small things from `kbowerma` was added:
- - I know this was not in the challenge req but another thing that would be nice is if the label for PARAM4 changed to “Heading” only if NAV_WAYPOINT is selected. and PARAMA1 label changed to “hold time” only if NAV_WAYPOINT is selected.
- - IT should be, but home and take off should be pinned together with the first click, but then should be able to be dragged or updated with text separately
- All modules integrated with current project styles.
- Test environment was set up. It uses `Mocha`, `Chai` and `Enzyme`. Also, it supports `jsx`, `css-modules` and `webpack resolve aliases`. Even though it's implicitly the scope of the challenge, it was a tangible part.

## NOTES
- As there is no Authorization implemented in the project. In the API I've hardcoded automatic registering and authorization of a dumb user to make requests to the server.
- A lot of files in the repository had the `crlf` line endings. Though `eslint` and `.editorconfig` prescribe using `lf` line endings. So all files were converted to `lf` line endings to pass the linting process and follow configuration.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import styles from './<%= pascalEntityName %>.scss';

export const <%= pascalEntityName %> = () => (
<div styleName="<%= dashesEntityName %>">
<%= pascalEntityName %>
</div>
);

<%= pascalEntityName %>.propTypes = {
foo: PropTypes.string.isRequired,
// foo: PropTypes.string.isRequired,
};

export default CSSModules(<%= pascalEntityName %>, styles);
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.<%= dashesEntityName %> {
background-color: transparent;

:global {

}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, {PropTypes} from 'react';
import CSSModules from 'react-css-modules';
import styles from './<%= pascalEntityName %>View.scss';

export const <%= pascalEntityName %>View = () => (
<div styleName="<%= dashesEntityName %>-view">
<%= pascalEntityName %>View
</div>
);

<%= pascalEntityName %>View.propTypes = {
// foo: PropTypes.string.isRequired,
};

export default CSSModules(<%= pascalEntityName %>View, styles);
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.<%= camelEntityName %>View {
.<%= dashesEntityName %>-view {
background-color: transparent;

:global {

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { asyncConnect } from 'redux-connect';
import {actions} from '../modules/<%= pascalEntityName %>';
import { actions } from '../modules/<%= pascalEntityName %>';

import <%= pascalEntityName %>View from '../components/<%= pascalEntityName %>View';

Expand Down
1 change: 1 addition & 0 deletions blueprints/route/files/src/routes/__name__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default (store) => ({
require.ensure([], (require) => {
const <%= pascalEntityName %> = require('./containers/<%= pascalEntityName %>Container').default;
const reducer = require('./modules/<%= pascalEntityName %>').default;

injectReducer(store, { key: '<%= camelEntityName %>', reducer });
cb(null, <%= pascalEntityName %>);
}, '<%= pascalEntityName %>');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const SAMPLE = '<%= pascalEntityName %>/SAMPLE';


export const sample2 = () => async (dispatch, getState) => {

getState(); // to pass eslint from the begining
};

export const actions = {
Expand All @@ -23,5 +23,8 @@ export const actions = {
// Reducer
// ------------------------------------
export default handleActions({
[SAMPLE]: (state, {payload}) => state,
[SAMPLE]: (state, {payload}) => {
payload; // to pass eslint from the begining
return state;
},
}, {});
2 changes: 2 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
module.exports = {
PORT: process.env.PORT || 3000,
GOOGLE_API_KEY: process.env.GOOGLE_API_KEY || 'AIzaSyCrL-O319wNJK8kk8J_JAYsWgu6yo5YsDI',
//API_BASE_PATH: process.env.API_BASE_PATH || 'http://localhost:3000',
API_BASE_PATH: process.env.API_BASE_PATH || 'https://kb-dsp-server-dev.herokuapp.com',
};
17 changes: 15 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"start": "cross-env NODE_ENV=production node server",
"build": "cross-env NODE_ENV=production webpack --bail --progress --build --tc",
"lint": "eslint --ext jsx --ext js .",
"lint:fix": "npm run lint -- --fix"
"lint:fix": "npm run lint -- --fix",
"test": "mocha-webpack --require setup-test.js --webpack-config webpack.config-test.js \"src/**/*.spec.(jsx|js)\""
},
"author": "",
"license": "MIT",
Expand All @@ -34,6 +35,7 @@
"express": "^4.14.0",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.9.0",
"flexboxgrid": "^6.3.1",
"history": "^2.0.0",
"html-webpack-plugin": "^2.22.0",
"imports-loader": "^0.6.5",
Expand All @@ -50,8 +52,11 @@
"react-css-modules": "^3.7.10",
"react-date-picker": "^5.3.28",
"react-dom": "^15.3.2",
"react-flexbox-grid": "^0.10.2",
"react-google-maps": "^6.0.1",
"react-modal": "^1.5.2",
"react-redux": "^4.0.0",
"react-redux-toastr": "^4.2.2",
"react-router": "^2.8.1",
"react-router-redux": "^4.0.0",
"react-select": "^1.0.0-rc.2",
Expand All @@ -73,15 +78,23 @@
"yargs": "^4.0.0"
},
"devDependencies": {
"chai": "^3.5.0",
"css-modules-require-hook": "^4.0.5",
"enzyme": "^2.6.0",
"eslint": "^3.7.1",
"eslint-config-airbnb": "^12.0.0",
"eslint-plugin-babel": "^3.3.0",
"eslint-plugin-import": "^1.16.0",
"eslint-plugin-jsx-a11y": "^2.2.2",
"eslint-plugin-react": "^6.3.0",
"jsdom": "^9.8.3",
"mocha": "^3.2.0",
"mocha-webpack": "^0.7.0",
"nodemon": "^1.8.1",
"react-addons-test-utils": "^15.4.1",
"webpack-dev-middleware": "^1.8.3",
"webpack-hot-middleware": "^2.13.0"
"webpack-hot-middleware": "^2.13.0",
"webpack-node-externals": "^1.5.4"
},
"engines": {
"node": "6.7.0"
Expand Down
31 changes: 31 additions & 0 deletions setup-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const hook = require('css-modules-require-hook');
const sass = require('node-sass');

/*
take care of css modules
*/
hook({
extensions: ['.scss', '.css'],
generateScopedName: '[local]___[hash:base64:5]',
preprocessCss: (data, file) => sass.renderSync({ file }).css,
});

/*
init jsdom to simulate browser
*/
const jsdom = require('jsdom').jsdom;

const exposedProperties = ['window', 'navigator', 'document'];

global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property);
global[property] = document.defaultView[property];
}
});

global.navigator = {
userAgent: 'node.js',
};
6 changes: 4 additions & 2 deletions src/components/Button/Button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ import _ from 'lodash';
import cn from 'classnames';
import styles from './Button.scss';

export const Button = ({children, color, ...rest}) => (
<button {..._.omit(rest, 'styles')} styleName={cn('button', `color-${color}`)}>
export const Button = ({children, color, size, ...rest}) => (
<button {..._.omit(rest, 'styles')} styleName={cn('button', `color-${color}`, `size-${size}`)}>
{children}
</button>
);

Button.propTypes = {
children: PropTypes.string.isRequired,
color: PropTypes.string.isRequired,
size: PropTypes.string,
};

Button.defaultProps = {
type: 'button',
size: 'normal',
};

export default CSSModules(Button, styles, {allowMultiple: true});
12 changes: 10 additions & 2 deletions src/components/Button/Button.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.button {
padding: 13px 10px;
min-width: 115px;
color: white;
border: none;
Expand All @@ -12,4 +11,13 @@

.color-blue {
background: #315b95;
}
}

.size-normal {
padding: 13px 10px;
}

.size-medium {
height: 38px;
padding: 0 10px;
}
2 changes: 1 addition & 1 deletion src/components/TextField/TextField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import styles from './TextField.scss';

export const TextField = (props) => (
<div styleName="text-field">
<input {..._.pick(props, 'type', 'value', 'onChange')} />
<input {..._.pick(props, 'type', 'value', 'onChange', 'placeholder')} />
</div>
);

Expand Down
13 changes: 12 additions & 1 deletion src/containers/AppContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@ import React, { PropTypes } from 'react';
import { ReduxAsyncConnect } from 'redux-connect';
import { Router } from 'react-router';
import { Provider } from 'react-redux';
import ReduxToastr from 'react-redux-toastr';

const AppContainer = ({ history, routes, routerKey, store }) => (
<Provider store={store}>
<Router history={history} render={(props) => <ReduxAsyncConnect {...props} />} key={routerKey}>{routes}</Router>
<div>
<Router history={history} render={(props) => <ReduxAsyncConnect {...props} />} key={routerKey}>{routes}</Router>
<ReduxToastr
timeOut={3000}
newestOnTop={false}
preventDuplicates
position="top-right"
transitionIn="fadeIn"
transitionOut="fadeOut"
/>
</div>
</Provider>
);

Expand Down
2 changes: 2 additions & 0 deletions src/routes/Dashboard/modules/Dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { handleActions } from 'redux-actions';


export const sendRequest = (values) => new Promise((resolve) => {
/* eslint-disable no-alert */
alert(JSON.stringify(values, null, 2));
/* eslint-enable no-alert */
resolve();
});

Expand Down
48 changes: 48 additions & 0 deletions src/routes/MissionList/components/MissionListView.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { PropTypes } from 'react';
import CSSModules from 'react-css-modules';
import { Link } from 'react-router';
import styles from './MissionListView.scss';

export const MissionListView = ({ missions, deleteMission }) => (
<div styleName="mission-list-view">
<div styleName="wrap">
<div styleName="header">
<h1 styleName="title">Mission List</h1>
<Link to="/mission-planner" styleName="create-btn">Create New Mission</Link>
</div>
<div styleName="panel">
{missions.length ? (
<table styleName="my-request-table">
<thead styleName="thead">
<tr>
<th styleName="th">Mission Name</th>
<th styleName="th" />
<th styleName="th" />
<th styleName="th" />
</tr>
</thead>
<tbody>
{missions.map((mission) => (
<tr styleName="tr" key={mission.id}>
<td styleName="td">{mission.missionName}</td>
<td styleName="td"><Link to={`/mission-planner/${mission.id}`}>Edit</Link></td>
<td styleName="td"><a href={mission.downloadLink} target="_blank" rel="noopener noreferrer">Download</a></td>
<td styleName="td"><a href="#" onClick={(event) => { event.preventDefault(); deleteMission(mission.id); }}>Delete</a></td>
</tr>
))}
</tbody>
</table>
) : (
<span>No missions found.</span>
)}
</div>
</div>
</div>
);

MissionListView.propTypes = {
missions: PropTypes.array.isRequired,
deleteMission: PropTypes.func.isRequired,
};

export default CSSModules(MissionListView, styles);
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy