Created
June 23, 2016 17:00
-
-
Save xRahul/eb6da744407a28d0b76d34773ab659b7 to your computer and use it in GitHub Desktop.
Collaborative List
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title> | |
Stickers | |
</title> | |
</head> | |
<body> | |
<div id="app"></div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// required variables and functions | |
const render = ReactDOM.render | |
const Redux = window.Redux | |
const Provider = ReactRedux.Provider | |
const createStore = Redux.createStore | |
const applyMiddleware = Redux.applyMiddleware | |
const combineReducers = Redux.combineReducers | |
const bindActionCreators = Redux.bindActionCreators | |
const ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; | |
const compose = Redux.compose | |
const ReduxThunk = window.ReduxThunk.default | |
const Component = React.Component | |
const PropTypes = React.PropTypes | |
const connect = ReactRedux.connect | |
const classnames = window.classNames | |
const LOGIN_USER = 'LOGIN_USER' | |
const LOGOUT_USER = 'LOGOUT_USER' | |
const UPDATE_INPUT_USER = 'UPDATE_INPUT_USER' | |
const ADD_LIST_ITEM = 'ADD_LIST_ITEM' | |
const CLEAR_INPUT_LIST = 'CLEAR_INPUT_LIST' | |
const UPDATE_LIST_ITEM_INPUT = 'UPDATE_LIST_ITEM_INPUT' | |
const SET_SERVER_LIST = 'SET_SERVER_LIST' | |
const UPDATE_INPUT_CHANNEL = 'UPDATE_INPUT_CHANNEL' | |
const publish_key = 'pub-c-e0e9015b-6735-400c-bb06-452845e74f1b'; | |
const subscribe_key = 'sub-c-6c42cea2-3702-11e6-a207-02ee2ddab7fe'; | |
let pubnub; | |
// reducer | |
function userData (state = { | |
authenticated: false, | |
inputUsername: '', | |
username: (localStorage.getItem('username')) ? (localStorage.getItem('username')) : '', | |
channel: (localStorage.getItem('channel')) ? (localStorage.getItem('channel')) : '', | |
inputChannel: '' | |
}, action) { | |
switch (action.type) { | |
case UPDATE_INPUT_USER: | |
return Object.assign({}, state, { | |
inputUsername: action.inputText | |
}) | |
case UPDATE_INPUT_CHANNEL: | |
return Object.assign({}, state, { | |
inputChannel: action.inputText | |
}) | |
case LOGIN_USER: | |
return Object.assign({}, state, { | |
username: state.inputUsername, | |
channel: state.inputChannel, | |
inputUsername: '', | |
inputChannel: '', | |
authenticated: true | |
}) | |
case LOGOUT_USER: | |
return Object.assign({}, state, { | |
username: '', | |
channel: '', | |
inputUsername: state.username, | |
inputChannel: state.channel, | |
authenticated: false | |
}) | |
default: | |
return state | |
} | |
} | |
function listData (state = { | |
list: [], | |
inputList: '' | |
}, action) { | |
switch (action.type) { | |
case ADD_LIST_ITEM: | |
return Object.assign({}, state, { | |
list: [ | |
action.listItem, | |
...state.list | |
] | |
}) | |
case CLEAR_INPUT_LIST: | |
return Object.assign({}, state, { | |
inputList: '' | |
}) | |
case UPDATE_LIST_ITEM_INPUT: | |
return Object.assign({}, state, { | |
inputList: action.listItem | |
}) | |
case SET_SERVER_LIST: | |
return Object.assign({}, state, { | |
list: action.list | |
}) | |
default: | |
return state | |
} | |
} | |
// actions | |
function login(username){ | |
localStorage.setItem("username", username) | |
return { | |
type: LOGIN_USER | |
} | |
} | |
function logout(){ | |
return (dispatch, getState) => { | |
localStorage.removeItem("username") | |
pubnub.unsubscribe({ | |
channel : getState().userData.channel, | |
}) | |
pubnub = '' | |
dispatch({type: LOGOUT_USER}) | |
} | |
} | |
function updateInputUsername(username){ | |
return { | |
type: UPDATE_INPUT_USER, | |
inputText: username | |
} | |
} | |
function updateInputChannel(channel){ | |
return { | |
type: UPDATE_INPUT_CHANNEL, | |
inputText: channel | |
} | |
} | |
function clearInputListItem() { | |
return { | |
type: CLEAR_INPUT_LIST | |
} | |
} | |
function addLocalListItem(listItem) { | |
return (dispatch, getState) => { | |
const state = getState() | |
const username = state.userData.username | |
const channel = state.userData.channel | |
const item = listItem | |
pubnub.publish({ | |
channel: channel, | |
message: {username, item}, | |
callback: () => dispatch(clearInputListItem()) // resetting the text field | |
}) | |
} | |
} | |
function updateInputListItem(listItem) { | |
return { | |
type: UPDATE_LIST_ITEM_INPUT, | |
listItem: listItem | |
} | |
} | |
function addPubnubListItem(item) { | |
return { | |
type: ADD_LIST_ITEM, | |
listItem: item | |
} | |
} | |
function setServerList(li) { | |
li[0].reverse() | |
return { | |
type: SET_SERVER_LIST, | |
list: li[0] | |
} | |
} | |
function getPubnubHistory() { | |
console.log("here"); | |
return (dispatch, getState) => { | |
pubnub.history({ | |
channel: getState().userData.channel, | |
count: 50, | |
callback: (li) => { | |
console.log(li) | |
dispatch(setServerList(li)) | |
} | |
}) | |
} | |
} | |
function initializePubNub() { | |
return (dispatch,getState) => { | |
const state = getState() | |
const username = state.userData.username | |
const channel = state.userData.channel | |
pubnub = PUBNUB.init({ | |
publish_key : publish_key, | |
subscribe_key : subscribe_key, | |
ssl: true, | |
uuid: username | |
}) | |
pubnub.subscribe({ | |
channel: channel, | |
restore: true, | |
connect: () => dispatch(getPubnubHistory()), | |
message: (m) => dispatch(addPubnubListItem(m)) | |
}) | |
} | |
} | |
class Auth extends Component { | |
render() { | |
const {authenticated, submitUsername, updateInputUsername, | |
inputUsername, username, logout, | |
updateInputChannel, inputChannel, channel} = this.props | |
return ( | |
<div className="jumbotron"> | |
{!authenticated && | |
<form className="form-inline" | |
onSubmit={(e) => { | |
e.preventDefault() | |
submitUsername(this.refs.inputUsernameRef.value) | |
}} > | |
<div className="form-group"> | |
<label for="username">{"Username: "}</label> | |
<input | |
type="text" id="username" | |
className="form-control" | |
placeholder="Enter your username" | |
value={inputUsername} | |
ref="inputUsernameRef" | |
onChange={() => updateInputUsername(this.refs.inputUsernameRef.value)} | |
/> | |
</div> | |
{' '} | |
<div className="form-group"> | |
<label for="channel">{"List Name: "}</label> | |
<input | |
type="text" id="channel" | |
className="form-control" | |
placeholder="Enter your list name" | |
value={inputChannel} | |
ref="inputChannelRef" | |
onChange={() => updateInputChannel(this.refs.inputChannelRef.value)} | |
/> | |
</div> | |
<button type="submit" className="btn btn-default"> | |
Login | |
</button> | |
</form> | |
} | |
{authenticated && | |
<div> | |
<div> | |
<h2>Hello, {username}</h2> | |
<button className="btn btn-default" | |
onClick={() => logout()} > | |
Logout | |
</button> | |
</div> | |
<div> | |
<h3>List: {channel}</h3> | |
</div> | |
</div> | |
} | |
</div> | |
) | |
} | |
} | |
class ListInput extends Component { | |
render() { | |
const { submitListItem, inputList, updateInputList } = this.props | |
return ( | |
<form className="form-inline col-xs-12" | |
onSubmit={(e) => { | |
e.preventDefault() | |
submitListItem(this.refs.inputListRef.value) | |
}} > | |
<div className="form-group"> | |
<label for="listInput">{"New Item: "}</label> | |
<input | |
type="text" id="listInput" | |
className="form-control" | |
placeholder="Enter your list item" | |
value={inputList} | |
ref="inputListRef" | |
onChange={() => updateInputList(this.refs.inputListRef.value)} | |
/> | |
</div> | |
<button type="submit" className="btn btn-default"> | |
Add | |
</button> | |
</form> | |
) | |
} | |
} | |
class CollabList extends Component { | |
render() { | |
const { list } = this.props | |
const listView = list.map( | |
(listObject, index) => { | |
console.log(typeof listObject) | |
if(typeof listObject === 'string') { | |
return ( | |
<li key={index} className="list-group-item"> | |
{listObject} | |
</li> | |
) | |
} else { | |
return ( | |
<li key={index} className="list-group-item"> | |
<span className="badge"> | |
{listObject.username} | |
</span> | |
{listObject.item} | |
</li> | |
) | |
} | |
} | |
) | |
return ( | |
<div className="col-xs-12"> | |
<ul className="list-group"> | |
{listView} | |
</ul> | |
</div> | |
) | |
} | |
} | |
class List extends Component { | |
componentWillMount() { | |
this.props.initializePubNub() | |
} | |
render() { | |
const { submitListItem, inputList, | |
updateInputList, list } = this.props | |
return ( | |
<div className="jumbotron"> | |
<ListInput | |
submitListItem = {submitListItem} | |
inputList = {inputList} | |
updateInputList = {updateInputList} | |
/> | |
<br /> | |
<CollabList | |
list = {list} | |
/> | |
<div className="clearfix"></div> | |
</div> | |
) | |
} | |
} | |
class App extends Component { | |
render() { | |
const { authenticated, inputUsername, username, | |
submitUsername, updateInputUsername, logout, | |
submitListItem, inputList, updateInputList, | |
initializePubNub, list, | |
updateInputChannel, inputChannel, channel } = this.props | |
return ( | |
<div className="container"> | |
<div className="jumbotron"> | |
<h1>Collaborate and create list</h1> | |
</div> | |
<Auth | |
authenticated = {authenticated} | |
submitUsername = {submitUsername} | |
updateInputUsername = {updateInputUsername} | |
updateInputChannel = {updateInputChannel} | |
inputUsername = {inputUsername} | |
inputChannel = {inputChannel} | |
username = {username} | |
logout = {logout} | |
channel = {channel} | |
/> | |
{authenticated && | |
<List | |
username = {username} | |
submitListItem = {submitListItem} | |
inputList = {inputList} | |
updateInputList = {updateInputList} | |
initializePubNub = {initializePubNub} | |
list = {list} | |
channel = {channel} | |
/> | |
} | |
</div> | |
) | |
} | |
} | |
// helper functions for app container | |
function mapStateToProps(state) { | |
const { userData, listData } = state | |
return { | |
...userData, | |
...listData | |
} | |
} | |
function mapDispatchToProps(dispatch) { | |
return { | |
submitUsername: (username) => dispatch(login(username)), | |
updateInputUsername: (inputuser) => dispatch(updateInputUsername(inputuser)), | |
updateInputChannel: (inputchannel) => dispatch(updateInputChannel(inputchannel)), | |
logout: () => dispatch(logout()), | |
submitListItem: (listItem) => dispatch(addLocalListItem(listItem)), | |
updateInputList: (listItem) => dispatch(updateInputListItem(listItem)), | |
initializePubNub: (username) => dispatch(initializePubNub(username)), | |
} | |
} | |
// create app container using connect() | |
const AppContainer = connect(mapStateToProps, mapDispatchToProps)(App) | |
// create store using middlewares | |
const rootReducer = combineReducers({ | |
userData, | |
listData | |
}) | |
let store = createStore( | |
rootReducer, | |
compose( | |
applyMiddleware(ReduxThunk), | |
window.devToolsExtension ? window.devToolsExtension() : f => f | |
) | |
) | |
// render the app to the page | |
render( | |
<Provider store={store}> | |
<AppContainer /> | |
</Provider> | |
,document.getElementById('app')); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script> | |
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> | |
<script src="https://fb.me/react-with-addons-15.1.0.js"></script> | |
<script src="https://fb.me/react-dom-15.1.0.min.js"></script> | |
<script src="https://npmcdn.com/redux@3.5.2/dist/redux.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/4.4.5/react-redux.min.js"></script> | |
<script src="https://npmcdn.com/redux-thunk@2.0.1/dist/redux-thunk.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.min.js"></script> | |
<script src="https://cdn.bootcss.com/string.js/3.3.1/string.min.js"></script> | |
<script src="https://cdn.pubnub.com/pubnub-3.15.1.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
margin-top: 5em; | |
font-family: 'Josefin Sans', sans-serif; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" /> | |
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment