diff --git a/public/control-panel.html b/public/control-panel.html index ba810fd..2e0d978 100644 --- a/public/control-panel.html +++ b/public/control-panel.html @@ -10,14 +10,14 @@ @@ -37,6 +37,7 @@

Large
Small
+ diff --git a/public/index.html b/public/index.html index 60701a4..9cb3a1b 100644 --- a/public/index.html +++ b/public/index.html @@ -13,21 +13,22 @@ Productivity App

Welcome to the Flux-Redux Productivity App!

diff --git a/public/message-board.html b/public/message-board.html index 2b4e91c..f003cdd 100644 --- a/public/message-board.html +++ b/public/message-board.html @@ -2,43 +2,38 @@ - Productivity App - Message Board - + Productivity App - Control Panel + - +
+

Message Board

-
+
- - - - - -
-
+
- - \ No newline at end of file + + + \ No newline at end of file diff --git a/public/tasks.html b/public/tasks.html index 58e3fc4..f360f40 100644 --- a/public/tasks.html +++ b/public/tasks.html @@ -2,49 +2,45 @@ - Productivity App - Tasks - - - + Productivity App - Control Panel + - + -

Tasks

-

- Welcome, Jim! -

+
+

Tasks

+
- +
- -
-
- -
+
+ +
+ \ No newline at end of file diff --git a/src/control-panel.js b/src/control-panel.js index 6a977ec..be3faad 100644 --- a/src/control-panel.js +++ b/src/control-panel.js @@ -10,15 +10,26 @@ const userNameUpdateAction = (name)=>{ type: UPDATE_USERNAME, value: name } -} +}; const fontSizePreferenceUpdateAction = (size)=>{ return { type: UPDATE_FONT_SIZE_PREFERENCE, value: size } -} -// +}; + +document.forms.fontSizeForm.fontSize.forEach(element=>{ + element.addEventListener("change",({target})=>{ + controlPanelDispatcher.dispatch(fontSizePreferenceUpdateAction(target.value)); + }) +}); + +document.getElementById(`userNameInput`).addEventListener("input",({target})=>{ + const name = target.value; + controlPanelDispatcher.dispatch(userNameUpdateAction(name)); +}); + class UserPrefsStore extends Store { getInitialState() { return localStorage[`preferences`] ? JSON.parse(localStorage[`preferences`]) : { @@ -44,35 +55,17 @@ class UserPrefsStore extends Store { } const userPrefsStore = new UserPrefsStore(controlPanelDispatcher); -const userNameInput = document.getElementById(`userNameInput`); -userNameInput.addEventListener("input",({target})=>{ - const name = target.value; - controlPanelDispatcher.dispatch(userNameUpdateAction(name)); -}); -const fontSizeForm = document.forms.fontSizeForm; - -fontSizeForm.fontSize.forEach(element=>{ - element.addEventListener("change",({target})=>{ - console.log("Buton change...",target.value); - controlPanelDispatcher.dispatch(fontSizePreferenceUpdateAction(target.value)); - }) +userPrefsStore.addListener((state)=>{ + console.info(`Updated Store`,state); + render(state); + localStorage[`preferences`] = JSON.stringify(state); }); const render = ({userName,fontSize})=>{ document.getElementById("userName").innerText = userName; document.getElementsByClassName("container")[0].style.fontSize = fontSize === "small" ? "16px" : "24px"; - fontSizeForm.fontSize.value = fontSize; - -} - -userPrefsStore.addListener((state)=>{ - render(state); - saveUserPreferences(state); -}); - -const saveUserPreferences =(state)=>{ - localStorage[`preferences`] = JSON.stringify(state); + document.forms.fontSizeForm.fontSize.value = fontSize; } -render(userPrefsStore.getUserPreferences()); \ No newline at end of file +render(userPrefsStore.getUserPreferences()); diff --git a/src/flux/ReduceStore.js b/src/flux/ReduceStore.js index 0392af1..65b920e 100644 --- a/src/flux/ReduceStore.js +++ b/src/flux/ReduceStore.js @@ -1,24 +1,26 @@ import {Store} from './Store'; export class ReduceStore extends Store { - constructor(dispatcher){ + constructor(dispatcher) { super(dispatcher); this.__history = []; } - reduce(state,action){ + + reduce(state, action) { throw new Error("Subclasses must implement reduce method of a Flux ReduceStore"); } - __onDispatch(action){ - const newState = this.reduce(this.__state,action); + + __onDispatch(action) { + const newState = this.reduce(this.__state, action); if (newState !== this.__state) { this.__history.push(this.__state); this.__state = newState; this.__emitChange(); } } - revertLastState(){ + + revertLastState() { if (this.__history.length > 0) this.__state = this.__history.pop(); this.__emitChange(); } - } \ No newline at end of file diff --git a/src/message-board.js b/src/message-board.js index b256c23..1c6a8e2 100644 --- a/src/message-board.js +++ b/src/message-board.js @@ -2,42 +2,30 @@ import { createStore, combineReducers, applyMiddleware } from 'redux' import { get } from './http'; import logger from 'redux-logger'; + export const ONLINE = `ONLINE`; export const AWAY = `AWAY`; export const BUSY = `BUSY`; -export const CREATE_NEW_MESSAGE = `CREATE_NEW_MESSAGE`; -export const NEW_MESSAGE_SERVER_ACCEPTED = `NEW_MESSAGE_SERVER_ACCEPTED`; export const UPDATE_STATUS = `UPDATE_STATUS`; export const OFFLINE = `OFFLINE`; +export const CREATE_NEW_MESSAGE = `CREATE_NEW_MESSAGE`; +export const NEW_MESSAGE_SERVER_ACCEPTED = `NEW_MESSAGE_SERVER_ACCEPTED`; export const READY = `READY`; export const WAITING = `WAITING`; -const defaultState = { - messages:[{ - date:new Date('2016-10-10 10:11:55'), - postedBy:`Stan`, - content:`I <3 the new productivity app!` - },{ - date:new Date('2016-10-10 10:12:00'), - postedBy:`Jerry`, - content:`I don't know if the new version of Bootstrap is really better...` - },{ - date:new Date('2016-10-10 12:06:04'), - postedBy:`Llewlyn`, - content:`Anyone got tickets to ng-conf?` - }], - userStatus: ONLINE, - apiCommunicationStatus: READY -} +const statusUpdateAction = (value)=>{ + return { + type: UPDATE_STATUS, + value + } +} -const newMessageAction = (content, postedBy, dispatch)=>{ +const newMessageAction = (content, postedBy)=>{ const date = new Date(); - // TODO... add asnychronicity to this action creator - get('/api/create',(id=>{ store.dispatch({ type: NEW_MESSAGE_SERVER_ACCEPTED, @@ -56,22 +44,37 @@ const newMessageAction = (content, postedBy, dispatch)=>{ } } -const statusUpdateAction = (value)=>{ - return { - type: UPDATE_STATUS, - value - } + + +const defaultState = { + messages:[{ + date:new Date('2016-10-10 10:11:55'), + postedBy:`Stan`, + content:`I <3 the new productivity app!` + },{ + date:new Date('2016-10-10 10:12:00'), + postedBy:`Jerry`, + content:`I don't know if the new version of Bootstrap is really better...` + },{ + date:new Date('2016-10-10 12:06:04'), + postedBy:`Llewlyn`, + content:`Anyone got tickets to ng-conf?` + }], + userStatus: ONLINE, + apiCommunicationStatus: READY } -const userStatusReducer = (state = ONLINE, {type, value}) => { + + +const userStatusReducer = (state = defaultState.userStatus, {type, value}) => { switch (type) { case UPDATE_STATUS: return value; } return state; -} +}; -const apiCommunicationStatusReducer = (state = READY, {type}) => { +const apiCommunicationStatusReducer = (state = defaultState.apiCommunicationStatus, {type}) => { switch (type) { case CREATE_NEW_MESSAGE: return WAITING; @@ -82,10 +85,10 @@ const apiCommunicationStatusReducer = (state = READY, {type}) => { } -const messageReducer = (state = defaultState.messages, {type, value, postedBy, date}) => { +const messagesReducer = (state = defaultState.messages, {type,value,postedBy,date})=>{ switch (type) { case CREATE_NEW_MESSAGE: - const newState = [ { date: date, postedBy, content: value } , ... state ] + const newState = [ { date: date, postedBy, content: value } , ... state ]; return newState; } return state; @@ -93,9 +96,9 @@ const messageReducer = (state = defaultState.messages, {type, value, postedBy, d const combinedReducer = combineReducers({ userStatus: userStatusReducer, - messages: messageReducer, + messages: messagesReducer, apiCommunicationStatus: apiCommunicationStatusReducer -}) +}); const store = createStore( combinedReducer, @@ -110,13 +113,16 @@ const render = ()=>{
${message.postedBy} : ${message.content}
` - )).join(""); + )).join(""); document.forms.newMessage.newMessage.value = ""; document.forms.newMessage.fields.disabled = (userStatus === OFFLINE) || (apiCommunicationStatus === WAITING); - } +document.forms.selectStatus.status.addEventListener("change",(e)=>{ + store.dispatch(statusUpdateAction(e.target.value)); +}); + document.forms.newMessage.addEventListener("submit",(e)=>{ e.preventDefault(); const value = e.target.newMessage.value; @@ -124,10 +130,6 @@ document.forms.newMessage.addEventListener("submit",(e)=>{ store.dispatch(newMessageAction(value, username)); }); -document.forms.selectStatus.status.addEventListener("change",(e)=>{ - store.dispatch(statusUpdateAction(e.target.value)); -}) - render(); -store.subscribe(render) \ No newline at end of file +store.subscribe(render); \ No newline at end of file diff --git a/src/server/index.js b/src/server/index.js deleted file mode 100644 index 542a0d5..0000000 --- a/src/server/index.js +++ /dev/null @@ -1,11 +0,0 @@ -const express = require('express'); -const app = express(); -app.get('/createMessage',(req,res)=>{ - res.json({"abc":"def"}); -}); - -app.use(require('cors')()); -app.listen(`7777`,()=>{ - console.log("Server initialize"); -}) - diff --git a/src/tasks.js b/src/tasks.js index 62fb293..a7a473c 100644 --- a/src/tasks.js +++ b/src/tasks.js @@ -1,11 +1,11 @@ -import { generate as id } from 'shortid'; import { Dispatcher, ReduceStore } from './flux'; -// import $ from 'cheerio'; +import { generate as id } from 'shortid'; + const tasksDispatcher = new Dispatcher(); const CREATE_TASK = `CREATE_TASK`; -const COMPLETE_TASK = `COMPLETE_TASK` +const COMPLETE_TASK = `COMPLETE_TASK`; const SHOW_TASKS = `SHOW_TASKS`; const createNewTaskAction = (content)=>{ @@ -13,7 +13,7 @@ const createNewTaskAction = (content)=>{ type: CREATE_TASK, value: content } -} +}; const completeTaskAction = (id,isComplete)=>{ return { @@ -21,40 +21,43 @@ const completeTaskAction = (id,isComplete)=>{ id, value: isComplete } -} +}; const showTasksAction = (show)=>{ return { type: SHOW_TASKS, value: show } -} +}; + +const initialState = { + tasks: [{ + id: id(), + content: "Update CSS styles", + complete: false + }, { + id: id(), + content: "Add unit tests", + complete: false + }, { + id: id(), + content: "Post to social media", + complete: false + },{ + id: id(), + content: "Install hard drive", + complete: true + }], + showComplete:true +}; class TasksStore extends ReduceStore { getInitialState() { - return { - tasks: [{ - id: id(), - content: "Update CSS styles", - complete: false - }, { - id: id(), - content: "Add unit tests", - complete: false - }, { - id: id(), - content: "Post to social media", - complete: false - },{ - id: id(), - content: "Install hard drive", - complete: true - }], - showComplete:true - }; + return initialState; } reduce(state,action){ let newState; + console.log("Processing action",action.type); switch(action.type) { case CREATE_TASK: newState = { ...state, tasks: [ ... state.tasks ]}; @@ -62,7 +65,7 @@ class TasksStore extends ReduceStore { id:id(), content:action.value, complete: false - }) + }); return newState; case COMPLETE_TASK: newState = { ... state, tasks: [ ... state.tasks ]}; @@ -82,13 +85,14 @@ class TasksStore extends ReduceStore { const tasksStore = new TasksStore(tasksDispatcher); -const TaskComponent = ({content,complete,id})=>( - `
+const render = () => { + + const TaskComponent = ({content,complete,id})=>( + `
${content}
` -) + ) -const render = () => { const tasksSection = document.getElementById(`tasks`); const state = tasksStore.getState(); const rendered = tasksStore.getState().tasks @@ -104,11 +108,7 @@ const render = () => { tasksDispatcher.dispatch(completeTaskAction(id,checked)); }) }); - - if (localStorage[`preferences`]) { - document.getElementById('userNameDisplay').innerHTML = JSON.parse(localStorage[`preferences`]).userName; - } -} +}; document.forms.newTask.addEventListener('submit',(e)=>{ e.preventDefault(); @@ -117,7 +117,7 @@ document.forms.newTask.addEventListener('submit',(e)=>{ tasksDispatcher.dispatch(createNewTaskAction(name)); e.target.newTaskName.value = null; } -}) +}); document.forms.undo.addEventListener('submit',(e)=>{ e.preventDefault(); @@ -127,10 +127,10 @@ document.forms.undo.addEventListener('submit',(e)=>{ document.getElementById(`showComplete`).addEventListener('change',({target})=>{ const showComplete = target.checked; tasksDispatcher.dispatch(showTasksAction(showComplete)); -}) +}); tasksStore.addListener(()=>{ render(); -}) +}); render(); \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 326fc90..e21da13 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,16 +1,4 @@ const path = require('path'); -// function MyPlugin() { -// // Configure your plugin with options... -// } -// -// MyPlugin.prototype.apply = function(compiler) { -// compiler.plugin("compile", function(params) { -// require('./src/server'); -// }); -// }; -// -// module.exports = MyPlugin; -// require('./src/server'); module.exports = { module: { loaders: [ @@ -32,9 +20,9 @@ module.exports = { ] }, entry: { - cpanel: ["./src/control-panel.js"], - "message-board": ["./src/message-board.js"], - tasks: ["./src/tasks.js"] + "cpanel": ["./src/control-panel.js"], + "tasks": ["./src/tasks.js"], + "message-board": ["./src/message-board.js"] }, output: { path: path.resolve(__dirname, "public"), @@ -43,8 +31,4 @@ module.exports = { }, devServer: { inline: true }, devtool: 'source-map', - // plugins: [ - // new MyPlugin() - // ] - } \ No newline at end of file