-
+
IClient
-
+
diff --git a/app/components/Menu/Menu.js b/app/components/Menu/Menu.js
index af21a47..06211bb 100644
--- a/app/components/Menu/Menu.js
+++ b/app/components/Menu/Menu.js
@@ -1,7 +1,7 @@
import React from 'react';
import { Router } from 'react-router'
-import Nav from 'components/Nav/Nav'
+import NavMenu from 'components/NavMenu/NavMenu'
import LinksApp from 'components/LinksApp/LinksApp'
@@ -26,14 +26,14 @@ class Menu extends React.Component{
handleView() {
return (
-
+
);
}
diff --git a/app/components/Nav/Nav.js b/app/components/NavMenu/NavMenu.js
similarity index 79%
rename from app/components/Nav/Nav.js
rename to app/components/NavMenu/NavMenu.js
index 616512a..c05ba92 100644
--- a/app/components/Nav/Nav.js
+++ b/app/components/NavMenu/NavMenu.js
@@ -1,6 +1,8 @@
import React from 'react';
-class Nav extends React.Component
+import Offline from 'components/Offline/Offline'
+
+class NavMenu extends React.Component
{
constructor(props, context) {
super(props, context);
@@ -33,6 +35,11 @@ class Nav extends React.Component
+
+
+
+
+
@@ -47,9 +54,9 @@ class Nav extends React.Component
}
}
-Nav.childContextTypes = {
+NavMenu.childContextTypes = {
onClick: React.PropTypes.func
};
-export default Nav;
+export default NavMenu;
diff --git a/app/components/Offline/Offline.js b/app/components/Offline/Offline.js
new file mode 100644
index 0000000..470dc00
--- /dev/null
+++ b/app/components/Offline/Offline.js
@@ -0,0 +1,42 @@
+import React from 'react';
+
+class Offline extends React.Component
+{
+ constructor(props, context) {
+ super(props, context);
+ this.updateNetworkStatus = this.updateNetworkStatus.bind(this);
+ this.state = {
+ networkStatus: {
+ display: 'none'
+ }
+ };
+ }
+
+ componentWillMount() {
+ this.updateNetworkStatus();
+ window.addEventListener('online', this.updateNetworkStatus, false);
+ window.addEventListener('offline', this.updateNetworkStatus, false);
+ }
+
+ updateNetworkStatus() {
+ if (window.navigator.onLine) {
+ this.setState({networkStatus: {display : 'none'}});
+ } else {
+ this.setState({networkStatus: {display : ''}});
+ }
+ }
+
+ render() {
+ return (
+
+
+
+
+ Off Line
+
+ );
+ }
+}
+
+export default Offline;
+
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000..f253b79
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,28 @@
+
+codecov:
+ notify:
+ require_ci_to_pass: true
+comment:
+ behavior: default
+ layout: header, diff
+ require_changes: false
+coverage:
+ precision: 2
+ range:
+ - 90.0
+ - 100.0
+ round: down
+ status:
+ changes: false
+ patch: true
+ project: true
+parsers:
+ gcov:
+ branch_detection:
+ conditional: true
+ loop: true
+ macro: false
+ method: false
+ javascript:
+ enable_partials: false
+
diff --git a/package.json b/package.json
index b6dd58f..31da7b2 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,7 @@
"react-test-renderer": "^15.3.2",
"style-loader": "^0.13.1",
"url-loader": "^0.5.7",
- "webpack": "^1.13.2"
+ "webpack": "^2.1.0-beta.27"
},
"scripts": {
"test": "jest",
@@ -47,8 +47,8 @@
"app"
],
"collectCoverage": true,
- "globals" : {
- "HOST" : "http://localhost:3000"
+ "globals": {
+ "HOST": "http://localhost:3000"
},
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/tests/__mocks__/fileMock.js",
diff --git a/public/favicons/android-chrome-192x192.png b/public/favicons/android-chrome-192x192.png
new file mode 100644
index 0000000..7fc652d
Binary files /dev/null and b/public/favicons/android-chrome-192x192.png differ
diff --git a/public/favicons/android-chrome-512x512.png b/public/favicons/android-chrome-512x512.png
new file mode 100644
index 0000000..7d0f9f2
Binary files /dev/null and b/public/favicons/android-chrome-512x512.png differ
diff --git a/public/favicons/apple-touch-icon.png b/public/favicons/apple-touch-icon.png
new file mode 100644
index 0000000..5b84bb7
Binary files /dev/null and b/public/favicons/apple-touch-icon.png differ
diff --git a/public/favicons/favicon-16x16.png b/public/favicons/favicon-16x16.png
new file mode 100644
index 0000000..1955950
Binary files /dev/null and b/public/favicons/favicon-16x16.png differ
diff --git a/public/favicons/favicon-32x32.png b/public/favicons/favicon-32x32.png
new file mode 100644
index 0000000..b1a8a10
Binary files /dev/null and b/public/favicons/favicon-32x32.png differ
diff --git a/public/favicons/favicon.ico b/public/favicons/favicon.ico
new file mode 100644
index 0000000..90d6844
Binary files /dev/null and b/public/favicons/favicon.ico differ
diff --git a/public/favicons/mstile-150x150.png b/public/favicons/mstile-150x150.png
new file mode 100644
index 0000000..314dee8
Binary files /dev/null and b/public/favicons/mstile-150x150.png differ
diff --git a/public/favicons/safari-pinned-tab.svg b/public/favicons/safari-pinned-tab.svg
new file mode 100644
index 0000000..4a387db
--- /dev/null
+++ b/public/favicons/safari-pinned-tab.svg
@@ -0,0 +1,44 @@
+
+
+
diff --git a/public/index.html b/public/index.html
index 64cd577..31b0905 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,11 +2,37 @@
+
+
+
+
+
+
React Client
-
+
+
+
+
+
+
diff --git a/public/manifest.json b/public/manifest.json
new file mode 100644
index 0000000..3a1e7cc
--- /dev/null
+++ b/public/manifest.json
@@ -0,0 +1,27 @@
+{
+ "name": "iClient",
+ "short_name": "iClient",
+ "start_url": ".",
+ "display": "standalone",
+ "background_color": "#00d1b2",
+ "theme_color": "#00d1b2",
+ "description": "A client to manager herbs sells",
+ "icons": [
+ {
+ "src": "\/favicons\/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image\/png"
+ },
+ {
+ "src": "\/favicons\/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image\/png"
+ }
+ ],
+ "related_applications": [
+ {
+ "platform": "web",
+ "id" : "iclient.web"
+ }
+ ]
+}
diff --git a/public/service-worker.js b/public/service-worker.js
new file mode 100644
index 0000000..092bbf0
--- /dev/null
+++ b/public/service-worker.js
@@ -0,0 +1,56 @@
+var CACHE_NAME = 'v1::iClient';
+var urlsToCache = [
+ '/',
+ '/index.html',
+ '/dist/bundle.min.js',
+ '/favicons/favicon-16x16.png',
+ 'https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-with-addons.min.js',
+ 'https://cdnjs.cloudflare.com/ajax/libs/react-router/2.8.1/ReactRouter.min.js',
+ 'https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js',
+];
+
+self.addEventListener('install', function(event) {
+ event.waitUntil(
+ caches.open(CACHE_NAME).then(function(cache) {
+ return cache.addAll(urlsToCache);
+ })
+ );
+});
+
+self.addEventListener('activate', function(event) {
+ event.waitUntil(
+ caches.keys().then(function(cacheNames) {
+ return Promise.all(
+ cacheNames.filter(function(cacheName) {
+ return cacheName !== CACHE_NAME;
+ }).map(function(cacheName) {
+ return caches.delete(cacheName);
+ })
+ );
+ })
+ );
+});
+self.addEventListener('fetch', function(event) {
+ var requestURL = new URL(event.request.url);
+
+ event.respondWith(
+ caches.open(CACHE_NAME).then(function(cache) {
+ return cache.match(event.request).then(function(response) {
+ if (response && !navigator.onLine) {
+ return response;
+ }
+ return fetch(event.request).then(function(response) {
+ if (response.ok) {
+ cache.put(event.request, response.clone()).catch(function(error) {
+ return new Response("Request failed!");
+ });
+ }
+ return response;
+ }).catch(function(e) {
+ return new Response("Request failed!");
+ });
+ });
+ })
+ );
+});
+
diff --git a/tests/Nav.test.js b/tests/NavMenu.test.js
similarity index 84%
rename from tests/Nav.test.js
rename to tests/NavMenu.test.js
index f113044..4c9c4ce 100644
--- a/tests/Nav.test.js
+++ b/tests/NavMenu.test.js
@@ -1,15 +1,15 @@
-describe('Test Nav', () => {
+describe('Test NavMenu', () => {
const React = require('react');
const shallow = require('enzyme').shallow;
- const Nav = require('components/Nav/Nav').default;
+ const NavMenu = require('components/NavMenu/NavMenu').default;
- it('Nav should render child', (done) => {
+ it('NavMenu should render child', (done) => {
let component = shallow(
-
+
);
expect(component.find('directive').text()).toEqual('Child');
@@ -20,7 +20,7 @@ describe('Test Nav', () => {
it('toggleNavStatus function should change toggleNavStatus state from is-active to empty', (done) => {
let component = shallow(
-
+
);
component.instance().setState({ toggleNavStatus: 'is-active' });
@@ -34,7 +34,7 @@ describe('Test Nav', () => {
it('toggleNavStatus function should change toggleNavStatus state from empty to is-active', (done) => {
let component = shallow(
-
+
);
expect(component.state().toggleNavStatus).toEqual('');
@@ -47,7 +47,7 @@ describe('Test Nav', () => {
it('hide should change toggleNavStatus state to empty', (done) => {
let component = shallow(
-
+
);
component.instance().setState({ toggleNavStatus: 'whatever'} );
diff --git a/tests/Offline.test.js b/tests/Offline.test.js
new file mode 100644
index 0000000..8f7e347
--- /dev/null
+++ b/tests/Offline.test.js
@@ -0,0 +1,35 @@
+
+describe('Test Offline', () => {
+ const React = require('react');
+ const enzyme = require('enzyme');
+ const shallow = enzyme.shallow;
+ const Offline = require('components/Offline/Offline').default;
+
+ it('Offline should show message when without internet', (done) => {
+
+ window.navigator.__defineGetter__('onLine', function(){
+ return false;
+ });
+
+ let component = shallow();
+
+ expect(component.text()).toEqual('Off Line');
+ expect(component.state().networkStatus).toEqual({"display": ""});
+
+ done();
+
+ });
+
+ it('Offline should display none when with internet', (done) => {
+
+ window.navigator.__defineGetter__('onLine', function(){
+ return true;
+ });
+
+ let component = shallow();
+
+ expect(component.state().networkStatus).toEqual({"display": "none"});
+ done();
+
+ });
+});
diff --git a/webpack.config.js b/webpack.config.js
index 8bfac55..f296cab 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -2,7 +2,64 @@ const path = require('path');
var webpack = require('webpack');
+var bulmaLoader = {
+ test: /\.css$/,
+ loader: "style-loader!css-loader"
+};
+
+var fontAwesomeLoader = {
+ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
+ loader: "file-loader"
+};
+
+var fontAwesomeWoffLoader = {
+ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
+ loader: "url-loader",
+ query: {
+ limit: '10000',
+ minetype: 'application/font-woff'
+ }
+};
+
+var jsxLoader = {
+ test: /\.js$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader',
+ query: {
+ presets: ['react', ['es2015', {'modules' : false}]]
+ }
+};
+
+var loaderOptionsPlugin = new webpack.LoaderOptionsPlugin({
+ minimize: true,
+ debug: false
+});
+
+var uglifyJsPlugin = new webpack.optimize.UglifyJsPlugin({
+ compress: { warnings: false }
+});
+
+var definePlugin = new webpack.DefinePlugin({
+ HOST: JSON.stringify(process.env.HOST || 'http://localhost:3000'),
+ 'process.env': {
+ 'NODE_ENV': JSON.stringify('production')
+ }
+});
+
+var resolve = {
+ extensions: ['*', '.js', '.jsx'],
+ modules: [
+ path.resolve('./app'),
+ 'node_modules'
+ ]
+};
+
module.exports = {
+ externals: {
+ 'react': 'React',
+ 'react-router': 'ReactRouter',
+ 'react-dom': 'ReactDOM'
+ },
entry: "./app/App.js",
output: {
path: 'public/dist/',
@@ -10,35 +67,17 @@ module.exports = {
filename: "bundle.min.js",
},
module: {
- loaders: [
- //Bulma loader
- { test: /\.css$/, loader: "style-loader!css-loader" },
- //Font-awesome loader
- { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&minetype=application/font-woff" },
- { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" },
- //Jsx loader
- {
- test: /\.js$/,
- exclude: /node_modules/,
- loader: 'babel',
- query: {
- presets: ['react', 'es2015']
- }
- }
+ rules: [
+ bulmaLoader,
+ fontAwesomeWoffLoader,
+ fontAwesomeLoader,
+ jsxLoader
]
},
plugins: [
- new webpack.optimize.UglifyJsPlugin({
- compress: { warnings: false }
- }),
- new webpack.DefinePlugin({
- HOST: JSON.stringify(process.env.HOST || 'http://localhost:3000')
- })
+ loaderOptionsPlugin,
+ uglifyJsPlugin,
+ definePlugin
],
- resolve: {
- extensions: ['', '.js', '.jsx'],
- root: [
- path.resolve('./app')
- ]
- }
+ resolve: resolve
}