Skip to content

Instantly share code, notes, and snippets.

@xRahul
Created June 23, 2016 17:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xRahul/eb6da744407a28d0b76d34773ab659b7 to your computer and use it in GitHub Desktop.
Save xRahul/eb6da744407a28d0b76d34773ab659b7 to your computer and use it in GitHub Desktop.
Collaborative List
<html>
<head>
<title>
Stickers
</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
// 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'));
<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>
body {
margin-top: 5em;
font-family: 'Josefin Sans', sans-serif;
}
<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