1
- import React , { useState , useEffect } from 'react' ;
1
+ import React , {
2
+ useState , useEffect , useRef , useMemo ,
3
+ } from 'react' ;
2
4
import PT from 'prop-types' ;
3
5
import { connect } from 'react-redux' ;
4
6
import TopBanner from 'assets/images/timeline-wall/top-banner.png' ;
5
7
import TopBannerMobile from 'assets/images/timeline-wall/top-banner-mobile.png' ;
6
8
import IconCheveronDownBlue from 'assets/images/timeline-wall/cheveron-down-blue.svg' ;
9
+ import IconArrowRight from 'assets/images/timeline-wall/icon-arrow-right.svg' ;
7
10
import { deleteEventById , approveEventById , rejectEventById } from 'services/timelineWall' ;
8
11
import cn from 'classnames' ;
9
12
import moment from 'moment' ;
10
13
import { useMediaQuery } from 'react-responsive' ;
11
14
import _ from 'lodash' ;
15
+ import { config } from 'topcoder-react-utils' ;
12
16
import timelineActions from 'actions/timelineWall' ;
13
17
import LoadingIndicator from 'components/LoadingIndicator' ;
14
18
import TimelineEvents from './timeline-events' ;
15
19
import PendingApprovals from './pending-approvals' ;
16
20
17
21
import './styles.scss' ;
18
22
23
+
24
+ const FETCHING_PENDING_APPROVAL_EVENTS_INTERVAL = _ . get ( config , 'TIMELINE.FETCHING_PENDING_APPROVAL_EVENTS_INTERVAL' , 0 ) ;
19
25
function TimelineWallContainer ( props ) {
20
26
const [ tab , setTab ] = useState ( 0 ) ;
27
+ const fetchingApprovalsInterval = useRef ( null ) ;
21
28
const [ showRightFilterMobile , setShowRightFilterMobile ] = useState ( false ) ;
22
29
const [ selectedFilterValue , setSelectedFilterValue ] = useState ( {
23
30
year : 0 ,
@@ -36,13 +43,15 @@ function TimelineWallContainer(props) {
36
43
getAvatar,
37
44
userAvatars,
38
45
pendingApprovals,
46
+ loadingApprovals,
39
47
uploading,
48
+ uploadResult,
40
49
} = props ;
41
50
42
51
const role = 'Admin User' ;
43
52
const authToken = _ . get ( auth , 'tokenV3' ) ;
44
53
const isMobile = useMediaQuery ( {
45
- query : '(max-device- width: 768px)' ,
54
+ query : '(max-width: 768px)' ,
46
55
} ) ;
47
56
48
57
useEffect ( ( ) => {
@@ -54,9 +63,25 @@ function TimelineWallContainer(props) {
54
63
} , [ ] ) ;
55
64
56
65
useEffect ( ( ) => {
57
- if ( authToken && isAdmin && ! pendingApprovals . length ) {
66
+ if ( fetchingApprovalsInterval . current ) {
67
+ clearInterval ( fetchingApprovalsInterval . current ) ;
68
+ fetchingApprovalsInterval . current = null ;
69
+ }
70
+ if ( authToken && isAdmin ) {
58
71
getPendingApprovals ( authToken ) ;
72
+ if ( FETCHING_PENDING_APPROVAL_EVENTS_INTERVAL ) {
73
+ fetchingApprovalsInterval . current = setInterval ( ( ) => {
74
+ getPendingApprovals ( authToken ) ;
75
+ } , FETCHING_PENDING_APPROVAL_EVENTS_INTERVAL ) ;
76
+ }
59
77
}
78
+
79
+ return ( ) => {
80
+ if ( fetchingApprovalsInterval . current ) {
81
+ clearInterval ( fetchingApprovalsInterval . current ) ;
82
+ fetchingApprovalsInterval . current = null ;
83
+ }
84
+ } ;
60
85
} , [ isAdmin ] ) ;
61
86
62
87
useEffect ( ( ) => {
@@ -71,7 +96,7 @@ function TimelineWallContainer(props) {
71
96
} , [ events ] ) ;
72
97
73
98
useEffect ( ( ) => {
74
- if ( ( pendingApprovals || [ ] ) . length ) {
99
+ if ( pendingApprovals . length ) {
75
100
_ . uniqBy ( pendingApprovals , 'createdBy' ) . forEach ( ( eventItem ) => {
76
101
const photoURL = _ . get ( userAvatars , eventItem . createdBy ) ;
77
102
if ( ! photoURL ) {
@@ -89,7 +114,7 @@ function TimelineWallContainer(props) {
89
114
let date = moment ( `${ currentYear } -${ currentMonth + 1 } ` ) . format ( 'YYYY-MM' ) ;
90
115
91
116
while ( ! target ) {
92
- target = document . getElementById ( `${ moment ( date ) . year ( ) } -${ ( moment ( date ) . month ( ) ) . toString ( ) . padStart ( 2 , '0' ) } ` ) ;
117
+ target = document . getElementById ( `${ isMobile ? 'mobile-' : 'desktop-' } ${ moment ( date ) . year ( ) } -${ ( moment ( date ) . month ( ) ) . toString ( ) . padStart ( 2 , '0' ) } ` ) ;
93
118
94
119
if ( target || ! moment ( date ) . isValid ( ) || moment ( date ) . year ( ) > maxYear ) {
95
120
break ;
@@ -100,11 +125,7 @@ function TimelineWallContainer(props) {
100
125
if ( target ) {
101
126
const yOffset = - 10 ;
102
127
const coordinate = target . getBoundingClientRect ( ) . top + window . pageYOffset + yOffset ;
103
- if ( isMobile ) {
104
- setTimeout ( target . scrollTo ( ) , 100 ) ;
105
- } else {
106
- window . scrollTo ( { top : coordinate , behavior : 'smooth' } ) ;
107
- }
128
+ window . scrollTo ( { top : coordinate , behavior : 'smooth' } ) ;
108
129
} else {
109
130
window . scrollTo ( { top : 0 , behavior : 'smooth' } ) ;
110
131
}
@@ -137,10 +158,23 @@ function TimelineWallContainer(props) {
137
158
} ;
138
159
139
160
const sortedEvents = _ . orderBy ( events , [ 'eventDate' ] , [ 'desc' ] ) ;
161
+ const shouldShowDiscuss = useMemo ( ( ) => {
162
+ if ( tab !== 0 ) {
163
+ return false ;
164
+ }
165
+ if ( isAdmin ) {
166
+ return ! isMobile ;
167
+ }
168
+ return true ;
169
+ } , [ isAdmin , isMobile , tab ] ) ;
140
170
141
171
return (
142
172
< div styleName = "container" >
143
- < div styleName = { isAdmin ? 'header header-admin' : 'header' } >
173
+ < div styleName = { cn ( 'header' , {
174
+ 'header-admin' : isAdmin ,
175
+ 'header-with-discuss' : shouldShowDiscuss ,
176
+ } ) }
177
+ >
144
178
< img src = { TopBanner } alt = "top-banner" styleName = "header-bg hide-mobile" />
145
179
< img src = { TopBannerMobile } alt = "top-banner" styleName = "header-bg hide-desktop show-mobile" />
146
180
@@ -170,6 +204,16 @@ function TimelineWallContainer(props) {
170
204
</ div >
171
205
) : ( < h1 styleName = "header-content-1" > Topcoder Timeline Wall</ h1 > ) }
172
206
207
+ { shouldShowDiscuss ? (
208
+ < button
209
+ type = "button"
210
+ styleName = "btn-discuss"
211
+ >
212
+ < span > DISCUSS</ span >
213
+ < IconArrowRight />
214
+ </ button >
215
+ ) : null }
216
+
173
217
< button
174
218
onClick = { ( ) => {
175
219
setShowRightFilterMobile ( true ) ;
@@ -203,12 +247,15 @@ function TimelineWallContainer(props) {
203
247
getAvatar = { getAvatar }
204
248
userAvatars = { userAvatars }
205
249
uploading = { uploading }
250
+ uploadResult = { uploadResult }
206
251
deleteEvent = { deleteEvent }
207
252
/>
208
253
< React . Fragment >
209
254
{
210
- loading ? (
211
- < LoadingIndicator />
255
+ loadingApprovals ? (
256
+ < LoadingIndicator
257
+ styleName = { cn ( { hide : tab === 0 } ) }
258
+ />
212
259
) : (
213
260
< PendingApprovals
214
261
events = { pendingApprovals }
@@ -234,7 +281,9 @@ TimelineWallContainer.defaultProps = {
234
281
auth : null ,
235
282
isAdmin : false ,
236
283
loading : false ,
284
+ loadingApprovals : false ,
237
285
uploading : false ,
286
+ uploadResult : '' ,
238
287
events : [ ] ,
239
288
userAvatars : { } ,
240
289
pendingApprovals : [ ] ,
@@ -247,7 +296,9 @@ TimelineWallContainer.propTypes = {
247
296
auth : PT . shape ( ) ,
248
297
isAdmin : PT . bool ,
249
298
loading : PT . bool ,
299
+ loadingApprovals : PT . bool ,
250
300
uploading : PT . bool ,
301
+ uploadResult : PT . string ,
251
302
events : PT . arrayOf ( PT . shape ( ) ) ,
252
303
loadUserDetails : PT . func . isRequired ,
253
304
createNewEvent : PT . func . isRequired ,
@@ -264,10 +315,13 @@ const mapStateToProps = state => ({
264
315
} ,
265
316
isAdmin : state . timelineWall . isAdmin ,
266
317
loading : state . timelineWall . loading ,
318
+ loadingApprovals : state . timelineWall . loadingApprovals
319
+ && ! ( state . timelineWall . pendingApprovals || [ ] ) . length ,
267
320
uploading : state . timelineWall . uploading ,
321
+ uploadResult : state . timelineWall . uploadResult ,
268
322
events : state . timelineWall . events ,
269
323
userAvatars : state . timelineWall . userAvatars ,
270
- pendingApprovals : state . timelineWall . pendingApprovals ,
324
+ pendingApprovals : state . timelineWall . pendingApprovals || [ ] ,
271
325
} ) ;
272
326
273
327
function mapDispatchToProps ( dispatch ) {
0 commit comments