+
{name}
{status} {company && at {company}}
-
{location && {location}}
-
+
{location && {location}}
+
View Profile
+
{skills.slice(0, 4).map((skill, index) => (
- -
- {skill}
+
-
+ {skill}
))}
@@ -36,7 +56,15 @@ const ProfileItem = ({
};
ProfileItem.propTypes = {
- profile: PropTypes.object.isRequired
+ sendFriendRequest: PropTypes.func.isRequired,
+ profile: PropTypes.object.isRequired,
+ auth: PropTypes.object.isRequired,
};
-export default ProfileItem;
+const mapStateToProps = state => ({
+ auth: state.auth,
+});
+
+export default connect(mapStateToProps, {
+ sendFriendRequest,
+})(ProfileItem);
diff --git a/client/src/utils/socketClient.js b/client/src/utils/socketClient.js
new file mode 100644
index 0000000..4b77533
--- /dev/null
+++ b/client/src/utils/socketClient.js
@@ -0,0 +1,2 @@
+import io from 'socket.io-client';
+export const socket = io('http://localhost:5000');
diff --git a/config/default.json b/config/default.json
index 1c210b2..d689216 100755
--- a/config/default.json
+++ b/config/default.json
@@ -1,6 +1,6 @@
{
- "mongoURI": "",
+ "mongoURI": "mongodb+srv://salih123:salih123@devconnector-tc7ou.mongodb.net/test?retryWrites=true&w=majority",
"jwtSecret": "secret",
"githubClientId": "",
"githubSecret": ""
-}
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 964b915..ed16aa0 100755
--- a/package.json
+++ b/package.json
@@ -20,7 +20,8 @@
"gravatar": "^1.8.0",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.7.5",
- "request": "^2.88.0"
+ "request": "^2.88.0",
+ "socket.io": "^2.3.0"
},
"devDependencies": {
"concurrently": "^4.1.0",
diff --git a/routes/api/profile.js b/routes/api/profile.js
index a9bf229..10f8fce 100755
--- a/routes/api/profile.js
+++ b/routes/api/profile.js
@@ -436,7 +436,7 @@ router.post('/friend/:id', auth, async (req, res) => {
return res.json({ msg: `Your friend request is successfully sent to ${receiver.name}` }); // @Todo
}
- return res.status(500).json({ msg: 'Server error' });
+ return res.status(404).json({ msg: 'Not found' });
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
diff --git a/server.js b/server.js
index ed72f71..01ad66d 100755
--- a/server.js
+++ b/server.js
@@ -1,24 +1,26 @@
+const path = require('path');
const express = require('express');
const connectDB = require('./config/db');
-const path = require('path');
const app = express();
// Connect Database
+
connectDB();
// Init Middleware
app.use(express.json({ extended: false }));
// Define Routes
+
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
app.use('/api/posts', require('./routes/api/posts'));
-// Serve static assets in production
+//Serve static assets in production
if (process.env.NODE_ENV === 'production') {
- // Set static folder
+ //Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
@@ -26,6 +28,8 @@ if (process.env.NODE_ENV === 'production') {
});
}
-const PORT = process.env.PORT || 5000;
+module.exports = app;
+const server = require('./socketIO');
-app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
+const PORT = process.env.PORT || 5000;
+server.listen(PORT, () => console.log(`Server started on port ${PORT}`));
diff --git a/socketIO.js b/socketIO.js
new file mode 100644
index 0000000..a9167d4
--- /dev/null
+++ b/socketIO.js
@@ -0,0 +1,47 @@
+const http = require('http');
+const socketio = require('socket.io');
+const app = require('./server');
+const server = http.createServer(app);
+const io = socketio(server);
+const {
+ addSocketClient,
+ removeSocketClient,
+ getSocketClient,
+ getReceiverSocketId,
+} = require('./utils/friend');
+
+io.on('connection', socket => {
+ console.log('New WebSocket connection', socket.id);
+
+ socket.on('sendAuth', senderId => {
+ addSocketClient({ id: socket.id, senderId });
+ });
+
+ socket.on('friendRequest', ({ senderName, senderId, receiverName, receiverId }) => {
+ const socketClient = getSocketClient(socket.id);
+ socketClient.senderName = senderName;
+ socketClient.senderId = senderId;
+ socketClient.receiverName = receiverName;
+ socketClient.receiverId = receiverId;
+
+ const { socketClientId, error } = getReceiverSocketId(socketClient.receiverId);
+ console.log('status', socketClient, error);
+
+ if (!error) {
+ io.to(socketClientId).emit('newFriendRequest', {
+ socketClientId,
+ senderId,
+ senderName,
+ receiverId,
+ receiverName,
+ });
+ }
+ });
+
+ socket.on('disconnect', function() {
+ removeSocketClient(socket.id);
+ console.log('user disconnected');
+ });
+});
+
+module.exports = server;
diff --git a/utils/deneme.js b/utils/deneme.js
new file mode 100644
index 0000000..085eace
--- /dev/null
+++ b/utils/deneme.js
@@ -0,0 +1,28 @@
+const obj = [
+ {
+ id: '8Che_3fRd0ZzAZvkAAAE',
+ senderName: 'Salih',
+ senderId: '5dc464f7e3f7002e22da54ac',
+ receiverName: 'Salih',
+ receiverId: '5dc464f7e3f7002e22da54ac',
+ },
+ {
+ id: '8Che_3fRd0ZzAZvkAAAE',
+ senderName: 'Salih',
+ senderId: '5dc464f7e3f7002e22da54ac',
+ receiverName: 'test',
+ receiverId: '5dc5edf78aeb2f1bc224db2b',
+ },
+];
+
+const recId = '5dc5edf78aeb2f1bc224db2b';
+
+const getReceiverSocket = () => {
+ const get = obj.find(el => {
+ return el.receiverId === recId;
+ });
+ return get.id;
+};
+const a = getReceiverSocket();
+
+console.log(a);
diff --git a/utils/friend.js b/utils/friend.js
new file mode 100644
index 0000000..c1d3eb5
--- /dev/null
+++ b/utils/friend.js
@@ -0,0 +1,44 @@
+const socketClients = [];
+
+const addSocketClient = ({ id, senderName, senderId, receiverName, receiverId }) => {
+ // Store user
+ const socketClient = { id, senderName, senderId, receiverName, receiverId };
+
+ socketClients.push(socketClient);
+ return { socketClient };
+};
+
+const removeSocketClient = id => {
+ const index = socketClients.findIndex(socket => socket.id === id);
+
+ if (index !== -1) {
+ return socketClients.splice(index, 1)[0];
+ }
+};
+
+const getSocketClient = id => socketClients.find(socket => socket.id === id);
+
+const getSocketClients = () => {
+ return socketClients.map(socket => {
+ return socket;
+ });
+};
+
+const getReceiverSocketId = receiverId => {
+ try {
+ const obj = socketClients.find(socket => {
+ return socket.senderId === receiverId;
+ });
+ return { socketClientId: obj.id };
+ } catch (err) {
+ return { error: 'Not Online' };
+ }
+};
+
+module.exports = {
+ addSocketClient,
+ removeSocketClient,
+ getSocketClient,
+ getReceiverSocketId,
+ getSocketClients,
+};
From 7972d0de9c2436d115adfd8a13a9615b232eec35 Mon Sep 17 00:00:00 2001
From: Salih
Date: Sat, 7 Dec 2019 12:22:36 +0100
Subject: [PATCH 7/8] chat app and friend request combined
---
client/public/index.html | 9 +
client/src/App.css | 165 ++++++++++++++++++
client/src/App.js | 6 +-
client/src/actions/auth.js | 11 +-
client/src/actions/chat.js | 22 +++
client/src/actions/types.js | 3 +
client/src/components/chat/App.js | 32 ++++
client/src/components/chat/Chat.js | 147 ++++++++++++++++
client/src/components/chat/Messages.js | 47 +++++
client/src/components/chat/UserList.js | 37 ++++
client/src/components/dashboard/Dashboard.js | 4 -
.../components/dashboard/DashboardActions.js | 17 +-
client/src/components/friends/FriendItem.js | 53 ++++++
client/src/components/friends/Friends.js | 57 ++++++
client/src/components/friends/RequestItem.js | 60 +++++++
client/src/components/friends/WaitingItem.js | 49 ++++++
client/src/components/layout/Navbar.js | 50 +++---
client/src/components/posts/FriendPosts.js | 51 ++++++
client/src/components/profiles/ProfileItem.js | 110 ++++++++----
client/src/components/profiles/Profiles.js | 22 +--
client/src/components/routing/Routes.js | 28 +--
client/src/reducers/chat.js | 33 ++++
client/src/reducers/index.js | 4 +-
client/src/utils/socketClient.js | 55 ++++++
models/User.js | 9 +
routes/api/profile.js | 58 ++++--
socketIO.js | 94 ++++++++--
utils/deneme.js | 28 ---
utils/friend.js | 14 +-
utils/users.js | 45 +++++
30 files changed, 1157 insertions(+), 163 deletions(-)
create mode 100644 client/src/actions/chat.js
create mode 100644 client/src/components/chat/App.js
create mode 100644 client/src/components/chat/Chat.js
create mode 100644 client/src/components/chat/Messages.js
create mode 100644 client/src/components/chat/UserList.js
create mode 100644 client/src/components/friends/FriendItem.js
create mode 100644 client/src/components/friends/Friends.js
create mode 100644 client/src/components/friends/RequestItem.js
create mode 100644 client/src/components/friends/WaitingItem.js
create mode 100644 client/src/components/posts/FriendPosts.js
create mode 100644 client/src/reducers/chat.js
delete mode 100644 utils/deneme.js
create mode 100644 utils/users.js
diff --git a/client/public/index.html b/client/public/index.html
index d9069be..675099b 100755
--- a/client/public/index.html
+++ b/client/public/index.html
@@ -11,6 +11,15 @@
integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
crossorigin="anonymous"
/>
+
+
+
Welcome To DevConnector
diff --git a/client/src/App.css b/client/src/App.css
index 0957f54..20bebb2 100755
--- a/client/src/App.css
+++ b/client/src/App.css
@@ -488,6 +488,25 @@ button {
margin-bottom: 0.5rem;
}
+/* Friends Page */
+.friend-card {
+ border: #ccc solid 1px;
+ background: var(--light-color);
+ display: grid;
+ grid-template-columns: 1fr 5fr 2fr;
+ align-items: center;
+ grid-gap: 0rem;
+ padding: 0.5rem 1rem;
+ line-height: 1.3;
+}
+
+.friend-name-card {
+ border-right: #ccc solid 1px;
+ border-left: #ccc solid 1px;
+ font-size: 1.2rem;
+ padding-left: 2rem;
+}
+
/* Mobile Styles */
@media (max-width: 700px) {
.container {
@@ -574,4 +593,150 @@ button {
.post button {
padding: 0.3rem 0.4rem;
}
+
+ /* Friends page */
+ .friend-card {
+ grid-template-columns: 1fr;
+ text-align: center;
+ align-items: left;
+ padding: 0.5rem;
+ }
+
+ .friend-card img {
+ width: 25%;
+ margin: 0.5rem auto;
+ }
+
+ .friend-name-card {
+ border: #ccc solid 1px;
+ }
+}
+
+/* Live Chat Component Styles */
+
+.chat-user-container {
+ background-color: #343a40;
+ width: 20%;
+ position: fixed;
+ top: 60px;
+ right: 0;
+ bottom: 0;
+ margin: 0;
+ padding: 0;
+}
+.chat-user-container h6 {
+ color: #0c9463;
+ font-family: 'Roboto', sans-serif;
+ font-size: 1.5rem;
+ background-color: #2d334a65;
+}
+.active.grey {
+ background-color: #454b52;
+}
+.chat-user {
+ color: white;
+ text-transform: capitalize;
+}
+
+.chat.room {
+ background-color: #851515 !important;
+}
+.chat-room .friend-list li {
+ border-bottom: 1px solid #e0e0e0;
+}
+.chat-room .friend-list li:last-of-type {
+ border-bottom: none;
+}
+
+.chat-room img.avatar {
+ height: 3rem;
+ width: 3rem;
+ border-radius: 50% !important;
+}
+
+.chat-room .text-small {
+ font-size: 0.95rem;
+}
+
+.chat-room .text-smaller {
+ font-size: 0.75rem;
+}
+
+.z-depth-1 {
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12) !important;
+}
+
+.chat-body {
+ padding: 1.5rem !important;
+ width: 20rem;
+ line-height: 1.5;
+ font-family: 'Roboto', sans-serif;
+ color: #212529;
+ word-break: break-all;
+}
+
+.chat-body p {
+ padding: 0.75rem 0rem !important;
+}
+
+div.header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 0.5rem;
+}
+
+.primary-font {
+ color: #212529;
+ font-weight: 700;
+ margin-right: 1rem;
+}
+
+.pull-right {
+ color: #6c757d !important;
+
+ font-weight: 300;
+}
+
+.chat-footer p {
+ color: greenyellow;
+}
+
+.user-chat-box {
+ flex-flow: row;
+}
+
+.guest-chat-box {
+ flex-flow: row-reverse;
+}
+
+.chat-input {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ background-color: whitesmoke;
+ padding: 16px 32px;
+ text-decoration: none;
+ margin: 4px;
+ border-radius: 5px;
+ width: 60%;
+ height: 60px;
+ border: 1px solid #0c7c80;
+}
+.chat-send-button {
+ position: fixed;
+ background-color: rgb(15, 112, 192);
+ width: 10%;
+ height: 60px;
+ bottom: 0;
+ right: 25%;
+ border-radius: 5px;
+ margin: 4px;
+ border: 1px solid #0c7c80;
+ color: white;
+ transition: 0.15s all ease-in;
+}
+
+.chat-send-button:hover {
+ color: white;
+ background-color: #343a40;
}
diff --git a/client/src/App.js b/client/src/App.js
index a93ffac..6fdc11c 100755
--- a/client/src/App.js
+++ b/client/src/App.js
@@ -10,6 +10,8 @@ import store from './store';
import { loadUser } from './actions/auth';
import setAuthToken from './utils/setAuthToken';
+import { socketClient } from './utils/socketClient';
+
import './App.css';
if (localStorage.token) {
@@ -18,8 +20,10 @@ if (localStorage.token) {
const App = () => {
useEffect(() => {
+ socketClient();
store.dispatch(loadUser());
- }, []);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [loadUser]);
return (
diff --git a/client/src/actions/auth.js b/client/src/actions/auth.js
index 93d25dd..fcf55a4 100755
--- a/client/src/actions/auth.js
+++ b/client/src/actions/auth.js
@@ -11,7 +11,7 @@ import {
CLEAR_PROFILE,
} from './types';
import setAuthToken from '../utils/setAuthToken';
-import { socket } from '../utils/socketClient';
+import { socketEmit, socketActions } from '../utils/socketClient';
// Load User
export const loadUser = () => async dispatch => {
@@ -26,7 +26,7 @@ export const loadUser = () => async dispatch => {
type: USER_LOADED,
payload: res.data,
});
- socket.emit('sendAuth', res.data._id);
+ socketEmit(res);
} catch (err) {
dispatch({
type: AUTH_ERROR,
@@ -109,6 +109,8 @@ export const logout = () => dispatch => {
export const sendFriendRequest = id => async dispatch => {
try {
const res = await axios.post(`/api/profile/friend/${id}`);
+
+ socketActions(res, 'sendFriendRequest');
dispatch(loadUser());
dispatch(setAlert(res.data.msg, 'success'));
} catch (err) {
@@ -119,28 +121,29 @@ export const sendFriendRequest = id => async dispatch => {
export const acceptFriendRequest = id => async dispatch => {
try {
const res = await axios.put(`/api/profile/friend/${id}`);
+ socketActions(res, 'acceptFriendRequest');
dispatch(loadUser());
dispatch(setAlert(res.data.msg, 'success'));
} catch (err) {
dispatch(setAlert(err.response.data.msg, 'danger'));
}
};
-
// Cancel Friend Request api/profile/friend/:senderId
export const cancelFriendRequest = id => async dispatch => {
try {
const res = await axios.patch(`/api/profile/friend/${id}`);
+ socketActions(res, 'cancelFriendRequest');
dispatch(loadUser());
dispatch(setAlert(res.data.msg, 'success'));
} catch (err) {
dispatch(setAlert(err.response.data.msg, 'danger'));
}
};
-
// Remove Friend api/profile/friend/:senderId
export const removeFriend = id => async dispatch => {
try {
const res = await axios.delete(`/api/profile/friend/${id}`);
+ socketActions(res, 'removeFriend');
dispatch(loadUser());
dispatch(setAlert(res.data.msg, 'success'));
} catch (err) {
diff --git a/client/src/actions/chat.js b/client/src/actions/chat.js
new file mode 100644
index 0000000..359eb6d
--- /dev/null
+++ b/client/src/actions/chat.js
@@ -0,0 +1,22 @@
+import { USERLIST_ADD, USERNAME_ADD, MESSAGE_ADD } from './types';
+
+export const receiveUsername = data => {
+ return {
+ type: USERNAME_ADD,
+ payload: data,
+ };
+};
+
+export const receiveUsers = data => {
+ return {
+ type: USERLIST_ADD,
+ payload: data,
+ };
+};
+
+export const receiveMessage = data => {
+ return {
+ type: MESSAGE_ADD,
+ payload: data,
+ };
+};
diff --git a/client/src/actions/types.js b/client/src/actions/types.js
index 883c20e..a35335e 100755
--- a/client/src/actions/types.js
+++ b/client/src/actions/types.js
@@ -22,3 +22,6 @@ export const DELETE_POST = 'DELETE_POST';
export const ADD_POST = 'ADD_POST';
export const ADD_COMMENT = 'ADD_COMMENT';
export const REMOVE_COMMENT = 'REMOVE_COMMENT';
+export const USERNAME_ADD = 'USERNAME_ADD';
+export const USERLIST_ADD = 'USERLIST_ADD';
+export const MESSAGE_ADD = 'MESSAGE_ADD';
diff --git a/client/src/components/chat/App.js b/client/src/components/chat/App.js
new file mode 100644
index 0000000..5a9bb14
--- /dev/null
+++ b/client/src/components/chat/App.js
@@ -0,0 +1,32 @@
+import React, { Fragment } from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import Spinner from './../layout/Spinner';
+
+import Chat from './Chat';
+
+const App = ({ auth: { user }, chat }) => {
+ if (!user) {
+ return ;
+ }
+
+ if (!chat.userlist.length) {
+ }
+
+ const username = user.name;
+ const chatt = username ? : null;
+ return {chatt};
+};
+
+App.propTypes = {
+ auth: PropTypes.object
+};
+
+const mapStateToProps = state => ({
+ user: state.user,
+ auth: state.auth,
+ chat: state.chat
+
+});
+
+export default connect(mapStateToProps)(App);
diff --git a/client/src/components/chat/Chat.js b/client/src/components/chat/Chat.js
new file mode 100644
index 0000000..6cf839d
--- /dev/null
+++ b/client/src/components/chat/Chat.js
@@ -0,0 +1,147 @@
+import React, { useState, useEffect } from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { receiveUsers, receiveMessage, receiveUsername } from '../../actions/chat';
+
+import UserList from './UserList';
+import Messages from './Messages';
+import Spinner from '../layout/Spinner';
+import { socket } from './../../utils/socketClient';
+const Chat = ({ user, chat, receiveMessage, receiveUsers, receiveUsername }) => {
+ const username = user.name;
+ useEffect(() => {
+ receiveUsername([username, user._id]);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [username]);
+
+ const [formData, setFormData] = useState({
+ text: '',
+ });
+ const { text } = formData;
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const chatSocket = () => {
+ // receive userlist
+ socket.on('chat users', ({ room, users }) => {
+ receiveUsers({ room, users });
+ });
+
+ // send join message
+ socket.emit(
+ 'chat join',
+ {
+ timestamp: new Date(),
+ username,
+ userID: user._id,
+ userAvatar: user.avatar,
+ room: 'general',
+ },
+ error => {
+ if (error) {
+ return;
+ }
+ },
+ );
+
+ // receive join message
+ socket.on('chat join', msg => {
+ receiveMessage(msg);
+ });
+
+ // receive leave message
+ socket.on('chat leave', msg => {
+ receiveMessage(msg);
+ });
+
+ // receive message
+ socket.on('chat message', msg => {
+ receiveMessage(msg);
+ });
+
+ // send leave message when user leaves the page
+ window.addEventListener('beforeunload', e => {
+ e.preventDefault();
+
+ socket.emit('chat leave', {
+ timestamp: new Date(),
+ username,
+ userID: user._id,
+ room: 'general',
+ });
+ });
+ };
+ useEffect(() => {
+ chatSocket();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ // update state from input
+ const onChange = e => {
+ setFormData({ [e.target.name]: e.target.value });
+ };
+
+ const onSubmit = e => {
+ e.preventDefault();
+ // send message
+ socket.emit('chat message', {
+ timestamp: new Date(),
+ username,
+ message: text,
+ userAvatar: user.avatar,
+ });
+
+ setFormData({ text: '' });
+ };
+
+ return (
+
+
+
+
+
+
Members
+ {chat.userlist.users ? : }
+
+
+
+
+ );
+};
+
+Chat.propTypes = {
+ receiveUsers: PropTypes.func.isRequired,
+ receiveMessage: PropTypes.func.isRequired,
+ receiveUsername: PropTypes.func.isRequired,
+ auth: PropTypes.object,
+ chat: PropTypes.object,
+};
+
+const mapStateToProps = state => ({
+ chat: state.chat,
+ auth: state.auth,
+});
+
+export default connect(mapStateToProps, { receiveUsers, receiveMessage, receiveUsername })(Chat);
diff --git a/client/src/components/chat/Messages.js b/client/src/components/chat/Messages.js
new file mode 100644
index 0000000..ebca2f3
--- /dev/null
+++ b/client/src/components/chat/Messages.js
@@ -0,0 +1,47 @@
+import React, { useEffect, useRef } from 'react';
+import moment from 'moment';
+
+const Messages = ({ username, messages }) => {
+ const chat = useRef(null);
+
+ const chatMessages = messages.map((chat, key) => (
+
+
+
+
+ {chat.username}
+
+ {moment(chat.timestamp).fromNow()}
+
+
+
+
{chat.message}
+
+
+ ));
+
+ useEffect(() => {
+ if (chat.current) {
+ window.scrollTo(0, chat.current.scrollHeight);
+ }
+ }, [chatMessages]);
+
+ return (
+
+ );
+};
+
+export default Messages;
diff --git a/client/src/components/chat/UserList.js b/client/src/components/chat/UserList.js
new file mode 100644
index 0000000..e65338a
--- /dev/null
+++ b/client/src/components/chat/UserList.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+
+const UserList = ({ chatData: { messages, userlist, username } }) => {
+ const countUserMessage = messages.filter(msg => {
+ return msg.username === username[0];
+ });
+
+ const users = userlist.users.map((chatUser, key) => (
+
+
+
+
+
{chatUser.username}
+
{}
+
+
+
Online
+ {username[1] === chatUser.userID && (
+
{countUserMessage.length}
+ )}
+
+
+
+ ));
+ return (
+
+ );
+};
+
+export default UserList;
diff --git a/client/src/components/dashboard/Dashboard.js b/client/src/components/dashboard/Dashboard.js
index 6886a35..d0d45b5 100755
--- a/client/src/components/dashboard/Dashboard.js
+++ b/client/src/components/dashboard/Dashboard.js
@@ -7,7 +7,6 @@ import DashboardActions from './DashboardActions';
import Experience from './Experience';
import Education from './Education';
import { getCurrentProfile, deleteAccount } from '../../actions/profile';
-import { socket } from './../../utils/socketClient';
const Dashboard = ({
getCurrentProfile,
@@ -17,9 +16,6 @@ const Dashboard = ({
}) => {
useEffect(() => {
getCurrentProfile();
- socket.on('newFriendRequest', data => {
- console.log(data);
- });
}, [getCurrentProfile]);
return loading && profile === null ? (
diff --git a/client/src/components/dashboard/DashboardActions.js b/client/src/components/dashboard/DashboardActions.js
index 3a63e5d..17c46bd 100755
--- a/client/src/components/dashboard/DashboardActions.js
+++ b/client/src/components/dashboard/DashboardActions.js
@@ -3,15 +3,18 @@ import { Link } from 'react-router-dom';
const DashboardActions = () => {
return (
-
-
-
Edit Profile
+
+
+ Edit Profile
-
- Add Experience
+
+ Add Experience
-
- Add Education
+
+ Add Education
+
+
+ Friends
);
diff --git a/client/src/components/friends/FriendItem.js b/client/src/components/friends/FriendItem.js
new file mode 100644
index 0000000..27f5ec9
--- /dev/null
+++ b/client/src/components/friends/FriendItem.js
@@ -0,0 +1,53 @@
+import React from "react";
+import { Link } from "react-router-dom";
+import PropTypes from "prop-types";
+import { connect } from "react-redux";
+import { removeFriend } from "../../actions/auth";
+import Spinner from "../layout/Spinner";
+
+const FriendItem = ({ auth: { user, loading }, removeFriend }) => {
+ return loading && user === null ? (
+
+ ) : (
+ user.friendsList.map(friend => (
+
+

+
+
+ {friend.friendName}
+
+
+ View Profile
+
+
+
+
+
+ View Posts
+
+
+
+ ))
+ );
+};
+
+FriendItem.propTypes = {
+ removeFriend: PropTypes.func.isRequired,
+ auth: PropTypes.object.isRequired
+};
+const mapStateToProps = state => ({
+ auth: state.auth
+});
+
+export default connect(mapStateToProps, {
+ removeFriend
+})(FriendItem);
diff --git a/client/src/components/friends/Friends.js b/client/src/components/friends/Friends.js
new file mode 100644
index 0000000..15f3061
--- /dev/null
+++ b/client/src/components/friends/Friends.js
@@ -0,0 +1,57 @@
+import React, { Fragment, useEffect, useState } from 'react';
+import { Link } from 'react-router-dom';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import Spinner from '../layout/Spinner';
+import { loadUser } from '../../actions/auth';
+import FriendItem from './FriendItem';
+import RequestItem from './RequestItem';
+import WaitingItem from './WaitingItem';
+
+const Friends = ({ auth: { user, loading } }) => {
+ return loading && user === null ? (
+
+ ) : (
+
+ My Friends
+ {user.friendsList.length > 0 ? (
+
+ ) : (
+
+ You have no friends yet.
+
+ )}
+ My Requests
+
+ {user.request.length > 0 ? (
+
+ ) : (
+
+ You have no friendship requests.
+
+ )}
+ My Waiting List
+ {user.sentRequest.length > 0 ? (
+
+ ) : (
+
+
+ You have no pending requests.
+
+ )}
+
+ );
+};
+
+Friends.propTypes = {
+ loadUser: PropTypes.func.isRequired,
+ auth: PropTypes.object.isRequired,
+ profile: PropTypes.object.isRequired,
+};
+
+const mapStateToProps = state => ({
+ auth: state.auth,
+ profile: state.profile,
+});
+
+export default connect(mapStateToProps, { loadUser })(Friends);
diff --git a/client/src/components/friends/RequestItem.js b/client/src/components/friends/RequestItem.js
new file mode 100644
index 0000000..85c9e36
--- /dev/null
+++ b/client/src/components/friends/RequestItem.js
@@ -0,0 +1,60 @@
+import React from "react";
+import { Link } from "react-router-dom";
+import PropTypes from "prop-types";
+import { connect } from "react-redux";
+import { acceptFriendRequest, cancelFriendRequest } from "../../actions/auth";
+import Spinner from "../layout/Spinner";
+
+const RequestItem = ({
+ auth: { user, loading },
+ acceptFriendRequest,
+ cancelFriendRequest
+}) => {
+ return loading && user === null ? (
+
+ ) : (
+ user.request.map(req => (
+
+

+
+
+ {" "}
+ {req.username}
+
+
+ View Profile
+
+
+
+
+
+
+
+ ))
+ );
+};
+
+RequestItem.propTypes = {
+ acceptFriendRequest: PropTypes.func.isRequired,
+ cancelFriendRequest: PropTypes.func.isRequired,
+ auth: PropTypes.object.isRequired
+};
+const mapStateToProps = state => ({
+ auth: state.auth
+});
+
+export default connect(mapStateToProps, {
+ acceptFriendRequest,
+ cancelFriendRequest
+})(RequestItem);
diff --git a/client/src/components/friends/WaitingItem.js b/client/src/components/friends/WaitingItem.js
new file mode 100644
index 0000000..4eff81f
--- /dev/null
+++ b/client/src/components/friends/WaitingItem.js
@@ -0,0 +1,49 @@
+import React from "react";
+import { Link } from "react-router-dom";
+import PropTypes from "prop-types";
+import { connect } from "react-redux";
+import moment from "moment";
+import Moment from "react-moment";
+import Spinner from "../layout/Spinner";
+
+const WaitingItem = ({ auth: { user, loading } }) => {
+ return loading && user === null ? (
+
+ ) : (
+ user.sentRequest.map(req => (
+
+

+
+
+ {" "}
+ {req.username}
+
+
+ View Profile
+
+
+
+ -
+
+
+ -
+ Request sent at: {" "}
+ {moment.utc(req.date)}
+
+
+
+ ))
+ );
+};
+
+WaitingItem.propTypes = {
+ auth: PropTypes.object.isRequired
+};
+const mapStateToProps = state => ({
+ auth: state.auth
+});
+
+export default connect(mapStateToProps, {})(WaitingItem);
diff --git a/client/src/components/layout/Navbar.js b/client/src/components/layout/Navbar.js
index fa83c72..61a6c7a 100755
--- a/client/src/components/layout/Navbar.js
+++ b/client/src/components/layout/Navbar.js
@@ -3,26 +3,33 @@ import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { logout } from '../../actions/auth';
+import { receiveUsername } from '../../actions/chat';
-const Navbar = ({ auth: { isAuthenticated, loading }, logout }) => {
+const Navbar = ({ auth: { isAuthenticated, loading, user }, logout }) => {
+ const handleUser = () => {
+ receiveUsername(user.name);
+ };
const authLinks = (
@@ -31,41 +38,36 @@ const Navbar = ({ auth: { isAuthenticated, loading }, logout }) => {
const guestLinks = (
-
- Developers
+ Developers
-
- Register
+ Register
-
- Login
+ Login
);
return (
-