diff --git a/package.json b/package.json
index 3ba6643..6bf00a4 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
- "@types/jest": "23.3.13",
- "@types/node": "10.12.18",
- "@types/react": "16.7.22",
- "@types/react-dom": "16.0.11",
"react": "^16.7.0",
"react-dom": "^16.7.0",
+ "react-redux": "^6.0.0",
"react-scripts": "2.1.3",
"typescript": "3.2.4"
},
@@ -26,5 +23,12 @@
"not dead",
"not ie <= 11",
"not op_mini all"
- ]
+ ],
+ "devDependencies": {
+ "@types/jest": "23.3.13",
+ "@types/node": "10.12.18",
+ "@types/react": "16.7.22",
+ "@types/react-dom": "16.0.11",
+ "@types/react-redux": "^7.0.1"
+ }
}
diff --git a/src/App.css b/src/App.css
index 92f956e..4931613 100755
--- a/src/App.css
+++ b/src/App.css
@@ -1,32 +1,3 @@
.App {
text-align: center;
}
-
-.App-logo {
- animation: App-logo-spin infinite 20s linear;
- height: 40vmin;
-}
-
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
-}
-
-.App-link {
- color: #61dafb;
-}
-
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
diff --git a/src/App.tsx b/src/App.tsx
index ff5a4a6..fe7898d 100755
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,25 +1,11 @@
-import React, { Component } from 'react';
-import logo from './logo.svg';
+import React, { PureComponent } from 'react';
import './App.css';
-class App extends Component {
+class App extends PureComponent {
render() {
return (
);
}
diff --git a/src/index.tsx b/src/index.tsx
index 0c5e75d..ba76e2b 100755
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,12 +1,31 @@
import React from 'react';
import ReactDOM from 'react-dom';
+import { createStore } from 'redux';
+import { Provider } from 'react-redux';
+
+import { reducers } from './state';
+import * as WorkloadActions from './state/workloads/actions';
+
import './index.css';
import App from './App';
-import * as serviceWorker from './serviceWorker';
-ReactDOM.render(, document.getElementById('root'));
-// If you want your app to work offline and load faster, you can change
-// unregister() to register() below. Note this comes with some pitfalls.
-// Learn more about service workers: http://bit.ly/CRA-PWA
-serviceWorker.unregister();
+const store = createStore(reducers);
+
+store.subscribe(() => {
+ console.log(store.getState().workloads[0]);
+});
+
+store.dispatch(WorkloadActions.submit({ complexity: 100 }));
+store.dispatch(WorkloadActions.create({ workloadId: 0, complexity: 100, completeDate: new Date() }));
+store.dispatch(WorkloadActions.updateStatus({ workloadId: 0, status: 'SUCCESS' }));
+
+
+ReactDOM.render(
+ (
+
+
+
+ ),
+ document.getElementById('root'),
+);
diff --git a/src/logo.svg b/src/logo.svg
deleted file mode 100755
index 6b60c10..0000000
--- a/src/logo.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/src/serviceWorker.ts b/src/serviceWorker.ts
deleted file mode 100755
index c0b1310..0000000
--- a/src/serviceWorker.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-// This optional code is used to register a service worker.
-// register() is not called by default.
-
-// This lets the app load faster on subsequent visits in production, and gives
-// it offline capabilities. However, it also means that developers (and users)
-// will only see deployed updates on subsequent visits to a page, after all the
-// existing tabs open on the page have been closed, since previously cached
-// resources are updated in the background.
-
-// To learn more about the benefits of this model and instructions on how to
-// opt-in, read http://bit.ly/CRA-PWA
-
-const isLocalhost = Boolean(
- window.location.hostname === 'localhost' ||
- // [::1] is the IPv6 localhost address.
- window.location.hostname === '[::1]' ||
- // 127.0.0.1/8 is considered localhost for IPv4.
- window.location.hostname.match(
- /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
- )
-);
-
-type Config = {
- onSuccess?: (registration: ServiceWorkerRegistration) => void;
- onUpdate?: (registration: ServiceWorkerRegistration) => void;
-};
-
-export function register(config?: Config) {
- if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
- // The URL constructor is available in all browsers that support SW.
- const publicUrl = new URL(
- (process as { env: { [key: string]: string } }).env.PUBLIC_URL,
- window.location.href
- );
- if (publicUrl.origin !== window.location.origin) {
- // Our service worker won't work if PUBLIC_URL is on a different origin
- // from what our page is served on. This might happen if a CDN is used to
- // serve assets; see https://github.com/facebook/create-react-app/issues/2374
- return;
- }
-
- window.addEventListener('load', () => {
- const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
-
- if (isLocalhost) {
- // This is running on localhost. Let's check if a service worker still exists or not.
- checkValidServiceWorker(swUrl, config);
-
- // Add some additional logging to localhost, pointing developers to the
- // service worker/PWA documentation.
- navigator.serviceWorker.ready.then(() => {
- console.log(
- 'This web app is being served cache-first by a service ' +
- 'worker. To learn more, visit http://bit.ly/CRA-PWA'
- );
- });
- } else {
- // Is not localhost. Just register service worker
- registerValidSW(swUrl, config);
- }
- });
- }
-}
-
-function registerValidSW(swUrl: string, config?: Config) {
- navigator.serviceWorker
- .register(swUrl)
- .then(registration => {
- registration.onupdatefound = () => {
- const installingWorker = registration.installing;
- if (installingWorker == null) {
- return;
- }
- installingWorker.onstatechange = () => {
- if (installingWorker.state === 'installed') {
- if (navigator.serviceWorker.controller) {
- // At this point, the updated precached content has been fetched,
- // but the previous service worker will still serve the older
- // content until all client tabs are closed.
- console.log(
- 'New content is available and will be used when all ' +
- 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
- );
-
- // Execute callback
- if (config && config.onUpdate) {
- config.onUpdate(registration);
- }
- } else {
- // At this point, everything has been precached.
- // It's the perfect time to display a
- // "Content is cached for offline use." message.
- console.log('Content is cached for offline use.');
-
- // Execute callback
- if (config && config.onSuccess) {
- config.onSuccess(registration);
- }
- }
- }
- };
- };
- })
- .catch(error => {
- console.error('Error during service worker registration:', error);
- });
-}
-
-function checkValidServiceWorker(swUrl: string, config?: Config) {
- // Check if the service worker can be found. If it can't reload the page.
- fetch(swUrl)
- .then(response => {
- // Ensure service worker exists, and that we really are getting a JS file.
- const contentType = response.headers.get('content-type');
- if (
- response.status === 404 ||
- (contentType != null && contentType.indexOf('javascript') === -1)
- ) {
- // No service worker found. Probably a different app. Reload the page.
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister().then(() => {
- window.location.reload();
- });
- });
- } else {
- // Service worker found. Proceed as normal.
- registerValidSW(swUrl, config);
- }
- })
- .catch(() => {
- console.log(
- 'No internet connection found. App is running in offline mode.'
- );
- });
-}
-
-export function unregister() {
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister();
- });
- }
-}
diff --git a/src/state/index.ts b/src/state/index.ts
new file mode 100644
index 0000000..7732883
--- /dev/null
+++ b/src/state/index.ts
@@ -0,0 +1 @@
+export * from './reducers';
\ No newline at end of file
diff --git a/src/state/reducers.ts b/src/state/reducers.ts
new file mode 100644
index 0000000..a749678
--- /dev/null
+++ b/src/state/reducers.ts
@@ -0,0 +1,18 @@
+import { combineReducers } from 'redux';
+
+import {
+ Store as WorkloadsStore,
+ Action as WorkloadActions,
+ reducer as workloadReducer,
+} from './workloads';
+
+
+export type Action = WorkloadActions;
+
+export interface Store {
+ workloads: WorkloadsStore;
+}
+
+export const reducers = combineReducers({
+ workloads: workloadReducer,
+});
diff --git a/src/state/workloads/actions.ts b/src/state/workloads/actions.ts
new file mode 100644
index 0000000..9ef264d
--- /dev/null
+++ b/src/state/workloads/actions.ts
@@ -0,0 +1,70 @@
+import { Status } from './types';
+
+export type Action = {
+ type: 'WORKLOAD_SUBMIT';
+ payload: {
+ complexity: number;
+ };
+} | {
+ type: 'WORKLOAD_CREATE';
+ payload: {
+ workloadId: number;
+ complexity: number;
+ completeDate: Date;
+ };
+} | {
+ type: 'WORKLOAD_CANCEL';
+ payload: {
+ workloadId: number;
+ };
+} | {
+ type: 'WORKLOAD_CHECK_STATUS';
+ payload: {
+ workloadId: number;
+ };
+} | {
+ type: 'WORKLOAD_UPDATE_STATUS';
+ payload: {
+ workloadId: number;
+ status: Status;
+ };
+};
+
+export const submit = ({ complexity }: { complexity: number }): Action => ({
+ type: 'WORKLOAD_SUBMIT',
+ payload: {
+ complexity,
+ },
+});
+
+export const create = ({ workloadId, complexity, completeDate }: { workloadId: number, complexity: number, completeDate: Date }): Action => ({
+ type: 'WORKLOAD_CREATE',
+ payload: {
+ workloadId,
+ completeDate,
+ complexity,
+ },
+});
+
+export const cancel = ({ workloadId }: { workloadId: number }): Action => ({
+ type: 'WORKLOAD_CANCEL',
+ payload: {
+ workloadId,
+ },
+});
+
+export const checkStatus = ({ workloadId }: { workloadId: number }): Action => ({
+ type: 'WORKLOAD_CHECK_STATUS',
+ payload: {
+ workloadId,
+ },
+});
+
+export const updateStatus = ({ workloadId, status }: { workloadId: number, status: Status }): Action => ({
+ type: 'WORKLOAD_UPDATE_STATUS',
+ payload: {
+ workloadId,
+ status,
+ },
+});
+
diff --git a/src/state/workloads/index.ts b/src/state/workloads/index.ts
new file mode 100644
index 0000000..4398836
--- /dev/null
+++ b/src/state/workloads/index.ts
@@ -0,0 +1,2 @@
+export * from './actions';
+export * from './reducers';
diff --git a/src/state/workloads/reducers.ts b/src/state/workloads/reducers.ts
new file mode 100644
index 0000000..5f5dc58
--- /dev/null
+++ b/src/state/workloads/reducers.ts
@@ -0,0 +1,47 @@
+import { Action } from './actions';
+import { Status } from './types';
+
+interface Entry {
+ id: id;
+ completeDate: Date;
+ status: Status;
+}
+
+export type Store = {
+ [id in number]: Entry;
+};
+
+
+const initialState: Store = {};
+
+export const reducer = (state: Store = initialState, action: Action): Store => {
+ switch (action.type) {
+ case 'WORKLOAD_CREATE':
+ return {
+ [action.payload.workloadId]: {
+ id: action.payload.workloadId,
+ completeDate: action.payload.completeDate,
+ status: 'WORKING',
+ },
+ };
+
+ case 'WORKLOAD_CANCEL':
+ return {
+ [action.payload.workloadId]: {
+ ...state[action.payload.workloadId],
+ status: 'CANCELED',
+ },
+ }
+
+ case 'WORKLOAD_UPDATE_STATUS':
+ return {
+ [action.payload.workloadId]: {
+ ...state[action.payload.workloadId],
+ status: action.payload.status,
+ },
+ }
+
+ default:
+ return state;
+ }
+}
diff --git a/src/state/workloads/types.ts b/src/state/workloads/types.ts
new file mode 100644
index 0000000..9c6bc53
--- /dev/null
+++ b/src/state/workloads/types.ts
@@ -0,0 +1 @@
+export type Status = 'WORKING' | 'SUCCESS' | 'FAILURE' | 'CANCELED';
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index ca5a687..7a3e750 100755
--- a/yarn.lock
+++ b/yarn.lock
@@ -825,6 +825,13 @@
dependencies:
regenerator-runtime "^0.12.0"
+"@babel/runtime@^7.2.0":
+ version "7.3.1"
+ resolved "https://npm.nutterlogic.com/@babel%2fruntime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a"
+ integrity sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==
+ dependencies:
+ regenerator-runtime "^0.12.0"
+
"@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2":
version "7.2.2"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907"
@@ -928,6 +935,14 @@
dependencies:
"@types/react" "*"
+"@types/react-redux@^7.0.1":
+ version "7.0.1"
+ resolved "https://npm.nutterlogic.com/@types%2freact-redux/-/react-redux-7.0.1.tgz#9dd2503be7a9861c5a092bf1c5050b7ade4dc62e"
+ integrity sha512-+DIH7TI2MT4Ke4lOrRMgNy//DzTDIzv5QwkJSD6AVrlsIgzf7yMM0JoWL5wJUXYwKQ2f1FgvwlvIVGD2QWQnew==
+ dependencies:
+ "@types/react" "*"
+ redux "^4.0.0"
+
"@types/react@*", "@types/react@16.7.22":
version "16.7.22"
resolved "https://npm.nutterlogic.com/@types%2freact/-/react-16.7.22.tgz#5bc6d166d5ac34b835756f0b736c7b1af0043e81"
@@ -4397,6 +4412,13 @@ hoek@4.x.x:
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
integrity sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==
+hoist-non-react-statics@^3.2.1:
+ version "3.3.0"
+ resolved "https://npm.nutterlogic.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
+ integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
+ dependencies:
+ react-is "^16.7.0"
+
home-or-tmp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
@@ -5942,7 +5964,7 @@ loglevel@^1.4.1:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=
-loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -7936,7 +7958,7 @@ react-dev-utils@^7.0.1:
strip-ansi "4.0.0"
text-table "0.2.0"
-react-dom@16.7.0:
+react-dom@^16.7.0:
version "16.7.0"
resolved "https://npm.nutterlogic.com/react-dom/-/react-dom-16.7.0.tgz#a17b2a7ca89ee7390bc1ed5eb81783c7461748b8"
integrity sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==
@@ -7951,6 +7973,23 @@ react-error-overlay@^5.1.2:
resolved "https://npm.nutterlogic.com/react-error-overlay/-/react-error-overlay-5.1.2.tgz#888957b884d4b25b083a82ad550f7aad96585394"
integrity sha512-7kEBKwU9R8fKnZJBRa5RSIfay4KJwnYvKB6gODGicUmDSAhQJ7Tdnll5S0RLtYrzRfMVXlqYw61rzrSpP4ThLQ==
+react-is@^16.6.3, react-is@^16.7.0:
+ version "16.7.0"
+ resolved "https://npm.nutterlogic.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa"
+ integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g==
+
+react-redux@^6.0.0:
+ version "6.0.0"
+ resolved "https://npm.nutterlogic.com/react-redux/-/react-redux-6.0.0.tgz#09e86eeed5febb98e9442458ad2970c8f1a173ef"
+ integrity sha512-EmbC3uLl60pw2VqSSkj6HpZ6jTk12RMrwXMBdYtM6niq0MdEaRq9KYCwpJflkOZj349BLGQm1MI/JO1W96kLWQ==
+ dependencies:
+ "@babel/runtime" "^7.2.0"
+ hoist-non-react-statics "^3.2.1"
+ invariant "^2.2.4"
+ loose-envify "^1.4.0"
+ prop-types "^15.6.2"
+ react-is "^16.6.3"
+
react-scripts@2.1.3:
version "2.1.3"
resolved "https://npm.nutterlogic.com/react-scripts/-/react-scripts-2.1.3.tgz#6e49be279f4039fb9f330d2b3529b933b8e90945"
@@ -8006,7 +8045,7 @@ react-scripts@2.1.3:
optionalDependencies:
fsevents "1.2.4"
-react@16.7.0:
+react@^16.7.0:
version "16.7.0"
resolved "https://npm.nutterlogic.com/react/-/react-16.7.0.tgz#b674ec396b0a5715873b350446f7ea0802ab6381"
integrity sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==
@@ -8105,6 +8144,14 @@ recursive-readdir@2.2.2:
dependencies:
minimatch "3.0.4"
+redux@^4.0.0:
+ version "4.0.1"
+ resolved "https://npm.nutterlogic.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5"
+ integrity sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==
+ dependencies:
+ loose-envify "^1.4.0"
+ symbol-observable "^1.2.0"
+
regenerate-unicode-properties@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c"
@@ -9107,6 +9154,11 @@ svgo@^1.0.0, svgo@^1.0.5:
unquote "~1.1.1"
util.promisify "~1.0.0"
+symbol-observable@^1.2.0:
+ version "1.2.0"
+ resolved "https://npm.nutterlogic.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
+ integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
+
symbol-tree@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"