Improve the UI #2

This commit is contained in:
Andrew Revinsky (DART)
2016-08-31 03:52:35 +03:00
parent fb97767a06
commit d9e13ff669
40 changed files with 69692 additions and 410 deletions

View File

@@ -1,3 +1,4 @@
{
"presets": ["es2015"]
"plugins": ["transform-runtime"],
"presets": ["es2015", "stage-0", "react"]
}

View File

@@ -1,4 +1,5 @@
node_modules
build
!/build
#dist
dist-intermediate

View File

@@ -1,153 +1,15 @@
# Unicorn Standard Starter Kit
# Money Transfer App - Frontend Client
This starter kit provides you with the code and conventions you need to get straight into building your React/Redux based app.
This..
## Happiness is six lines away
*Prerequisites: node.js and git*
```
git clone https://github.com/unicorn-standard/starter-kit.git your-repo-name
cd your-repo-name
cd js-frontend
npm install
npm start
npm run open # (from a different console window, otherwise open localhost:3000)
npm run build
```
Presto, you've got a ready-to-customise application!
![Unicorn Standard Starter Kit](http://unicornstandard.com/files/boilerplate.png?1)
## Why use Unicorn Standard Starter Kit?
- Your directory structure is sorted as soon as you `git clone`
- ES6 compilation and automatic-reloading development server are configured for you with [webpack](https://webpack.github.io/) and [Babel](https://babeljs.io/)
- [Redux](http://redux.js.org/) is an incredibly simple way of modelling your data, with great community support
- [React](https://www.reactjs.org/) is an incredibly simple way of rendering your views, and is maintained by Facebook
- Simple [uniloc](http://unicornstandard.com/packages/uniloc.html)-based routing is included - easy to understand, and easy to customize
- The [Pacomo](http://unicornstandard.com/packages/pacomo.html) CSS conventions eliminate bugs caused by conflicting styles
- The actors pattern allows you to easily react to changes on your store *without* forcing a re-render
- Your redux store is already configured with navigation, data and view models
- Comes with views, layouts and reducers for a simple document editor!
## Getting Started
#### Put your name on it
- Update name, desription and author in `package.json`
- Update app title in `src/index.html`
- Restart the dev server (make sure to do this after any changes to `src/index.html`)
#### Make sure your editor is happy
- Setup ES6 syntax highlighting on extensions `.js` and `.jsx` (see [babel-sublime](https://github.com/babel/babel-sublime))
#### Start building
- Add a route to `src/constants/ROUTES.js`
- Add a nav menu item for your route in `src/components/ApplicationLayout.jsx`
- Add a component for your route in `src/components`
- Add reducers and actions for your component's view model in `src/actions` and `src/reducers/view`
- Add any data models which your component reqiures in `src/reducers/data`
- Add a container to map your store's `state` and `dispatch` to component props in `src/containers`
- Configure your route in `src/Application.jsx`
- Bask in the glory of your creation
- Don't forget to commit your changes and push to Bitbucket or GitHub!
#### Show your friends
- Run `gulp dist` to output a web-ready build of your app to `dist`
## Structure
### Entry point
`main.js` is the entry point to your application. It defines your redux store, handles any actions dispatched to your redux store, handles changes to the browser's current URL, and also makes an initial route change dispatch.
Most of the above will be obvious from a quick read through `main.js` - if there is one thing which may strike you as "interesting", it'll be the block which handles actors.
### Actors
*[Read the introduction to actors](http://jamesknelson.com/join-the-dark-side-of-the-flux-responding-to-actions-with-actors/)*
Each time your store's state changes, a sequence of functions are called on the *current state* of your store. These functions are called **actors**.
There is one important exception to this rule: actors will not be called if `main.js` is currently in the midst of calling the sequence from a previous update. This allows earlier actors in a sequence to dispatch actions to the store, with later actors in the sequence receiving the *updated* state.
The code which accomplishes this is very small:
```javascript
let acting = false
store.subscribe(function() {
// Ensure that any action dispatched by actors do not result in a new
// actor run, allowing actors to dispatch with impunity.
if (!acting) {
acting = true
for (let actor of actors) {
actor(store.getState(), store.dispatch.bind(store))
}
acting = false
}
})
```
The actor is defined in `src/actors/index.js`. By default, it runs the following sequence:
- **redirector** - dispatch a navigation action if the current location should redirect to another location
- **renderer** - renders your <Application> component with React
### Model
Your model (i.e. reducers and actions) is pre-configured with three parts:
#### Navigation
The `navigation` state holds the following information:
- `location` is the object which your `ROUTES` constant's `lookup` function returns for the current URL. With the default uniloc-based `ROUTES` object, this will have a string `name` property, and an `options` object containing any route parameters.
- `transitioning` is true if a navigation `start` action has been dispatched, but the browser hasn't changed URL yet
#### Data
The `data` state can be thought of as the database for your application. If your application reads data from a remote server, it should be stored here. Any metadata should also be stored here, including the time it was fetched or its current version number.
#### View
The `view` state has a property for each of the view's in your app, holding their current state. For example, form state should be stored in the view models.
### Directories
- `src/actions` - Redux action creators
- `src/actors` - Handle changes to your store's state
- `src/components` - React components, stateless where possible
- `src/constants` - Define stateless data
- `src/containers` - Unstyled "smart" components which take your store's `state` and `dispatch`, and possibly navigation `location`, and pass them to "dumb" components
- `src/reducers` - Redux reducers
- `src/static` - Files which will be copied across to the root directory on build
- `src/styles` - Helpers for stylesheets for individual components
- `src/utils` - General code which isn't specific to your application
- `src/validators` - Functions which take an object containing user entry and return an object containing any errors
Other directories:
- `build` - Intermediate files produced by the development server. Don't touch these.
- `dist` - The output of `gulp dist`, which contains your distribution-ready app.
- `config/environments` - The build system will assign one of these to the `environment` module, depending on the current build environment.
Main application files:
- `src/Application.jsx` - Your application's top-level React component
- `src/index.html` - The single page for your single page application
- `src/main.js` - The application's entry point
- `src/main.less` - Global styles for your application
Main build files:
- `gulpfile.babel.js` - Build scripts written with [gulp](http://gulpjs.com/)
- `webpack.config.js` - [Webpack](http://webpack.github.io/) configuration
## TODO
- Watch `static` and `index.html` for changes and copy them across to `build` when appropriate
Text..

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<!--[if lt IE 7 ]> <html lang="en" class="ie6" > <![endif]-->
<!--[if IE 7 ]> <html lang="en" class="ie7" > <![endif]-->
<!--[if IE 8 ]> <html lang="en" class="ie8" > <![endif]-->
<!--[if IE 9 ]> <html lang="en" class="ie9" > <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Money Transfer App</title><meta name="description" content="ES Money Transfer App" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" /><!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css"><link href="/style.45c91aea174020d653f5.css" rel="stylesheet"></head>
<body><div id="root"></div><script src="/manifest.6ad78289b29e62452459.js"></script><script src="/vendor.baef2b8165bd82cefb69.js"></script><script src="/style.45c91aea174020d653f5.js"></script><script src="/app.0161ddc3379424602da9.js"></script><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXX-XX', 'auto');
ga('send', 'pageview');
</script><!--{"files":{"publicPath":"/","chunks":{"manifest":{"size":0,"entry":"/manifest.6ad78289b29e62452459.js","hash":"6ad78289b29e62452459","css":[]},"vendor":{"size":1670874,"entry":"/vendor.baef2b8165bd82cefb69.js","hash":"baef2b8165bd82cefb69","css":[]},"style":{"size":122,"entry":"/style.45c91aea174020d653f5.js","hash":"45c91aea174020d653f5","css":["/style.45c91aea174020d653f5.css"]},"app":{"size":410511,"entry":"/app.0161ddc3379424602da9.js","hash":"0161ddc3379424602da9","css":[]}},"js":["/manifest.6ad78289b29e62452459.js","/vendor.baef2b8165bd82cefb69.js","/style.45c91aea174020d653f5.js","/app.0161ddc3379424602da9.js"],"css":["/style.45c91aea174020d653f5.css"]},"options":{"template":"/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/node_modules/html-webpack-plugin/lib/loader.js!/Users/andrew/dev/clients/ES/code/event-sourcing-examples/js-frontend/public/index.ejs","filename":"index.html","hash":false,"inject":false,"compile":true,"favicon":false,"minify":false,"cache":true,"showErrors":true,"chunks":"all","excludeChunks":[],"title":"Money Transfer App","xhtml":false,"description":"ES Money Transfer App","appMountId":"root","googleAnalytics":{"trackingId":"UA-XXXX-XX","pageViewOnLoad":true},"mobile":true}}--></body>
</html>

View File

@@ -0,0 +1,95 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ var parentJsonpFunction = window["webpackJsonp"];
/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) {
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0, callbacks = [];
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(installedChunks[chunkId])
/******/ callbacks.push.apply(callbacks, installedChunks[chunkId]);
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ for(moduleId in moreModules) {
/******/ modules[moduleId] = moreModules[moduleId];
/******/ }
/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);
/******/ while(callbacks.length)
/******/ callbacks.shift().call(null, __webpack_require__);
/******/ if(moreModules[0]) {
/******/ installedModules[0] = 0;
/******/ return __webpack_require__(0);
/******/ }
/******/ };
/******/
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // object to store loaded and loading chunks
/******/ // "0" means "already loaded"
/******/ // Array means "loading", array contains callbacks
/******/ var installedChunks = {
/******/ 3:0
/******/ };
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = function requireEnsure(chunkId, callback) {
/******/ // "0" is the signal for "already loaded"
/******/ if(installedChunks[chunkId] === 0)
/******/ return callback.call(null, __webpack_require__);
/******/
/******/ // an array means "currently loading".
/******/ if(installedChunks[chunkId] !== undefined) {
/******/ installedChunks[chunkId].push(callback);
/******/ } else {
/******/ // start chunk loading
/******/ installedChunks[chunkId] = [callback];
/******/ var head = document.getElementsByTagName('head')[0];
/******/ var script = document.createElement('script');
/******/ script.type = 'text/javascript';
/******/ script.charset = 'utf-8';
/******/ script.async = true;
/******/
/******/ script.src = __webpack_require__.p + "" + {"0":"0161ddc3379424602da9","1":"45c91aea174020d653f5","2":"baef2b8165bd82cefb69"}[chunkId] + ".js";
/******/ head.appendChild(script);
/******/ }
/******/ };
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
/******/ })
/************************************************************************/
/******/ ([]);
//# sourceMappingURL=manifest.6ad78289b29e62452459.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap ad5528b400614ad1cde1?"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,uDAA+C,iFAAiF;AAChI;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA","file":"manifest.6ad78289b29e62452459.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n \t\twhile(callbacks.length)\n \t\t\tcallbacks.shift().call(null, __webpack_require__);\n \t\tif(moreModules[0]) {\n \t\t\tinstalledModules[0] = 0;\n \t\t\treturn __webpack_require__(0);\n \t\t}\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// \"0\" means \"already loaded\"\n \t// Array means \"loading\", array contains callbacks\n \tvar installedChunks = {\n \t\t3:0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n \t\t// \"0\" is the signal for \"already loaded\"\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn callback.call(null, __webpack_require__);\n\n \t\t// an array means \"currently loading\".\n \t\tif(installedChunks[chunkId] !== undefined) {\n \t\t\tinstalledChunks[chunkId].push(callback);\n \t\t} else {\n \t\t\t// start chunk loading\n \t\t\tinstalledChunks[chunkId] = [callback];\n \t\t\tvar head = document.getElementsByTagName('head')[0];\n \t\t\tvar script = document.createElement('script');\n \t\t\tscript.type = 'text/javascript';\n \t\t\tscript.charset = 'utf-8';\n \t\t\tscript.async = true;\n\n \t\t\tscript.src = __webpack_require__.p + \"\" + {\"0\":\"0161ddc3379424602da9\",\"1\":\"45c91aea174020d653f5\",\"2\":\"baef2b8165bd82cefb69\"}[chunkId] + \".js\";\n \t\t\thead.appendChild(script);\n \t\t}\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap ad5528b400614ad1cde1\n **/"],"sourceRoot":""}

View File

@@ -0,0 +1,5 @@
# www.robotstxt.org/
# Allow crawling of all content
User-agent: *
Disallow:

View File

@@ -0,0 +1,441 @@
@import url(http://fonts.googleapis.com/css?family=Roboto:300,400,500);
/**
* React Select
* ============
* Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
* https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
* MIT License: https://github.com/keystonejs/react-select
*/
.Select {
position: relative;
}
.Select,.Select div,.Select input,.Select span {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.Select.is-disabled > .Select-control {
background-color: #f6f6f6;
}
.Select.is-disabled .Select-arrow-zone {
cursor: default;
pointer-events: none;
}
.Select-control {
background-color: #fff;
border-color: #d9d9d9 #ccc #b3b3b3;
border-radius: 4px;
border: 1px solid #ccc;
color: #333;
cursor: default;
display: table;
height: 36px;
outline: none;
overflow: hidden;
position: relative;
width: 100%;
}
.Select-control:hover {
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
}
.is-searchable.is-open > .Select-control {
cursor: text;
}
.is-open > .Select-control {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
background: #fff;
border-color: #b3b3b3 #ccc #d9d9d9;
}
.is-open > .Select-control > .Select-arrow {
border-color: transparent transparent #999;
border-width: 0 5px 5px;
}
.is-searchable.is-focused:not(.is-open) > .Select-control {
cursor: text;
}
.is-focused:not(.is-open) > .Select-control {
border-color: #08c #0099e6 #0099e6;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px rgba(0, 136, 204, 0.5);
}
.Select-placeholder {
bottom: 0;
color: #aaa;
left: 0;
line-height: 34px;
padding-left: 10px;
padding-right: 10px;
position: absolute;
right: 0;
top: 0;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.has-value > .Select-control > .Select-placeholder {
color: #333;
}
.Select-value {
color: #aaa;
left: 0;
padding: 8px 52px 8px 10px;
position: absolute;
right: -15px;
top: 0;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.has-value > .Select-control > .Select-value {
color: #333;
}
.Select-input {
height: 34px;
padding-left: 10px;
padding-right: 10px;
vertical-align: middle;
}
.Select-input > input {
background: none transparent;
border: 0 none;
box-shadow: none;
cursor: default;
display: inline-block;
font-family: inherit;
font-size: inherit;
height: 34px;
margin: 0;
outline: none;
padding: 0;
-webkit-appearance: none;
}
.is-focused .Select-input > input {
cursor: text;
}
.Select-control:not(.is-searchable) > .Select-input {
outline: none;
}
.Select-loading-zone {
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 16px;
}
.Select-loading {
-webkit-animation: Select-animation-spin 400ms infinite linear;
-o-animation: Select-animation-spin 400ms infinite linear;
animation: Select-animation-spin 400ms infinite linear;
width: 16px;
height: 16px;
box-sizing: border-box;
border-radius: 50%;
border: 2px solid #ccc;
border-right-color: #333;
display: inline-block;
position: relative;
vertical-align: middle;
}
.Select-clear-zone {
-webkit-animation: Select-animation-fadeIn 200ms;
-o-animation: Select-animation-fadeIn 200ms;
animation: Select-animation-fadeIn 200ms;
color: #999;
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 17px;
}
.Select-clear-zone:hover {
color: #D0021B;
}
.Select-clear {
display: inline-block;
font-size: 18px;
line-height: 1;
}
.Select--multi .Select-clear-zone {
width: 17px;
}
.Select-arrow-zone {
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 25px;
padding-right: 5px;
}
.Select-arrow {
border-color: #999 transparent transparent;
border-style: solid;
border-width: 5px 5px 2.5px;
display: inline-block;
height: 0;
width: 0;
}
.is-open .Select-arrow,.Select-arrow-zone:hover > .Select-arrow {
border-top-color: #666;
}
@-webkit-keyframes Select-animation-fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes Select-animation-fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.Select-menu-outer {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
background-color: #fff;
border: 1px solid #ccc;
border-top-color: #e6e6e6;
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
box-sizing: border-box;
margin-top: -1px;
max-height: 200px;
position: absolute;
top: 100%;
width: 100%;
z-index: 1000;
-webkit-overflow-scrolling: touch;
}
.Select-menu {
max-height: 198px;
overflow-y: auto;
}
.Select-option {
box-sizing: border-box;
color: #666666;
cursor: pointer;
display: block;
padding: 8px 10px;
}
.Select-option:last-child {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
.Select-option.is-focused {
background-color: #f2f9fc;
color: #333;
}
.Select-option.is-disabled {
color: #cccccc;
cursor: not-allowed;
}
.Select-noresults,.Select-search-prompt,.Select-searching {
box-sizing: border-box;
color: #999999;
cursor: default;
display: block;
padding: 8px 10px;
}
.Select--multi .Select-input {
vertical-align: middle;
margin-left: 10px;
padding: 0;
}
.Select--multi.has-value .Select-input {
margin-left: 5px;
}
.Select-item {
background-color: #f2f9fc;
border-radius: 2px;
border: 1px solid #c9e6f2;
color: #08c;
display: inline-block;
font-size: 0.9em;
margin-left: 5px;
margin-top: 5px;
vertical-align: top;
}
.Select-item-icon,.Select-item-label {
display: inline-block;
vertical-align: middle;
}
.Select-item-label {
border-bottom-right-radius: 2px;
border-top-right-radius: 2px;
cursor: default;
padding: 2px 5px;
}
.Select-item-label .Select-item-label__a {
color: #08c;
cursor: pointer;
}
.Select-item-icon {
cursor: pointer;
border-bottom-left-radius: 2px;
border-top-left-radius: 2px;
border-right: 1px solid #c9e6f2;
padding: 1px 5px 3px;
}
.Select-item-icon:hover,.Select-item-icon:focus {
background-color: #ddeff7;
color: #0077b3;
}
.Select-item-icon:active {
background-color: #c9e6f2;
}
.Select--multi.is-disabled .Select-item {
background-color: #f2f2f2;
border: 1px solid #d9d9d9;
color: #888;
}
.Select--multi.is-disabled .Select-item-icon {
cursor: not-allowed;
border-right: 1px solid #d9d9d9;
}
.Select--multi.is-disabled .Select-item-icon:hover,.Select--multi.is-disabled .Select-item-icon:focus,.Select--multi.is-disabled .Select-item-icon:active {
background-color: #f2f2f2;
}
@keyframes Select-animation-spin {
to {
transform: rotate(1turn);
}
}
@-webkit-keyframes Select-animation-spin {
to {
-webkit-transform: rotate(1turn);
}
}
/*
* This file contains Global styles.
*
* In general, your styles should *not* be in this file, but in the individual
* component files. For details, see the Pacomo specification:
*
* https://github.com/unicorn-standard/pacomo
*/
* {
box-sizing: border-box;
margin: 0;
}
*:before,*:after {
box-sizing: border-box;
}
html,body,main {
position: relative;
height: 100%;
min-height: 100%;
font-family: Roboto;
}
body {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
input,button,select,textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
#react-app {
position: relative;
height: 100%;
min-height: 100%;
}
body {
padding-bottom: 50px;
/* height: 100%; */
/* min-height: 100%; */
height: auto;
}
.footer-navigation {
height: 1px;
}
.footer-navigation > .container {
height: 100%;
}
.footer-navigation > .container > * {
top: 50%;
transform: translateY(-50%);
}
.page-header {
padding-bottom: 9px;
margin: 0px 0 20px;
border-bottom: 1px solid #eee;
}
h1 {
margin-top: .5em;
}
/*# sourceMappingURL=style.45c91aea174020d653f5.css.map*/

View File

@@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"style.45c91aea174020d653f5.css","sourceRoot":""}

View File

@@ -0,0 +1,27 @@
webpackJsonp([1,3],{
/***/ 0:
/***/ function(module, exports, __webpack_require__) {
__webpack_require__(732);
module.exports = __webpack_require__(736);
/***/ },
/***/ 732:
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/***/ 736:
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ }
});
//# sourceMappingURL=style.45c91aea174020d653f5.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["webpack:///./~/react-select/dist/react-select.css?","webpack:///./src/main.less?"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,0C;;;;;;;ACAA,0C","file":"style.45c91aea174020d653f5.js","sourcesContent":["// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react-select/dist/react-select.css\n ** module id = 732\n ** module chunks = 1\n **/","// removed by extract-text-webpack-plugin\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/main.less\n ** module id = 736\n ** module chunks = 1\n **/"],"sourceRoot":""}

View File

@@ -0,0 +1,334 @@
/**
* React Select
* ============
* Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
* https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
* MIT License: https://github.com/keystonejs/react-select
*/
.Select {
position: relative;
}
.Select,
.Select div,
.Select input,
.Select span {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.Select.is-disabled > .Select-control {
background-color: #f9f9f9;
}
.Select.is-disabled > .Select-control:hover {
box-shadow: none;
}
.Select.is-disabled .Select-arrow-zone {
cursor: default;
pointer-events: none;
}
.Select-control {
background-color: #fff;
border-color: #d9d9d9 #ccc #b3b3b3;
border-radius: 4px;
border: 1px solid #ccc;
color: #333;
cursor: default;
display: table;
height: 36px;
outline: none;
overflow: hidden;
position: relative;
width: 100%;
}
.Select-control:hover {
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
}
.is-searchable.is-open > .Select-control {
cursor: text;
}
.is-open > .Select-control {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
background: #fff;
border-color: #b3b3b3 #ccc #d9d9d9;
}
.is-open > .Select-control > .Select-arrow {
border-color: transparent transparent #999;
border-width: 0 5px 5px;
}
.is-searchable.is-focused:not(.is-open) > .Select-control {
cursor: text;
}
.is-focused:not(.is-open) > .Select-control {
border-color: #007eff;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 3px rgba(0, 126, 255, 0.1);
}
.Select-placeholder,
:not(.Select--multi) > .Select-control .Select-value {
bottom: 0;
color: #aaa;
left: 0;
line-height: 34px;
padding-left: 10px;
padding-right: 10px;
position: absolute;
right: 0;
top: 0;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.has-value:not(.Select--multi) > .Select-control > .Select-value .Select-value-label,
.has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value .Select-value-label {
color: #333;
}
.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label,
.has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label {
cursor: pointer;
text-decoration: none;
}
.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:hover,
.has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:hover,
.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:focus,
.has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:focus {
color: #007eff;
outline: none;
text-decoration: underline;
}
.Select-input {
height: 34px;
padding-left: 10px;
padding-right: 10px;
vertical-align: middle;
}
.Select-input > input {
background: none transparent;
border: 0 none;
box-shadow: none;
cursor: default;
display: inline-block;
font-family: inherit;
font-size: inherit;
height: 34px;
margin: 0;
outline: none;
padding: 0;
-webkit-appearance: none;
}
.is-focused .Select-input > input {
cursor: text;
}
.has-value.is-pseudo-focused .Select-input {
opacity: 0;
}
.Select-control:not(.is-searchable) > .Select-input {
outline: none;
}
.Select-loading-zone {
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 16px;
}
.Select-loading {
-webkit-animation: Select-animation-spin 400ms infinite linear;
-o-animation: Select-animation-spin 400ms infinite linear;
animation: Select-animation-spin 400ms infinite linear;
width: 16px;
height: 16px;
box-sizing: border-box;
border-radius: 50%;
border: 2px solid #ccc;
border-right-color: #333;
display: inline-block;
position: relative;
vertical-align: middle;
}
.Select-clear-zone {
-webkit-animation: Select-animation-fadeIn 200ms;
-o-animation: Select-animation-fadeIn 200ms;
animation: Select-animation-fadeIn 200ms;
color: #999;
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 17px;
}
.Select-clear-zone:hover {
color: #D0021B;
}
.Select-clear {
display: inline-block;
font-size: 18px;
line-height: 1;
}
.Select--multi .Select-clear-zone {
width: 17px;
}
.Select-arrow-zone {
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 25px;
padding-right: 5px;
}
.Select-arrow {
border-color: #999 transparent transparent;
border-style: solid;
border-width: 5px 5px 2.5px;
display: inline-block;
height: 0;
width: 0;
}
.is-open .Select-arrow,
.Select-arrow-zone:hover > .Select-arrow {
border-top-color: #666;
}
@-webkit-keyframes Select-animation-fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes Select-animation-fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.Select-menu-outer {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
background-color: #fff;
border: 1px solid #ccc;
border-top-color: #e6e6e6;
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
box-sizing: border-box;
margin-top: -1px;
max-height: 200px;
position: absolute;
top: 100%;
width: 100%;
z-index: 1;
-webkit-overflow-scrolling: touch;
}
.Select-menu {
max-height: 198px;
overflow-y: auto;
}
.Select-option {
box-sizing: border-box;
background-color: #fff;
color: #666666;
cursor: pointer;
display: block;
padding: 8px 10px;
}
.Select-option:last-child {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
.Select-option.is-focused {
background-color: rgba(0, 126, 255, 0.08);
color: #333;
}
.Select-option.is-disabled {
color: #cccccc;
cursor: default;
}
.Select-noresults {
box-sizing: border-box;
color: #999999;
cursor: default;
display: block;
padding: 8px 10px;
}
.Select--multi .Select-input {
vertical-align: middle;
margin-left: 10px;
padding: 0;
}
.Select--multi.has-value .Select-input {
margin-left: 5px;
}
.Select--multi .Select-value {
background-color: rgba(0, 126, 255, 0.08);
border-radius: 2px;
border: 1px solid rgba(0, 126, 255, 0.24);
color: #007eff;
display: inline-block;
font-size: 0.9em;
line-height: 1.4;
margin-left: 5px;
margin-top: 5px;
vertical-align: top;
}
.Select--multi .Select-value-icon,
.Select--multi .Select-value-label {
display: inline-block;
vertical-align: middle;
}
.Select--multi .Select-value-label {
border-bottom-right-radius: 2px;
border-top-right-radius: 2px;
cursor: default;
padding: 2px 5px;
}
.Select--multi a.Select-value-label {
color: #007eff;
cursor: pointer;
text-decoration: none;
}
.Select--multi a.Select-value-label:hover {
text-decoration: underline;
}
.Select--multi .Select-value-icon {
cursor: pointer;
border-bottom-left-radius: 2px;
border-top-left-radius: 2px;
border-right: 1px solid rgba(0, 126, 255, 0.24);
padding: 1px 5px 3px;
}
.Select--multi .Select-value-icon:hover,
.Select--multi .Select-value-icon:focus {
background-color: rgba(0, 113, 230, 0.08);
color: #0071e6;
}
.Select--multi .Select-value-icon:active {
background-color: rgba(0, 126, 255, 0.24);
}
.Select--multi.is-disabled .Select-value {
background-color: #fcfcfc;
border: 1px solid #e3e3e3;
color: #333;
}
.Select--multi.is-disabled .Select-value-icon {
cursor: not-allowed;
border-right: 1px solid #e3e3e3;
}
.Select--multi.is-disabled .Select-value-icon:hover,
.Select--multi.is-disabled .Select-value-icon:focus,
.Select--multi.is-disabled .Select-value-icon:active {
background-color: #fcfcfc;
}
@keyframes Select-animation-spin {
to {
transform: rotate(1turn);
}
}
@-webkit-keyframes Select-animation-spin {
to {
-webkit-transform: rotate(1turn);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +1,214 @@
/**
* Created by andrew on 8/18/16.
*/
export const useJSON = () => {};
export const clean = () => {};
export const useJQuery = () => {};
export const extractBundle = () => {};
export const extractLESS = () => {};
export const purifyCSS = () => {};
export const setupLess = () => {};
export const devServer = () => {};
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PurifyCSSPlugin = require('purifycss-webpack-plugin');
exports.devServer = function(options) {
return {
entry: {
'webpack-dev-server': 'webpack-dev-server/client?http://localhost:8080',
hmr: 'webpack/hot/only-dev-server'
},
devServer: {
contentBase: './build',
hot: true,
historyApiFallback: true,
inline: true,
stats: 'errors-only',
host: options.host, // Defaults to `localhost`
port: options.port, // Defaults to 8080
proxy: {
'/user*' : {
target: 'http://localhost:8080'
},
'/login' : {
target: 'http://localhost:8080'
},
'/customers*' : {
target: 'http://localhost:8080'
},
'/accounts*' : {
target: 'http://localhost:8080'
},
'/transfers*' : {
target: 'http://localhost:8080'
}
}
},
watchOptions: {
// Delay the rebuild after the first change
aggregateTimeout: 300,
// Poll using interval (in ms, accepts boolean too)
poll: 1000
},
plugins: [
// Enable multi-pass compilation for enhanced performance
// in larger projects. Good default.
new webpack.HotModuleReplacementPlugin({
multiStep: true
})
]
};
};
exports.setupCSS = function(paths) {
return {
module: {
loaders: [
{
test: /\.css$/,
loaders: ['style', 'css'],
include: paths
}
]
}
};
};
exports.setupLess = function(paths) {
return {
module: {
loaders: [
{
test: /\.(le)|(c)ss$/,
loaders: ['style', 'css', 'less'],
include: paths
}
]
}
};
};
exports.useJSON = function() {
return {
module: {
loaders: [
{
test: /\.json$/,
loaders: ['json']
}
]
}
};
};
exports.minify = function() {
return {
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
};
};
exports.extractBundle = function(options) {
const entry = {};
entry[options.name] = options.entries;
return {
// Define an entry point needed for splitting.
entry: entry,
plugins: [
// Extract bundle and manifest files. Manifest is
// needed for reliable caching.
new webpack.optimize.CommonsChunkPlugin({
names: [options.name, 'manifest']
})
]
};
};
exports.clean = function(path) {
return {
plugins: [
new CleanWebpackPlugin([path], {
// Without `root` CleanWebpackPlugin won't point to our
// project and will fail to work.
root: process.cwd()
})
]
};
};
exports.extractCSS = function(paths) {
return {
module: {
loaders: [
// Extract CSS during build
{
test: /\.css$/,
// loaders: ['style', 'css'],
loader: ExtractTextPlugin.extract('style', 'css'),
include: paths
}
]
},
plugins: [
// Output extracted CSS to a file
new ExtractTextPlugin('[name].[chunkhash].css')
]
};
};
exports.extractLESS = function(paths) {
return {
module: {
loaders: [
// Extract CSS during build
{
test: /\.(le)|(c)ss$/,
// loaders: ['style', 'css', 'less'],
loader: ExtractTextPlugin.extract(
"style-loader",
'css?sourceMap!' +
'less?sourceMap'
),
include: paths
}
]
},
plugins: [
// Output extracted CSS to a file
new ExtractTextPlugin('[name].[chunkhash].css')
]
};
};
exports.purifyCSS = function(paths) {
return {
plugins: [
new PurifyCSSPlugin({
basePath: process.cwd(),
// `paths` is used to point PurifyCSS to files not
// visible to Webpack. You can pass glob patterns
// to it.
paths: paths,
purifyOptions: {
// minify: false,
// info: true,
// output: './output.css'
}
})
]
}
};
exports.useJQuery = function() {
return {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
};
};

View File

@@ -1,7 +1,7 @@
{
"name": "",
"description": "",
"author": "",
"name": "event-sourcing-examples",
"description": "ES Money Transfer App",
"author": "cer",
"private": true,
"version": "0.1.0",
"license": "MIT",
@@ -9,20 +9,24 @@
"scripts": {
"start": "gulp serve",
"open": "gulp open",
"gulp": "gulp"
"gulp": "gulp",
"build": "webpack",
"watch": "webpack --progress --colors --watch --display-error-details --display-chunks --profile",
"start-dev": "export PORT=3000 && webpack-dev-server --host 0.0.0.0"
},
"devDependencies": {
"autoprefixer-loader": "^2.0.0",
"babel-core": "6.1.4",
"babel-loader": "6.1.0",
"babel-plugin-add-module-exports": "^0.1.2",
"babel-plugin-transform-runtime": "6.1.4",
"babel-plugin-transform-runtime": "^6.12.0",
"babel-polyfill": "^6.1.4",
"babel-preset-es2015": "6.1.4",
"babel-preset-react": "6.1.4",
"babel-preset-stage-0": "6.1.2",
"babel-register": "6.1.4",
"babel-runtime": "^6.0.14",
"clean-webpack-plugin": "^0.1.10",
"copy-webpack-plugin": "^3.0.1",
"css-loader": "^0.14.4",
"del": "^1.2.0",
@@ -42,6 +46,8 @@
"less-loader": "^2.2.0",
"node-libs-browser": "^0.5.2",
"open": "0.0.5",
"purifycss-webpack-plugin": "^2.0.3",
"react-hot-loader": "^1.3.0",
"redux-devtools": "^2.1.5",
"run-sequence": "^1.1.0",
"style-loader": "^0.12.3",
@@ -63,10 +69,10 @@
"react": "^0.14.7",
"react-bootstrap": "^0.28.3",
"react-dom": "^0.14.0",
"react-loader": "^2.0.0",
"react-loader": "^2.4.0",
"react-pacomo": "^0.5.1",
"react-redux": "^4.4.0",
"react-router": "^2.0.0-rc2",
"react-router": "^2.7.0",
"react-router-bootstrap": "^0.20.1",
"react-router-redux": "^3.0.0",
"react-select": "^0.9.1",

View File

View File

@@ -0,0 +1,81 @@
<!DOCTYPE html>
<!--[if lt IE 7 ]> <html lang="en" class="ie6" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]-->
<!--[if IE 7 ]> <html lang="en" class="ie7" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]-->
<!--[if IE 8 ]> <html lang="en" class="ie8" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]-->
<!--[if IE 9 ]> <html lang="en" class="ie9" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title><%= htmlWebpackPlugin.options.title || 'Webpack App'%></title><%
if (htmlWebpackPlugin.options.description) {
%><meta name="description" content="<%= htmlWebpackPlugin.options.description%>" /><%
} %><%
if (htmlWebpackPlugin.files.favicon) {
%><link rel="shortcut icon" href="<%= htmlWebpackPlugin.files.favicon%>"><%
} %><%
if (htmlWebpackPlugin.options.mobile) {
%><meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" /><%
} %><!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css"><%
for (var css in htmlWebpackPlugin.files.css) {
%><link href="<%= htmlWebpackPlugin.files.css[css] %>" rel="stylesheet"><%
} %><%
if (htmlWebpackPlugin.options.baseHref) {
%><base href="<%= htmlWebpackPlugin.options.baseHref %>" /><%
} %></head>
<body><%
if (htmlWebpackPlugin.options.unsupportedBrowser) {
%><style>.unsupported-browser { display: none; }</style>
<div class="unsupported-browser">
Sorry, your browser is not supported. Please upgrade to
the latest version or switch your browser to use this site.
See <a href="http://outdatedbrowser.com/">outdatedbrowser.com</a>
for options.
</div><%
} %><%
if (htmlWebpackPlugin.options.appMountId) {
%><div id="<%= htmlWebpackPlugin.options.appMountId%>"></div><%
} %><%
if (htmlWebpackPlugin.options.appMountIds && htmlWebpackPlugin.options.appMountIds.length > 0) {
%><%
for (var index in htmlWebpackPlugin.options.appMountIds) {
%><div id="<%= htmlWebpackPlugin.options.appMountIds[index]%>"></div><%
} %><%
} %><%
if (htmlWebpackPlugin.options.window) {
%><script>
<%
for (var varName in htmlWebpackPlugin.options.window) { %>window['<%=varName%>'] = <%= JSON.stringify(htmlWebpackPlugin.options.window[varName]) %>;<%
} %>
</script><%
} %><%
for (var chunk in htmlWebpackPlugin.files.chunks) {
%><script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script><%
} %><%
if (htmlWebpackPlugin.options.devServer) {
%><script src="<%= htmlWebpackPlugin.options.devServer%>/webpack-dev-server.js"></script><%
} %><%
if (htmlWebpackPlugin.options.googleAnalytics) {
%><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
<% if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
ga('create', '<%= htmlWebpackPlugin.options.googleAnalytics.trackingId%>', 'auto');
<% } else { throw new Error("html-webpack-template requires googleAnalytics.trackingId config"); }%>
<% if (htmlWebpackPlugin.options.googleAnalytics.pageViewOnLoad) { %>
ga('send', 'pageview');
<% } %>
</script><%
}
%><!--<%= JSON.stringify(htmlWebpackPlugin)%>--></body>
</html>

5
js-frontend/public/robots.txt Executable file
View File

@@ -0,0 +1,5 @@
# www.robotstxt.org/
# Allow crawling of all content
User-agent: *
Disallow:

View File

@@ -0,0 +1,334 @@
/**
* React Select
* ============
* Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
* https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
* MIT License: https://github.com/keystonejs/react-select
*/
.Select {
position: relative;
}
.Select,
.Select div,
.Select input,
.Select span {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.Select.is-disabled > .Select-control {
background-color: #f9f9f9;
}
.Select.is-disabled > .Select-control:hover {
box-shadow: none;
}
.Select.is-disabled .Select-arrow-zone {
cursor: default;
pointer-events: none;
}
.Select-control {
background-color: #fff;
border-color: #d9d9d9 #ccc #b3b3b3;
border-radius: 4px;
border: 1px solid #ccc;
color: #333;
cursor: default;
display: table;
height: 36px;
outline: none;
overflow: hidden;
position: relative;
width: 100%;
}
.Select-control:hover {
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
}
.is-searchable.is-open > .Select-control {
cursor: text;
}
.is-open > .Select-control {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
background: #fff;
border-color: #b3b3b3 #ccc #d9d9d9;
}
.is-open > .Select-control > .Select-arrow {
border-color: transparent transparent #999;
border-width: 0 5px 5px;
}
.is-searchable.is-focused:not(.is-open) > .Select-control {
cursor: text;
}
.is-focused:not(.is-open) > .Select-control {
border-color: #007eff;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 3px rgba(0, 126, 255, 0.1);
}
.Select-placeholder,
:not(.Select--multi) > .Select-control .Select-value {
bottom: 0;
color: #aaa;
left: 0;
line-height: 34px;
padding-left: 10px;
padding-right: 10px;
position: absolute;
right: 0;
top: 0;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.has-value:not(.Select--multi) > .Select-control > .Select-value .Select-value-label,
.has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value .Select-value-label {
color: #333;
}
.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label,
.has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label {
cursor: pointer;
text-decoration: none;
}
.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:hover,
.has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:hover,
.has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:focus,
.has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:focus {
color: #007eff;
outline: none;
text-decoration: underline;
}
.Select-input {
height: 34px;
padding-left: 10px;
padding-right: 10px;
vertical-align: middle;
}
.Select-input > input {
background: none transparent;
border: 0 none;
box-shadow: none;
cursor: default;
display: inline-block;
font-family: inherit;
font-size: inherit;
height: 34px;
margin: 0;
outline: none;
padding: 0;
-webkit-appearance: none;
}
.is-focused .Select-input > input {
cursor: text;
}
.has-value.is-pseudo-focused .Select-input {
opacity: 0;
}
.Select-control:not(.is-searchable) > .Select-input {
outline: none;
}
.Select-loading-zone {
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 16px;
}
.Select-loading {
-webkit-animation: Select-animation-spin 400ms infinite linear;
-o-animation: Select-animation-spin 400ms infinite linear;
animation: Select-animation-spin 400ms infinite linear;
width: 16px;
height: 16px;
box-sizing: border-box;
border-radius: 50%;
border: 2px solid #ccc;
border-right-color: #333;
display: inline-block;
position: relative;
vertical-align: middle;
}
.Select-clear-zone {
-webkit-animation: Select-animation-fadeIn 200ms;
-o-animation: Select-animation-fadeIn 200ms;
animation: Select-animation-fadeIn 200ms;
color: #999;
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 17px;
}
.Select-clear-zone:hover {
color: #D0021B;
}
.Select-clear {
display: inline-block;
font-size: 18px;
line-height: 1;
}
.Select--multi .Select-clear-zone {
width: 17px;
}
.Select-arrow-zone {
cursor: pointer;
display: table-cell;
position: relative;
text-align: center;
vertical-align: middle;
width: 25px;
padding-right: 5px;
}
.Select-arrow {
border-color: #999 transparent transparent;
border-style: solid;
border-width: 5px 5px 2.5px;
display: inline-block;
height: 0;
width: 0;
}
.is-open .Select-arrow,
.Select-arrow-zone:hover > .Select-arrow {
border-top-color: #666;
}
@-webkit-keyframes Select-animation-fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes Select-animation-fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.Select-menu-outer {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
background-color: #fff;
border: 1px solid #ccc;
border-top-color: #e6e6e6;
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
box-sizing: border-box;
margin-top: -1px;
max-height: 200px;
position: absolute;
top: 100%;
width: 100%;
z-index: 1;
-webkit-overflow-scrolling: touch;
}
.Select-menu {
max-height: 198px;
overflow-y: auto;
}
.Select-option {
box-sizing: border-box;
background-color: #fff;
color: #666666;
cursor: pointer;
display: block;
padding: 8px 10px;
}
.Select-option:last-child {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
.Select-option.is-focused {
background-color: rgba(0, 126, 255, 0.08);
color: #333;
}
.Select-option.is-disabled {
color: #cccccc;
cursor: default;
}
.Select-noresults {
box-sizing: border-box;
color: #999999;
cursor: default;
display: block;
padding: 8px 10px;
}
.Select--multi .Select-input {
vertical-align: middle;
margin-left: 10px;
padding: 0;
}
.Select--multi.has-value .Select-input {
margin-left: 5px;
}
.Select--multi .Select-value {
background-color: rgba(0, 126, 255, 0.08);
border-radius: 2px;
border: 1px solid rgba(0, 126, 255, 0.24);
color: #007eff;
display: inline-block;
font-size: 0.9em;
line-height: 1.4;
margin-left: 5px;
margin-top: 5px;
vertical-align: top;
}
.Select--multi .Select-value-icon,
.Select--multi .Select-value-label {
display: inline-block;
vertical-align: middle;
}
.Select--multi .Select-value-label {
border-bottom-right-radius: 2px;
border-top-right-radius: 2px;
cursor: default;
padding: 2px 5px;
}
.Select--multi a.Select-value-label {
color: #007eff;
cursor: pointer;
text-decoration: none;
}
.Select--multi a.Select-value-label:hover {
text-decoration: underline;
}
.Select--multi .Select-value-icon {
cursor: pointer;
border-bottom-left-radius: 2px;
border-top-left-radius: 2px;
border-right: 1px solid rgba(0, 126, 255, 0.24);
padding: 1px 5px 3px;
}
.Select--multi .Select-value-icon:hover,
.Select--multi .Select-value-icon:focus {
background-color: rgba(0, 113, 230, 0.08);
color: #0071e6;
}
.Select--multi .Select-value-icon:active {
background-color: rgba(0, 126, 255, 0.24);
}
.Select--multi.is-disabled .Select-value {
background-color: #fcfcfc;
border: 1px solid #e3e3e3;
color: #333;
}
.Select--multi.is-disabled .Select-value-icon {
cursor: not-allowed;
border-right: 1px solid #e3e3e3;
}
.Select--multi.is-disabled .Select-value-icon:hover,
.Select--multi.is-disabled .Select-value-icon:focus,
.Select--multi.is-disabled .Select-value-icon:active {
background-color: #fcfcfc;
}
@keyframes Select-animation-spin {
to {
transform: rotate(1turn);
}
}
@-webkit-keyframes Select-animation-spin {
to {
-webkit-transform: rotate(1turn);
}
}

View File

@@ -12,17 +12,9 @@ import createLogger from 'redux-logger';
import { Route, IndexRoute, Link, IndexLink } from "react-router";
import { ReduxRouter} from "redux-router";
//import { Router, IndexRoute, Route, browserHistory } from 'react-router';
//import { syncHistory, routeReducer } from 'react-router-redux';
//import { configure as reduxAuthConfigure, authStateReducer } from "redux-auth";
//import { authStateReducer } from "redux-auth";
//import authStateReducer from './reducers/auth';
//import appStateReducer from './reducers/data';
import mainReducer from './reducers';
import { configure as reduxAuthConfigure } from './actions/configure';
//import { AuthGlobals } from "redux-auth/bootstrap-theme";
import { createHistory, createHashHistory, createMemoryHistory } from "history";
import { pushState, routerStateReducer, reduxReactRouter as clientRouter} from "redux-router";
@@ -41,11 +33,9 @@ import SignUp from "./views/SignUp";
class App extends React.Component {
render() {
return (
<Container>
return (<Container>
{this.props.children}
</Container>
);
</Container>);
}
}

View File

@@ -217,20 +217,20 @@ export const makeTransfer = (accountId, payload) => {
};
};
export const getTransfersRequested = makeActionCreator(T.TRANSFERS.LIST_START);
export const getTransfersComplete = makeActionCreator(T.TRANSFERS.LIST_COMPLETE, 'payload');
export const getTransfersError = makeActionCreator(T.TRANSFERS.LIST_ERROR, 'error');
export const getTransfersRequested = makeActionCreator(T.TRANSFERS.LIST_START, 'id');
export const getTransfersComplete = makeActionCreator(T.TRANSFERS.LIST_COMPLETE, 'id', 'payload');
export const getTransfersError = makeActionCreator(T.TRANSFERS.LIST_ERROR, 'id', 'error');
export const getTransfers = (accountId) => {
return dispatch => {
dispatch(getTransfersRequested());
dispatch(getTransfersRequested(accountId));
return api.apiRetrieveTransfers(accountId)
.then(data => {
dispatch(getTransfersComplete(data));
dispatch(getTransfersComplete(accountId, data));
return data;
})
.catch(err => {
dispatch(getTransfersError(err));
dispatch(getTransfersError(accountId, err));
return err;
});
};

View File

@@ -9,7 +9,7 @@ import { initialize } from "./app";
/**
* Fire-up React Router.
*/
const reactRoot = window.document.getElementById("react-app");
const reactRoot = window.document.getElementById("root");
initialize().then(({ provider }) => {
ReactDOM.render(provider, reactRoot);
});

View File

@@ -4,8 +4,9 @@
import React from "react";
import { connect } from 'react-redux';
import Spinner from "react-loader";
import * as BS from "react-bootstrap";
// import * as BS from "react-bootstrap";
import * as A from '../actions/entities';
import { Route, IndexRoute, Link, IndexLink } from "react-router";
// import { Money } from '../components/Money';
@@ -32,15 +33,15 @@ export class AccountInfo extends React.Component {
const account = entities[accountId];
if (!account) {
return (<div>{ accountId } <Spinner ref="spinner" loaded={false} /></div>)
return (<Link to={ `/account/${accountId}` }>{ accountId } <Spinner loaded={false} /></Link>)
}
const { title } = account;
return (<div>{ title } </div>);
return (<Link to={ `/account/${accountId}` }>{ title }</Link>);
}
}
export default connect(({ app }) => ({
entities: app.data.entities
}))(AccountInfo);
}))(AccountInfo);

View File

@@ -11,17 +11,23 @@ import AccountInfo from './AccountInfo';
export class TransfersTable extends React.Component {
render() {
const { loading, data, errors } = this.props;
if (loading) {
return (<h2><Spinner ref="spinner" loaded={false} /> Loading..</h2>);
const { transfers, forAccount } = this.props;
const { loading, data, errors } = transfers || {};
if (!transfers || loading) {
return (<h2><Spinner loaded={false} /> Loading..</h2>);
}
if (Object.keys(errors).length) {
return (<div className="text-danger">Errors..</div>);
}
const transfers = data.length ? data.map(({
const currentAccountId = forAccount;
const transfersMarkup = data.length ?
data
.filter(({ toAccountId, fromAccountId}) => ((fromAccountId === currentAccountId) || (toAccountId === currentAccountId)))
.sort((a, b) => (-(a.date - b.date)))
.map(({
amount,
fromAccountId,
toAccountId,
@@ -29,32 +35,43 @@ export class TransfersTable extends React.Component {
description = '',
date = null,
status = ''
}, idx) => (<tr key={idx}>
<td><TimeAgo date={date} /></td>
<td><AccountInfo accountId={ fromAccountId } /></td>
<td><AccountInfo accountId={ toAccountId } /></td>
<td><Money amount={ amount } /></td>
<td>{ description || '[No description]'}</td>
<td>{ status || '&mdash;' }</td>
</tr>)) : (<tr>
<td colSpan={6}>No transfers for this account just yet.</td>
</tr>);
}) => {
const isOriginating = fromAccountId == currentAccountId;
const directionMarkup = isOriginating ? 'Debit' : 'Credit';
const counterAccountMarkup = isOriginating ?
<AccountInfo accountId={ toAccountId } /> :
<AccountInfo accountId={ fromAccountId } />;
const transferTimestamp = new Date(date);
const timeAgoTitle = transferTimestamp.toLocaleDateString() + ' ' + transferTimestamp.toLocaleTimeString();
return (<tr>
<td><TimeAgo date={date} title={ timeAgoTitle } /></td>
<td>{ directionMarkup }</td>
<td>{ counterAccountMarkup }</td>
<td><Money amount={ amount } /></td>
<td>{ description || '—' }</td>
<td>{ status || '—' }</td>
</tr>);
}) : (<tr>
<td colSpan={6}>No transfers for this account just yet.</td>
</tr>);
return (
<BS.Table striped bordered condensed hover>
<thead>
<tr>
<th>Date</th>
<th>Transfer Out</th>
<th>Transfer In</th>
<th>Type</th>
<th>Other Account</th>
<th>Amount</th>
<th>Description</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{ transfers }
{ transfersMarkup }
</tbody>
</BS.Table>
);

View File

@@ -11,11 +11,6 @@ import HeaderLinks from '../HeaderLinks';
//const SignOutButton = () => (<div>SignOutButton!</div>);
//if (!global.__SERVER__ && !global.__TEST__) {
// require("../../styles/main.scss");
//}
class Container extends React.Component {
static propTypes = {
children: PropTypes.node

View File

@@ -40,7 +40,7 @@ class ButtonLoader extends React.Component {
? this.props.spinColorDark
: this.props.spinColorLight;
icon = <Spinner ref="spinner" {...this.props.spinConfig} color={spinColor} loaded={false} />;
icon = <Spinner {...this.props.spinConfig} color={spinColor} loaded={false} />;
} else {
icon = this.props.icon;
}

View File

@@ -37,5 +37,5 @@ store.subscribe(blocked(() => {
function onHashChange() {
store.dispatch(navigation.complete())
}
window.addEventListener('hashchange', onHashChange, false)
onHashChange()
window.addEventListener('hashchange', onHashChange, false);
onHashChange();

View File

@@ -1,6 +1,28 @@
/**
* Created by andrew on 3/22/16.
*/
export const createByIdDataReducer = ([KEY_REQUEST, KEY_SUCCESS, KEY_ERROR], next) => (state = {}, action) => {
switch (action.type) {
case KEY_REQUEST:
case KEY_SUCCESS:
case KEY_ERROR: {
if (!action.id) {
debugger;
}
if (state.errors) {
debugger;
}
return {
...state,
[action.id]: next(state, action)
};
}
default:
return state;
}
};
const createDataReducer = ([KEY_REQUEST, KEY_SUCCESS, KEY_ERROR], payloadActionNameProp = 'payload', payloadStateNameProp = 'data', payloadAssignFn = (k = []) => [...k]) => {
const initialState = {

View File

@@ -5,10 +5,13 @@
* Created by andrew on 15/03/16.
*/
import T from '../../constants/ACTION_TYPES';
import createListReducer from '../createDataReducer';
import createListReducer from '../createDataReducer';
import {createByIdDataReducer } from '../createDataReducer';
export const transfers = createListReducer([
const selectedEvents = [
T.TRANSFERS.LIST_START,
T.TRANSFERS.LIST_COMPLETE,
T.TRANSFERS.LIST_ERROR
]);
];
export const transfers = createByIdDataReducer(selectedEvents, createListReducer(selectedEvents));

View File

@@ -2,7 +2,7 @@
* Created by andrew on 8/17/16.
*/
export const blocked = (fn) => {
export const blocked = (fn, useCb) => {
let isBlocked = false;
return (...args) => {
if (isBlocked) {
@@ -10,8 +10,13 @@ export const blocked = (fn) => {
}
//noinspection JSUnusedAssignment
isBlocked = true;
const result = fn(...args);
isBlocked = false;
const cb = () => {
isBlocked = false;
};
const result = useCb ? fn(...(args.concat([cb]))) : fn(...args);
if (!useCb) {
cb();
}
return result;
};
};

View File

@@ -7,8 +7,8 @@ import { connect } from "react-redux";
import { PageHeader, OverlayTrigger, Tooltip, Grid, Col, Row, Nav, NavItem, ButtonGroup, Button, Table } from "react-bootstrap";
import * as BS from "react-bootstrap";
import Select from "react-select";
import Spinner from "react-loader";
import Select from "react-select";
import Input from "../controls/bootstrap/Input";
import { Money, moneyText } from '../components/Money';
import { TransfersTable } from '../components/TransfersTable';
@@ -21,32 +21,92 @@ import * as Modals from './modals';
import * as A from '../actions/entities';
import read from '../utils/readProp';
import { blocked } from '../utils/blockedExecution';
const resetModals = {
showAccountModal: false
showAccountModal: false,
unsaved: false
};
export class Account extends React.Component {
constructor(...args) {
super(...args);
this.state = { ...resetModals };
const ensureTransfers = this.ensureTransfers.bind(this);
const ensureAccounts = this.ensureAccounts.bind(this);
this.ensureTransfers = blocked(ensureTransfers, true);
this.ensureAccounts = blocked(ensureAccounts, true);
}
loadAccountInfo() {
ensureTransfers(props, cb) {
const forceFetch = !cb;
if (forceFetch) {
cb = props;
props = this.props;
}
const { dispatch, params, transfers } = props;
if (!forceFetch && !params) {
return cb();
}
const { accountId } = params;
if (!forceFetch && (!accountId || transfers[accountId])) {
return cb();
}
dispatch(A.getTransfers(accountId)).then(cb, cb);
}
ensureAccounts(props, cb) {
const forceFetch = !cb;
if (forceFetch) {
cb = props;
props = this.props;
}
const { dispatch, params, data } = props;
if (!forceFetch && (!params || !data || !data.accounts)) {
return cb();
}
const { accountId } = params;
if (!forceFetch && data.accounts.own && data.accounts.own.length && data.entities[accountId]) {
return cb();
}
if (!forceFetch && (!props.auth || !props.auth.user || !props.auth.user.attributes)) {
return cb();
}
const {
id: customerId
} = this.props.auth.user.attributes;
this.props.dispatch(A.fetchOwnAccounts(customerId));
} = props.auth.user.attributes;
const { dispatch, params } = this.props;
const { accountId } = params;
dispatch(A.fetchAccount(accountId));
dispatch(A.getTransfers(accountId));
Promise.all([
dispatch(A.fetchOwnAccounts(customerId)),
dispatch(A.fetchAccount(accountId)),
]).then(cb, cb);
}
// shouldComponentUpdate(nextProps) {
// return (nextProps.params.accountId !== this.props.params.accountId) || (nextProps.app !== this.props.app);
// }
componentWillMount() {
this.loadAccountInfo();
this.ensureAccounts(this.props);
this.ensureTransfers(this.props);
}
componentWillReceiveProps(nextProps) {
this.ensureAccounts(nextProps);
this.ensureTransfers(nextProps);
}
createAccountModal() {
@@ -56,7 +116,7 @@ export class Account extends React.Component {
}
createAccountModalConfirmed() {
debugger;
// debugger;
}
@@ -69,18 +129,21 @@ export class Account extends React.Component {
handleInput(key, value) {
this.props.dispatch(A.makeTransferFormUpdate(key, value));
}
initiateTransfer(){
const { dispatch, params, transfer } = this.props;
const { accountId } = params;
dispatch(A.makeTransfer(accountId, transfer.form ))
.then(() => {
setTimeout(() => {
this.loadAccountInfo();
}, 500);
});
.then(() => new Promise((rs) => {
setTimeout(() => {
this.ensureAccounts();
this.ensureTransfers();
rs();
}, 1500);
})
);
}
render () {
const { showAccountModal } = this.state;
@@ -91,15 +154,17 @@ export class Account extends React.Component {
const account = entities[accountId];
const spinnerResult = (<h2 key="0">Loading..</h2>);
if (loading) {
return (<h2><Spinner ref="spinner" loaded={false} /> Loading..</h2>);
return spinnerResult;
}
if (!account) {
if (errors.length) {
return (<h2>Error loading specified account</h2>);
} else {
return (<h2><Spinner ref="spinner" loaded={false} /> Loading..</h2>);
return spinnerResult;
}
}
@@ -126,13 +191,13 @@ export class Account extends React.Component {
const { title: titleRaw, description: descriptionRaw, balance } = account;
const title = titleRaw || '[No title]';
const description = descriptionRaw || '[No description]';
const title = titleRaw || '';
const description = descriptionRaw || '';
const transferDisabled = this.props.transfer.loading;
return (
<div>
<div key={accountId}>
<PageHeader>
Account
<Nav pullRight={true}>
@@ -219,7 +284,8 @@ export class Account extends React.Component {
<h3>Transfer History:</h3>
</Col>
</Row>
<TransfersTable { ...this.props.transfers } />
<TransfersTable forAccount={accountId} transfers={ this.props.transfers[accountId] } />
<Modals.NewAccountModal show={showAccountModal}
action={this.createAccountModalConfirmed.bind(this)}
@@ -235,11 +301,14 @@ export class Account extends React.Component {
}
export default connect(({
app
app,
router
}) => ({
app,
auth: app.auth,
data: app.data,
transfers: app.data.transfers,
ui: app.ui.account,
transfer: app.ui.transfersMake
transfer: app.ui.transfersMake,
router
}))(Account);

View File

@@ -52,10 +52,14 @@ class MyAccounts extends React.Component {
this.props.dispatch(A.accountCreate(customerId, payload))
.then((accountId) => {
this.close();
return this.props.dispatch(A.fetchOwnAccounts(customerId));
// return new Promise((rs, rj) => {
setTimeout(() => {
this.props.dispatch(A.fetchOwnAccounts(customerId)); //.then(rs, rj);
}, 1000);
// });
})
.catch(err => {
debugger;
// debugger;
this.props.dispatch(A.accountCreateError(err));
});
}
@@ -74,10 +78,14 @@ class MyAccounts extends React.Component {
this.props.dispatch(A.accountRefCreate(customerId, payload))
.then(() => {
this.close();
return this.props.dispatch(A.fetchOwnAccounts(customerId));
return new Promise((rs, rj) => {
setTimeout(() => {
this.props.dispatch(A.fetchOwnAccounts(customerId)).then(rs, rj);
}, 1000);
})
})
.catch(err => {
debugger;
// debugger;
this.props.dispatch(A.accountRefCreateError(err));
});
}

View File

@@ -13,23 +13,30 @@ const pkg = require('./package.json');
const parts = require('./config/webpackConfigParts');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const ENTRIES = Object.keys(pkg.dependencies);
const CSS_ENTIRES = ['bootstrap-horizon'];
const CSS_ENTIRES = [
//'bootstrap-horizon'
];
const JS_ENTRIES = ENTRIES.filter(p => CSS_ENTIRES.indexOf(p) < 0);
const PATHS = {
app: path.join(__dirname, 'src'),
appEntry: path.join(__dirname, 'src', 'index.js'),
appEntry: path.join(__dirname, 'src', 'client.js'),
style: [
path.join(__dirname, 'node_modules', 'bootstrap-horizon'),
path.join(__dirname, 'node_modules', 'rc-slider/assets'),
path.join(__dirname, 'src', 'style.css')
// path.join(__dirname, 'node_modules', 'bootstrap-horizon'),
// path.join(__dirname, 'node_modules', 'rc-slider/assets'),
path.join(__dirname, 'node_modules/react-select/dist/react-select.css'),
path.join(__dirname, 'src', 'main.css')
],
styleLess: [
path.join(__dirname, 'node_modules', 'bootstrap-horizon'),
path.join(__dirname, 'node_modules/rc-slider/assets/index.css'),
path.join(__dirname, 'src', 'style.less')
// path.join(__dirname, 'node_modules', 'bootstrap-horizon'),
// path.join(__dirname, 'node_modules/rc-slider/assets/index.css'),
path.join(__dirname, 'node_modules/react-select/dist/react-select.css'),
path.join(__dirname, 'src', 'main.less')
],
build: path.join(__dirname, 'build')
};
@@ -84,11 +91,10 @@ const common = {
// Required
inject: false,
template: './public/index.ejs',
//template: 'node_modules/html-webpack-template/index.ejs',
// Optional
title: 'ES IOT Lighting',
description: 'ES IOT Lighting App',
title: 'Money Transfer App',
description: 'ES Money Transfer App',
appMountId: 'root',
// baseHref: 'http://example.com/awesome',
// devServer: 3001,
@@ -142,7 +148,7 @@ const config = (() => {
return merge(
common,
{
devtool: 'eval-source-map'
devtool: 'source-map'
},
parts.useJSON(),
parts.useJQuery(),
@@ -163,109 +169,4 @@ const config = (() => {
})();
// module.exports = validate(config);
//import ExtractTextPlugin from "extract-text-webpack-plugin";
export default (DEBUG, PATH, PORT=3000) => ({
entry: (DEBUG ? [
`webpack-dev-server/client?http://localhost:${PORT}`,
] : []).concat([
'./src/main.less',
'babel-polyfill',
'./src/client'
]),
output: {
path: path.resolve(__dirname, PATH, "generated"),
filename: DEBUG ? "main.js" : "main-[hash].js",
publicPath: "/generated/"
},
cache: DEBUG,
debug: DEBUG,
// For options, see http://webpack.github.io/docs/configuration.html#devtool
//devtool: DEBUG && "eval",
devtool: DEBUG && "cheap-module-eval-source-map",
module: {
loaders: [
// Load ES6/JSX
{ test: /\.jsx?$/,
include: [
path.resolve(__dirname, "src")
//,
//path.resolve(__dirname, "node_modules/redux-auth/src/views/bootstrap")
],
loader: "babel-loader",
query: {
plugins: ['transform-runtime'],
presets: ['es2015', 'react', 'stage-0']
}
},
//json
{
test: /\.json$/,
loader: 'json-loader'
},
// Load styles
{ test: /\.less$/,
loader: DEBUG
? "style!css!autoprefixer!less"
: ExtractTextPlugin.extract("style-loader", "css-loader!autoprefixer-loader!less-loader")
},
// Load images
{ test: /\.jpg/, loader: "url-loader?limit=10000&mimetype=image/jpg" },
{ test: /\.gif/, loader: "url-loader?limit=10000&mimetype=image/gif" },
{ test: /\.png/, loader: "url-loader?limit=10000&mimetype=image/png" },
{ test: /\.svg/, loader: "url-loader?limit=10000&mimetype=image/svg" },
// Load fonts
{ test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" },
]
},
plugins: DEBUG
? [
//new
]
: [
new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'}),
new ExtractTextPlugin("style.css", {allChunks: false}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
compressor: {screw_ie8: true, keep_fnames: true, warnings: false},
mangle: {screw_ie8: true, keep_fnames: true}
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
],
resolveLoader: {
root: path.join(__dirname, "node_modules")
},
resolve: {
root: path.join(__dirname, "node_modules"),
modulesDirectories: ['node_modules'],
alias: {
environment: DEBUG
? path.resolve(__dirname, 'config', 'environments', 'development.js')
: path.resolve(__dirname, 'config', 'environments', 'production.js')
},
// Allow to omit extensions when requiring these files
extensions: ["", ".js", ".jsx"]
}
});
module.exports = validate(config);