Skip to content

Commit

Permalink
Merge pull request #208 from boostcamp-2020/dev
Browse files Browse the repository at this point in the history
v0.0.7 배포
  • Loading branch information
bell-won committed Dec 20, 2020
2 parents 4018bee + 2370261 commit b4e4832
Show file tree
Hide file tree
Showing 27 changed files with 292 additions and 106 deletions.
24 changes: 14 additions & 10 deletions backend/chatServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createServer } from 'http'
import createChatServer from 'socket.io'
import { createChatMessage, createReplyMessage } from './service/chat'
import { addReaction, removeReaction } from './service/reaction'
import { SOCKET_EVENT } from './util/constant'
dotenv()

const server = createServer(express())
Expand All @@ -20,31 +21,34 @@ namespace.use((socket, next) => {
namespace.on('connection', socket => {
const { workspaceUserInfoId } = socket.handshake.query
socket.join(workspaceUserInfoId)
socket.on('invite channel', ({ channelId, origin, newMember }) => {
socket.on(SOCKET_EVENT.INVITE_CHANNEL, ({ channelId, origin, newMember }) => {
origin
.concat(newMember)
.forEach(member =>
namespace.in(member).emit('invited channel', { channelId, newMember }),
namespace
.in(member)
.emit(SOCKET_EVENT.INVITED_CHANNEL, { channelId, newMember }),
)
})
socket.on('new message', async data => {
socket.on(SOCKET_EVENT.NEW_MESSAGE, async data => {
const { contents, channelId, file } = data
const { data: result } = await createChatMessage({
creator: workspaceUserInfoId,
channelId,
contents,
file,
})
namespace.in(channelId).emit('new message', {
namespace.in(channelId).emit(SOCKET_EVENT.NEW_MESSAGE, {
message: {
...data,
_id: result._id,
createdAt: result.createdAt,
reactions: [],
reply: [],
},
})
})
socket.on('new reply', async data => {
socket.on(SOCKET_EVENT.NEW_REPLY, async data => {
const { contents, channelId, parentId, file } = data
const { data: result } = await createReplyMessage({
creator: workspaceUserInfoId,
Expand All @@ -53,7 +57,7 @@ namespace.on('connection', socket => {
parentId,
file,
})
namespace.in(channelId).emit('new reply', {
namespace.in(channelId).emit(SOCKET_EVENT.NEW_REPLY, {
message: {
...data,
_id: result._id,
Expand All @@ -63,7 +67,7 @@ namespace.on('connection', socket => {
},
})
})
socket.on('update reaction', async data => {
socket.on(SOCKET_EVENT.UPDAETE_REACTION, async data => {
const { emoji, chatId, userInfo, channelId, type, parentId } = data
//1 = add, 0 = remove
const result =
Expand All @@ -79,7 +83,7 @@ namespace.on('connection', socket => {
emoticon: emoji,
})

namespace.in(channelId).emit('update reaction', {
namespace.in(channelId).emit(SOCKET_EVENT.UPDAETE_REACTION, {
reaction: {
chatId: chatId,
emoji: emoji,
Expand All @@ -91,10 +95,10 @@ namespace.on('connection', socket => {
})
})

socket.on('join-room', (channelList = []) => {
socket.on(SOCKET_EVENT.JOIN_ROOM, (channelList = []) => {
socket.join(channelList)
})
socket.on('leave-room', roomId => {
socket.on(SOCKET_EVENT.LEAVE_ROOM, roomId => {
socket.leave(roomId)
})
})
Expand Down
1 change: 1 addition & 0 deletions backend/model/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const channelSchema = mongoose.Schema(
},
{ timestamps: true },
)
channelSchema.index({ workspaceId: 1, channelType: 1 })

channelSchema.statics.getChannelBrowserData = async function (
workspaceId,
Expand Down
3 changes: 3 additions & 0 deletions backend/model/ChannelConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ const channelConfigSchema = mongoose.Schema(
{ timestamps: true },
)

channelConfigSchema.index({ channelId: 1, workspaceUserInfoId: 1 })
channelConfigSchema.index({ workspaceUserInfoId: 1 })

channelConfigSchema.statics.getChannelHeaderInfo = async function (
channelId,
workspaceUserInfoId,
Expand Down
6 changes: 6 additions & 0 deletions backend/model/Chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ const chatSchema = mongoose.Schema(
},
{ timestamps: true },
)

chatSchema.index({ createdAt: 1, channel: 1 })
chatSchema.index({ channel: 1, parentId: 1 })
chatSchema.index({ pinned: 1 })
chatSchema.index({ parentId: 1 })

chatSchema.statics.getChatMessages = ({ channelId, currentCursor, fromDate }) =>
Chat.aggregate([
{ $sort: { createdAt: -1 } },
Expand Down
3 changes: 3 additions & 0 deletions backend/model/Reaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ const reactionSchema = mongoose.Schema({
type: String,
},
})
reactionSchema.index({ workspaceUserInfoId: 1, chatId: 1 })
reactionSchema.index({ chatId: 1 })

const Reaction = mongoose.model('Reaction', reactionSchema)
module.exports = { Reaction }
2 changes: 2 additions & 0 deletions backend/model/Workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ const workspaceSchema = mongoose.Schema(
},
{ timestamps: true },
)
workspaceSchema.index({ name: 1 })

const Workspace = mongoose.model('Workspace', workspaceSchema)
module.exports = { Workspace }
3 changes: 3 additions & 0 deletions backend/model/WorkspaceUserInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ const workspaceUserInfoSchema = mongoose.Schema(
{ timestamps: true },
)

workspaceUserInfoSchema.index({ workspaceId: 1, userId: 1 })
workspaceUserInfoSchema.index({ userId: 1 })

workspaceUserInfoSchema.statics.getWorkspaceUserInfo = async function (
workspaceUserInfoId,
) {
Expand Down
9 changes: 9 additions & 0 deletions backend/util/constant.js
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
export const MAX_CHAT_MESSAGE = 20
export const SOCKET_EVENT = {
INVITE_CHANNEL: 'invite channel',
INVITED_CHANNEL: 'invited channel',
NEW_MESSAGE: 'new message',
NEW_REPLY: 'new reply',
UPDAETE_REACTION: 'update reaction',
JOIN_ROOM: 'join room',
LEAVE_ROOM: 'leave room',
}
13 changes: 10 additions & 3 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"immer": "^8.0.0",
"qs": "^6.9.4",
"react": "^17.0.1",
"react-copy-to-clipboard": "^5.0.2",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.0",
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/api/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Request from '../util/request'

export const signOut = async () => {
const data = await Request.DELETE('/api/user/sign-out')
return data
}
9 changes: 9 additions & 0 deletions frontend/src/constant/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const SOCKET_EVENT = {
INVITE_CHANNEL: 'invite channel',
INVITED_CHANNEL: 'invited channel',
NEW_MESSAGE: 'new message',
NEW_REPLY: 'new reply',
UPDAETE_REACTION: 'update reaction',
JOIN_ROOM: 'join room',
LEAVE_ROOM: 'leave room',
}
7 changes: 3 additions & 4 deletions frontend/src/container/ChannelHeader/ChannelHeader.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import styled from 'styled-components'
import { useSetRecoilState } from 'recoil'
import { useSetRecoilState, useRecoilValue } from 'recoil'

import Icon from '../../presenter/Icon'
import { ADDUSER, INFOCIRCLE } from '../../constant/icon'
Expand All @@ -9,15 +9,14 @@ import ChannelStarBtn from '../ChannelStarBtn'
import ChannelPinBtn from '../../presenter/ChannelPinBtn'
import ChannelTopicBtn from '../../presenter/ChannelTopicBtn'
import ChannelMemberThumbnail from '../../presenter/ChannelMemberThumbnail'
import { modalRecoil } from '../../store'
import { modalRecoil, currentChannelInfoRecoil } from '../../store'
import InviteUserToChannelModal from '../Modal/InviteUserToChannelModal'
import { COLOR } from '../../constant/style'
import useChannelInfo from '../../hooks/useChannelInfo'
import { isEmpty } from '../../util'

function ChannelHeader() {
const setModal = useSetRecoilState(modalRecoil)
const [channelInfo] = useChannelInfo()
const channelInfo = useRecoilValue(currentChannelInfoRecoil)
const openAddUserModal = () => {
setModal(<InviteUserToChannelModal handleClose={() => setModal(null)} />)
}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/container/ChatMessage/ChatMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import ChatContent from '../../presenter/ChatContent'
import ThreadReactionList from '../../presenter/ThreadReactionList'
import ActionBar from '../ActionBar'
import ViewThreadButton from '../../presenter/Button/ViewThreadButton'
import { isEmpty, isImage } from '../../util'
import { isEmpty } from '../../util'
import { SIZE, COLOR } from '../../constant/style'
import { workspaceRecoil, socketRecoil } from '../../store'
import FilePreview from '../FilePreview'

import { SOCKET_EVENT } from '../../constant'
const ChatMessage = forwardRef(
(
{
Expand Down Expand Up @@ -45,7 +45,7 @@ const ChatMessage = forwardRef(
displayName: workspaceUserInfo.displayName,
},
}
socket.emit('update reaction', reaction)
socket.emit(SOCKET_EVENT.UPDAETE_REACTION, reaction)
}

const updateReactionHandler = emoji => {
Expand Down
58 changes: 45 additions & 13 deletions frontend/src/container/ChatRoom/ChatRoom.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import React, { useEffect, useState, useRef, useCallback } from 'react'
import styled from 'styled-components'
import { useParams } from 'react-router-dom'
import { useRecoilValue } from 'recoil'
import { useRecoilState, useRecoilValue } from 'recoil'
import ChatMessage from '../ChatMessage'
import { COLOR } from '../../constant/style'
import { getChatMessage } from '../../api/chat'
import MessageEditor from '../MessageEditor/MessageEditor'
import { workspaceRecoil, socketRecoil } from '../../store'
import {
workspaceRecoil,
socketRecoil,
currentChannelInfoRecoil,
} from '../../store'
import ChannelHeader from '../ChannelHeader'
import { isEmpty } from '../../util'
import { hasMyReaction, chageReactionState } from '../../util/reactionUpdate'
import useChannelInfo from '../../hooks/useChannelInfo'
import Icon from '../../presenter/Icon'
import { ArrowDown } from '../../constant/icon'
import { getChannelHeaderInfo } from '../../api/channel'
import { SOCKET_EVENT } from '../../constant'

const ChatRoom = ({ width }) => {
const viewport = useRef(null)
Expand All @@ -23,7 +28,7 @@ const ChatRoom = ({ width }) => {
const isAllMessageFetched = useRef(false)
const isReading = useRef(false)
const workspaceUserInfo = useRecoilValue(workspaceRecoil)
const [channelInfo] = useChannelInfo()
const [channelInfo, setChannelInfo] = useRecoilState(currentChannelInfoRecoil)
const { workspaceId, channelId } = useParams()
const params = useParams()
const socket = useRecoilValue(socketRecoil)
Expand Down Expand Up @@ -52,6 +57,20 @@ const ChatRoom = ({ width }) => {
[messages],
)

const updateChannelInfo = useCallback(async () => {
if (workspaceUserInfo && channelId)
setChannelInfo(
await getChannelHeaderInfo({
workspaceUserInfoId: workspaceUserInfo._id,
channelId,
}),
)
}, [channelId, workspaceUserInfo, setChannelInfo])

useEffect(() => {
updateChannelInfo()
}, [channelId, workspaceUserInfo, updateChannelInfo])

useEffect(() => {
setMessages([])
isLoading.current = false
Expand All @@ -74,7 +93,7 @@ const ChatRoom = ({ width }) => {
profileUrl: workspaceUserInfo.profileUrl,
},
}
socket.emit('new message', chat)
socket.emit(SOCKET_EVENT.NEW_MESSAGE, chat)
}

useEffect(() => {
Expand All @@ -83,17 +102,18 @@ const ChatRoom = ({ width }) => {

useEffect(() => {
if (socket) {
socket.on('new message', ({ message }) => {
socket.on(SOCKET_EVENT.NEW_MESSAGE, ({ message }) => {
if (message.channelId === channelId) {
setMessages(messages => [
...messages,
...hasMyReaction([message], workspaceUserInfo),
])
if (isReading.current && document.hasFocus()) {
if (message.userInfo._id === workspaceUserInfo._id) {
setHasUnreadMessage(false)
scrollTo()
} else if (message.userInfo._id !== workspaceUserInfo._id)
} else if (!isReading.current && !document.hasFocus()) {
setHasUnreadMessage(true)
}
}

if (document.hidden) {
Expand All @@ -104,17 +124,30 @@ const ChatRoom = ({ width }) => {

if (message.userInfo._id === workspaceUserInfo._id) scrollTo()
})
socket.on('update reaction', ({ reaction }) => {
setMessages(messages => chageReactionState(messages, reaction))
socket.on(SOCKET_EVENT.NEW_REPLY, ({ message }) => {
setMessages(messages =>
messages.map(target =>
target._id === message.parentId
? { ...target, reply: [...target.reply, message] }
: target,
),
)
})
socket.on(SOCKET_EVENT.UPDAETE_REACTION, ({ reaction }) => {
setMessages(messages =>
chageReactionState(messages, reaction, workspaceUserInfo),
)
})
}
return () => {
if (socket) {
socket.off('new message')
socket.off('update reaction')
socket.off(SOCKET_EVENT.NEW_REPLY)
socket.off(SOCKET_EVENT.NEW_MESSAGE)
socket.off(SOCKET_EVENT.UPDAETE_REACTION)
}
}
}, [socket, channelId, document.hidden, params])

useEffect(() => {
const handleIntersection = (entries, observer) => {
entries.forEach(entry => {
Expand Down Expand Up @@ -225,7 +258,6 @@ const UnreadMessage = styled.div`
background-color: ${COLOR.STARBLUE};
color: ${COLOR.WHITE};
width: 170px;
height: 50px;
margin-left: auto;
margin-right: auto;
position: sticky;
Expand Down
Loading

0 comments on commit b4e4832

Please sign in to comment.