1
1
import React from 'react' ;
2
- import { View , Keyboard , AppState } from 'react-native' ;
2
+ import {
3
+ Animated ,
4
+ View ,
5
+ Keyboard ,
6
+ AppState ,
7
+ } from 'react-native' ;
3
8
import PropTypes from 'prop-types' ;
4
9
import _ from 'underscore' ;
5
10
import lodashGet from 'lodash.get' ;
6
11
import { withOnyx } from 'react-native-onyx' ;
7
12
import Text from '../../../components/Text' ;
13
+ import UnreadActionIndicator from '../../../components/UnreadActionIndicator' ;
8
14
import { fetchActions , updateLastReadActionID } from '../../../libs/actions/Report' ;
9
15
import ONYXKEYS from '../../../ONYXKEYS' ;
10
16
import ReportActionItem from './ReportActionItem' ;
@@ -23,6 +29,12 @@ const propTypes = {
23
29
24
30
/* Onyx Props */
25
31
32
+ // The report currently being looked at
33
+ report : PropTypes . shape ( {
34
+ // Number of actions unread
35
+ unreadActionCount : PropTypes . number ,
36
+ } ) ,
37
+
26
38
// Array of report actions for this report
27
39
reportActions : PropTypes . objectOf ( PropTypes . shape ( ReportActionPropTypes ) ) ,
28
40
@@ -34,6 +46,9 @@ const propTypes = {
34
46
} ;
35
47
36
48
const defaultProps = {
49
+ report : {
50
+ unreadActionCount : 0 ,
51
+ } ,
37
52
reportActions : { } ,
38
53
session : { } ,
39
54
} ;
@@ -46,8 +61,17 @@ class ReportActionsView extends React.Component {
46
61
this . scrollToListBottom = this . scrollToListBottom . bind ( this ) ;
47
62
this . recordMaxAction = this . recordMaxAction . bind ( this ) ;
48
63
this . onVisibilityChange = this . onVisibilityChange . bind ( this ) ;
49
- this . sortedReportActions = this . updateSortedReportActions ( ) ;
64
+
65
+ this . sortedReportActions = [ ] ;
50
66
this . timers = [ ] ;
67
+ this . unreadIndicatorOpacity = new Animated . Value ( 1 ) ;
68
+
69
+ // Helper variable that keeps track of the unread action count before it updates to zero
70
+ this . unreadActionCount = 0 ;
71
+
72
+ // Helper variable that prevents the unread indicator to show up for new messages
73
+ // received while the report is still active
74
+ this . shouldShowUnreadActionIndicator = true ;
51
75
52
76
this . state = {
53
77
refetchNeeded : true ,
@@ -145,6 +169,31 @@ class ReportActionsView extends React.Component {
145
169
this . setState ( { refetchNeeded} ) ;
146
170
}
147
171
172
+ /**
173
+ * Checks if the unreadActionIndicator should be shown.
174
+ * If it does, starts a timeout for the fading out animation and creates
175
+ * a flag to not show it again if the report is still open
176
+ */
177
+ setUpUnreadActionIndicator ( ) {
178
+ if ( ! this . props . isActiveReport || ! this . shouldShowUnreadActionIndicator ) {
179
+ return ;
180
+ }
181
+
182
+ this . unreadActionCount = this . props . report . unreadActionCount ;
183
+
184
+ if ( this . unreadActionCount > 0 ) {
185
+ this . unreadIndicatorOpacity = new Animated . Value ( 1 ) ;
186
+ this . timers . push ( setTimeout ( ( ) => {
187
+ Animated . timing ( this . unreadIndicatorOpacity , {
188
+ toValue : 0 ,
189
+ useNativeDriver : false ,
190
+ } ) . start ( ) ;
191
+ } , 3000 ) ) ;
192
+ }
193
+
194
+ this . shouldShowUnreadActionIndicator = false ;
195
+ }
196
+
148
197
/**
149
198
* Updates and sorts the report actions by sequence number
150
199
*/
@@ -239,12 +288,21 @@ class ReportActionsView extends React.Component {
239
288
needsLayoutCalculation,
240
289
} ) {
241
290
return (
242
- < ReportActionItem
243
- action = { item . action }
244
- displayAsGroup = { this . isConsecutiveActionMadeByPreviousActor ( index ) }
245
- onLayout = { onLayout }
246
- needsLayoutCalculation = { needsLayoutCalculation }
247
- />
291
+
292
+ // Using <View /> instead of a Fragment because there is a difference between how
293
+ // <InvertedFlatList /> are implemented on native and web/desktop which leads to
294
+ // the unread indicator on native to render below the message instead of above it.
295
+ < View >
296
+ { this . unreadActionCount > 0 && index === this . unreadActionCount - 1 && (
297
+ < UnreadActionIndicator animatedOpacity = { this . unreadIndicatorOpacity } />
298
+ ) }
299
+ < ReportActionItem
300
+ action = { item . action }
301
+ displayAsGroup = { this . isConsecutiveActionMadeByPreviousActor ( index ) }
302
+ onLayout = { onLayout }
303
+ needsLayoutCalculation = { needsLayoutCalculation }
304
+ />
305
+ </ View >
248
306
) ;
249
307
}
250
308
@@ -263,6 +321,7 @@ class ReportActionsView extends React.Component {
263
321
) ;
264
322
}
265
323
324
+ this . setUpUnreadActionIndicator ( ) ;
266
325
this . updateSortedReportActions ( ) ;
267
326
return (
268
327
< InvertedFlatList
@@ -281,6 +340,9 @@ ReportActionsView.propTypes = propTypes;
281
340
ReportActionsView . defaultProps = defaultProps ;
282
341
283
342
export default withOnyx ( {
343
+ report : {
344
+ key : ( { reportID} ) => `${ ONYXKEYS . COLLECTION . REPORT } ${ reportID } ` ,
345
+ } ,
284
346
reportActions : {
285
347
key : ( { reportID} ) => `${ ONYXKEYS . COLLECTION . REPORT_ACTIONS } ${ reportID } ` ,
286
348
canEvict : props => ! props . isActiveReport ,
0 commit comments