Repository: tabvn/nodejs-reactjs-chatapp Branch: master Commit: 4ff49c675885 Files: 45 Total size: 131.9 KB Directory structure: gitextract_xpe_08_e/ ├── .gitignore ├── README.md ├── app/ │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── docker-compose.yml │ ├── package.json │ ├── public/ │ │ ├── index.html │ │ └── manifest.json │ └── src/ │ ├── components/ │ │ ├── app.js │ │ ├── messenger.js │ │ ├── search-user.js │ │ ├── user-bar.js │ │ ├── user-form.js │ │ └── user-menu.js │ ├── config.js │ ├── css/ │ │ ├── .sass-cache/ │ │ │ └── c6c61f1d3471adfa6b4f36ea934cb8d28f43b0b7/ │ │ │ ├── _font.scssc │ │ │ ├── _variable.scssc │ │ │ └── app.scssc │ │ ├── _font.scss │ │ ├── _variable.scss │ │ ├── app.css │ │ └── app.scss │ ├── helpers/ │ │ ├── index.js │ │ └── objectid.js │ ├── index.js │ ├── realtime.js │ ├── registerServiceWorker.js │ ├── service.js │ └── store.js ├── deployment-to-digitalocean-hosting.md └── server/ ├── Dockerfile ├── docker-compose.yml ├── package.json └── src/ ├── app-router.js ├── database.js ├── helper.js ├── index.js ├── models/ │ ├── channel.js │ ├── connection.js │ ├── index.js │ ├── message.js │ ├── token.js │ └── user.js └── www/ └── index.html ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .idea .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* server/node_modules app/node_modules server/dist server/package-lock.json app/node_modules app/package-lock.json ================================================ FILE: README.md ================================================ # nodejs-reactjs-chatapp Create messenger chat application use Nodejs Expressjs, Reactjs. ## Screenshot: ## Server ``` cd server ``` ``` npm install ``` ``` npm run dev ``` ### Reactjs App development ``` cd app ``` ``` npm start ``` ### Reactjs App development using docker-compose The docker-compose files are located in the two different application folders app and server. To run all the functions using docker run the follow commands: ``` cd server ``` ``` docker-compose up ``` At this moment the server application side will be running. Now it's time to run application front end. Open a new terminal (window or tab) and in the project folder use the following commands: ``` cd app ``` ``` docker-compose up ``` Attention: Deppending on the way you have installed the docker in your compile you may use **sudo** command to run docker, for example: ``` sudo docker-compose up ``` For more docker informations and how to install access https://www.docker.com/ . ## Tutorials * Checkout the video toturials list: https://www.youtube.com/playlist?list=PLFaW_8zE4amPaLyz5AyVT8B_wfOYwd8x8 * My Facebook: https://www.facebook.com/TabvnGroup/ * Youtube Chanel: https://youtube.com/tabvn ## Deploy Node.js React.js to DigitalOcean.com Ubuntu 16.04 Cloud VPS * Document * Video: https://www.youtube.com/watch?v=wJsH45eWNBo ================================================ FILE: app/.gitignore ================================================ # See https://help.github.com/ignore-files/ for more about ignoring files. # dependencies /node_modules # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: app/Dockerfile ================================================ FROM node:11.12.0 # Install a bunch of node modules that are commonly used. #ADD package.json /usr/app/ ADD . /usr/app/ EXPOSE 80 ENV BIND_HOST=0.0.0.0 CMD ["npm", "start"] WORKDIR /usr/app RUN npm install ================================================ FILE: app/README.md ================================================ ## Start app ``` npm install ``` ``` npm start ``` ================================================ FILE: app/docker-compose.yml ================================================ version: '3' services: app: build: . ports: - "3000:3000" command: npm start ================================================ FILE: app/package.json ================================================ { "name": "my-app", "version": "0.1.0", "private": true, "dependencies": { "axios": "^0.17.1", "classnames": "^2.2.5", "immutable": "^3.8.2", "lodash": "^4.17.4", "moment": "^2.19.2", "react": "^16.1.1", "react-dom": "^16.1.1", "react-scripts": "1.0.17" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" } } ================================================ FILE: app/public/index.html ================================================ React App
================================================ FILE: app/public/manifest.json ================================================ { "short_name": "React App", "name": "Create React App Sample", "icons": [ { "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" } ], "start_url": "./index.html", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" } ================================================ FILE: app/src/components/app.js ================================================ import React, {Component} from 'react' import Store from '../store' import Messenger from './messenger' export default class App extends Component{ constructor(props){ super(props); this.state = { store: new Store(this), } } render(){ const {store} = this.state; return
} } ================================================ FILE: app/src/components/messenger.js ================================================ import React, {Component} from 'react' import classNames from 'classnames' import {OrderedMap} from 'immutable' import _ from 'lodash' import {ObjectID} from '../helpers/objectid' import SearchUser from './search-user' import moment from 'moment' import UserBar from './user-bar' export default class Messenger extends Component { constructor(props) { super(props); this.state = { height: window.innerHeight, newMessage: 'Hello there...', searchUser: "", showSearchUser: false, } this._onResize = this._onResize.bind(this); this.handleSend = this.handleSend.bind(this) this.renderMessage = this.renderMessage.bind(this); this.scrollMessagesToBottom = this.scrollMessagesToBottom.bind(this) this._onCreateChannel = this._onCreateChannel.bind(this); this.renderChannelTitle = this.renderChannelTitle.bind(this) this.renderChannelAvatars = this.renderChannelAvatars.bind(this); } renderChannelAvatars(channel){ const {store} = this.props; const members = store.getMembersFromChannel(channel); const maxDisplay = 4; const total = members.size > maxDisplay ? maxDisplay : members.size; const avatars = members.map((user, index) => { return index < maxDisplay ? {_.get(user, : null }); return
{avatars}
} renderChannelTitle(channel = null) { if (!channel) { return null; } const {store} = this.props; const members = store.getMembersFromChannel(channel); const names = []; members.forEach((user) => { const name = _.get(user, 'name'); names.push(name); }) let title = _.join(names, ','); if (!title && _.get(channel, 'isNew')) { title = 'New message'; } return

{title}

} _onCreateChannel() { const {store} = this.props; const currentUser = store.getCurrentUser(); const currentUserId = _.get(currentUser, '_id'); const channelId = new ObjectID().toString(); const channel = { _id: channelId, title: '', lastMessage: "", members: new OrderedMap(), messages: new OrderedMap(), isNew: true, userId: currentUserId, created: new Date(), }; channel.members = channel.members.set(currentUserId, true); store.onCreateNewChannel(channel); } scrollMessagesToBottom() { if (this.messagesRef) { this.messagesRef.scrollTop = this.messagesRef.scrollHeight; } } renderMessage(message) { const text = _.get(message, 'body', ''); const html = _.split(text, '\n').map((m, key) => { return

}) return html; } handleSend() { const {newMessage} = this.state; const {store} = this.props; // create new message if (_.trim(newMessage).length) { const messageId = new ObjectID().toString(); const channel = store.getActiveChannel(); const channelId = _.get(channel, '_id', null); const currentUser = store.getCurrentUser(); const message = { _id: messageId, channelId: channelId, body: newMessage, userId: _.get(currentUser, '_id'), me: true, }; store.addMessage(messageId, message); this.setState({ newMessage: '', }) } } _onResize() { this.setState({ height: window.innerHeight }); } componentDidUpdate() { this.scrollMessagesToBottom(); } componentDidMount() { window.addEventListener('resize', this._onResize); } componentWillUnmount() { window.removeEventListener('resize', this._onResize) } render() { const {store} = this.props; const {height} = this.state; const style = { height: height, }; const activeChannel = store.getActiveChannel(); const messages = store.getMessagesFromChannel(activeChannel); //store.getMessages(); const channels = store.getChannels(); const members = store.getMembersFromChannel(activeChannel); return (

Messenger

{_.get(activeChannel, 'isNew') ?
{ members.map((user, key) => { return { store.removeMemberFromChannel(activeChannel, user); }} key={key}>{_.get(user, 'name')} }) } { const searchUserText = _.get(event, 'target.value'); //console.log("searching for user with name: ", searchUserText) this.setState({ searchUser: searchUserText, showSearchUser: true, }, () => { store.startSearchUsers(searchUserText); }); }} type="text" value={this.state.searchUser}/> {this.state.showSearchUser ? { this.setState({ showSearchUser: false, searchUser: '', }, () => { const userId = _.get(user, '_id'); const channelId = _.get(activeChannel, '_id'); store.addUserToChannel(channelId, userId); }); }} store={store}/> : null}
: this.renderChannelTitle(activeChannel)}
{channels.map((channel, key) => { return (
{ store.setActiveChannelId(channel._id); }} key={channel._id} className={classNames('chanel', {'notify': _.get(channel, 'notify') === true},{'active': _.get(activeChannel, '_id') === _.get(channel, '_id', null)})}>
{this.renderChannelAvatars(channel)}
{this.renderChannelTitle(channel)}

{channel.lastMessage}

) })}
this.messagesRef = ref} className="messages"> {messages.map((message, index) => { const user = _.get(message, 'user'); return (
{message.me ? 'You ' : _.get(message, 'user.name')} says:
{this.renderMessage(message)}
) })}
{activeChannel && members.size > 0 ?