├── public
└── index.html
├── webpack.config.js
├── README.md
├── package.json
├── .gitignore
├── LICENSE
├── index.js
└── src
└── index.js
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: __dirname + '/src',
3 | output: {
4 | path: '/'
5 | },
6 | devtool: 'source-maps',
7 | module: {
8 | loaders: [
9 | {
10 | test: /\.js$/,
11 | loader: 'babel',
12 | query: {
13 | presets: ['es2015', 'react'],
14 | plugins: ['transform-class-properties']
15 | }
16 | }
17 | ]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nyc-react-meetup-message-board
2 |
3 | Demo code from the NYC React Meetup on April 28th, 2016.
4 |
5 | ## Installation
6 |
7 | ```bash
8 | git clone git@github.com:eddiezane/nyc-react-meetup-message-board.git
9 | cd nyc-react-meetup-message-board
10 | npm install
11 | ```
12 |
13 | To get the SMS bit working sign up for a free [Twilio account](https://twilio.com/try-twilio).
14 |
15 | Start up [ngrok](https://ngrok.com/) and point your [Twilio Phone Number](https://www.twilio.com/user/account/phone-numbers/incoming) at your ngrok URL.
16 |
17 |
18 | ## Usage
19 |
20 | Start the app:
21 |
22 | ```bash
23 | node .
24 | ```
25 |
26 | Start [ngrok](https://ngrok.io) in a separate shell:
27 |
28 | ```bash
29 | ngrok http 3000
30 | ```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "message-board",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "Eddie Zaneski",
11 | "license": "MIT",
12 | "dependencies": {
13 | "babel-core": "^6.7.7",
14 | "babel-loader": "^6.2.4",
15 | "babel-plugin-transform-class-properties": "^6.6.0",
16 | "babel-preset-es2015": "^6.6.0",
17 | "babel-preset-react": "^6.5.0",
18 | "body-parser": "^1.15.0",
19 | "express": "^4.13.4",
20 | "react": "^15.0.1",
21 | "react-dom": "^15.0.1",
22 | "socket.io": "^1.4.5",
23 | "webpack": "^1.13.0",
24 | "webpack-dev-middleware": "^1.6.1"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/node
3 |
4 | ### Node ###
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 |
15 | # Directory for instrumented libs generated by jscoverage/JSCover
16 | lib-cov
17 |
18 | # Coverage directory used by tools like istanbul
19 | coverage
20 |
21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
22 | .grunt
23 |
24 | # node-waf configuration
25 | .lock-wscript
26 |
27 | # Compiled binary addons (http://nodejs.org/api/addons.html)
28 | build/Release
29 |
30 | # Dependency directories
31 | node_modules
32 | jspm_packages
33 |
34 | # Optional npm cache directory
35 | .npm
36 |
37 | # Optional REPL history
38 | .node_repl_history
39 |
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Eddie Zaneski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const http = require('http')
3 | const bodyParser = require('body-parser')
4 | const socketIo = require('socket.io')
5 | const webpack = require('webpack')
6 | const webpackDevMiddleware = require('webpack-dev-middleware')
7 | const webpackConfig = require('./webpack.config.js')
8 |
9 | const app = express()
10 | const server = http.createServer(app)
11 | const io = socketIo(server)
12 |
13 | app.use(express.static(__dirname + '/public'))
14 | app.use(webpackDevMiddleware(webpack(webpackConfig)))
15 | app.use(bodyParser.urlencoded({ extended: false }))
16 |
17 | app.post('/', (req, res) => {
18 | const { Body, From, MediaUrl0 } = req.body
19 | const message = {
20 | body: Body,
21 | from: From.slice(8),
22 | img: MediaUrl0
23 | }
24 | io.emit('message', message)
25 | res.send(`
26 |
27 | Thanks for texting!
28 |
29 | `)
30 | })
31 |
32 | io.on('connection', socket => {
33 | socket.on('message', body => {
34 | socket.broadcast.emit('message', {
35 | body,
36 | from: socket.id.slice(8)
37 | })
38 | })
39 | })
40 |
41 | server.listen(3000)
42 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import io from 'socket.io-client'
4 |
5 | class App extends React.Component {
6 | constructor (props) {
7 | super(props)
8 | this.state = { messages: [] }
9 | }
10 |
11 | componentDidMount () {
12 | this.socket = io('/')
13 | this.socket.on('message', message => {
14 | this.setState({ messages: [message, ...this.state.messages] })
15 | })
16 | }
17 |
18 | handleSubmit = event => {
19 | const body = event.target.value
20 | if (event.keyCode === 13 && body) {
21 | const message = {
22 | body,
23 | from: 'Me'
24 | }
25 | this.setState({ messages: [message, ...this.state.messages] })
26 | this.socket.emit('message', body)
27 | event.target.value = ''
28 | }
29 | }
30 |
31 | render () {
32 | const messages = this.state.messages.map((message, index) => {
33 | const img = message.img ?
: null
34 | return {message.from}:{message.body} {img}
35 | })
36 | return (
37 |
38 |
ez.ngrok.io
39 | +18622562970
40 |
41 | {messages}
42 |
43 | )
44 | }
45 | }
46 |
47 | ReactDOM.render(, document.getElementById('root'))
48 |
--------------------------------------------------------------------------------