@@ -11,6 +11,8 @@ import ChannelHeader from '../ChannelHeader'
11
11
import { isEmpty } from '../../util'
12
12
import { hasMyReaction , chageReactionState } from '../../util/reactionUpdate'
13
13
import useChannelInfo from '../../hooks/useChannelInfo'
14
+ import Icon from '../../presenter/Icon'
15
+ import { ArrowDown } from '../../constant/icon'
14
16
15
17
const ChatRoom = ( { width } ) => {
16
18
const viewport = useRef ( null )
@@ -19,13 +21,15 @@ const ChatRoom = ({ width }) => {
19
21
const previousReadMessage = useRef ( null )
20
22
const isLoading = useRef ( false )
21
23
const isAllMessageFetched = useRef ( false )
24
+ const isReading = useRef ( false )
22
25
const workspaceUserInfo = useRecoilValue ( workspaceRecoil )
23
26
const [ channelInfo ] = useChannelInfo ( )
24
27
const { workspaceId, channelId } = useParams ( )
25
28
const params = useParams ( )
26
29
const socket = useRecoilValue ( socketRecoil )
27
30
const [ messages , setMessages ] = useState ( [ ] )
28
31
const [ previousReadMessageIndex , setPreviousReadMessageIndex ] = useState ( 0 )
32
+ const [ hasUnreadMessage , setHasUnreadMessage ] = useState ( false )
29
33
30
34
const loadMessage = useCallback (
31
35
async ( workspaceId , channelId , currentCursor ) => {
@@ -80,11 +84,17 @@ const ChatRoom = ({ width }) => {
80
84
useEffect ( ( ) => {
81
85
if ( socket ) {
82
86
socket . on ( 'new message' , ( { message } ) => {
83
- if ( message . channelId === channelId )
87
+ if ( message . channelId === channelId ) {
84
88
setMessages ( messages => [
85
89
...messages ,
86
90
...hasMyReaction ( [ message ] , workspaceUserInfo ) ,
87
91
] )
92
+ if ( isReading . current && document . hasFocus ( ) ) {
93
+ setHasUnreadMessage ( false )
94
+ scrollTo ( )
95
+ } else if ( message . userInfo . _id !== workspaceUserInfo . _id )
96
+ setHasUnreadMessage ( true )
97
+ }
88
98
89
99
if ( document . hidden ) {
90
100
new Notification ( 'μλ‘μ΄ λ©μμ§κ° μμ΅λλ€.' , {
@@ -105,12 +115,24 @@ const ChatRoom = ({ width }) => {
105
115
}
106
116
}
107
117
} , [ socket , channelId , document . hidden , params ] )
108
-
109
118
useEffect ( ( ) => {
110
119
const handleIntersection = ( entries , observer ) => {
111
120
entries . forEach ( entry => {
112
- if ( entry . isIntersecting ) {
113
- if ( ! isLoading . current && ! isAllMessageFetched . current ) {
121
+ if ( entry . target === messageEndRef . current ) {
122
+ if ( ! entry . isIntersecting || ! document . hasFocus ( ) ) {
123
+ isReading . current = false
124
+ }
125
+ if ( entry . isIntersecting ) {
126
+ setHasUnreadMessage ( false )
127
+ isReading . current = true
128
+ }
129
+ }
130
+ if ( entry . target === observerTargetNode . current ) {
131
+ if (
132
+ entry . isIntersecting &&
133
+ ! isLoading . current &&
134
+ ! isAllMessageFetched . current
135
+ ) {
114
136
loadMessage ( workspaceId , channelId , observerTargetNode . current . id )
115
137
observer . unobserve ( entry . target )
116
138
observer . observe ( observerTargetNode . current )
@@ -123,6 +145,7 @@ const ChatRoom = ({ width }) => {
123
145
threshold : 0 ,
124
146
} )
125
147
if ( observerTargetNode . current ) IO . observe ( observerTargetNode . current )
148
+ if ( messageEndRef . current ) IO . observe ( messageEndRef . current )
126
149
return ( ) => IO && IO . disconnect ( )
127
150
} , [ channelId , workspaceId , loadMessage ] )
128
151
@@ -134,7 +157,9 @@ const ChatRoom = ({ width }) => {
134
157
} ,
135
158
[ previousReadMessageIndex ] ,
136
159
)
137
-
160
+ const handleUnreadMessageButton = ( ) => {
161
+ scrollTo ( )
162
+ }
138
163
return (
139
164
< ChatArea width = { width } >
140
165
< ChatHeader >
@@ -152,6 +177,11 @@ const ChatRoom = ({ width }) => {
152
177
/>
153
178
)
154
179
} ) }
180
+ { hasUnreadMessage && (
181
+ < UnreadMessage onClick = { handleUnreadMessageButton } >
182
+ < Icon icon = { ArrowDown } color = { COLOR . WHITE } /> Unread messages..
183
+ </ UnreadMessage >
184
+ ) }
155
185
< div ref = { messageEndRef } > </ div >
156
186
</ ChatContents >
157
187
< MessageEditor
@@ -167,7 +197,7 @@ const ChatArea = styled.div`
167
197
display: flex;
168
198
flex-direction: column;
169
199
height: 100%;
170
- width: calc( ${ props => props . width } % - 2px) ;
200
+ width: ${ props => `calc( 100 % - ${ props . width } px)` } ;
171
201
background: ${ COLOR . HOVER_GRAY } ;
172
202
`
173
203
@@ -189,5 +219,20 @@ const ChatContents = styled.div`
189
219
background: ${ COLOR . WHITE } ;
190
220
border: 1px solid rgba(255, 255, 255, 0.1);
191
221
`
192
-
222
+ const UnreadMessage = styled . div `
223
+ border-radius: 30px;
224
+ border: 1px solid ${ COLOR . LIGHT_GRAY } ;
225
+ background-color: ${ COLOR . STARBLUE } ;
226
+ color: ${ COLOR . WHITE } ;
227
+ width: 170px;
228
+ height: 50px;
229
+ margin-left: auto;
230
+ margin-right: auto;
231
+ position: sticky;
232
+ bottom: 15px;
233
+ text-align: center;
234
+ padding: 5px;
235
+ font-weight: 700;
236
+ cursor: pointer;
237
+ `
193
238
export default ChatRoom
0 commit comments