1- import React , { useState , useEffect } from 'react' ;
1+ import React , {
2+ useState , useEffect , useRef , useMemo ,
3+ } from 'react' ;
24import PT from 'prop-types' ;
35import { connect } from 'react-redux' ;
46import TopBanner from 'assets/images/timeline-wall/top-banner.png' ;
57import TopBannerMobile from 'assets/images/timeline-wall/top-banner-mobile.png' ;
68import IconCheveronDownBlue from 'assets/images/timeline-wall/cheveron-down-blue.svg' ;
9+ import IconArrowRight from 'assets/images/timeline-wall/icon-arrow-right.svg' ;
710import { deleteEventById , approveEventById , rejectEventById } from 'services/timelineWall' ;
811import cn from 'classnames' ;
912import moment from 'moment' ;
1013import { useMediaQuery } from 'react-responsive' ;
1114import _ from 'lodash' ;
15+ import { config } from 'topcoder-react-utils' ;
1216import timelineActions from 'actions/timelineWall' ;
1317import LoadingIndicator from 'components/LoadingIndicator' ;
1418import TimelineEvents from './timeline-events' ;
1519import PendingApprovals from './pending-approvals' ;
1620
1721import './styles.scss' ;
1822
23+
24+ const FETCHING_PENDING_APPROVAL_EVENTS_INTERVAL = _ . get ( config , 'TIMELINE.FETCHING_PENDING_APPROVAL_EVENTS_INTERVAL' , 0 ) ;
1925function TimelineWallContainer ( props ) {
2026 const [ tab , setTab ] = useState ( 0 ) ;
27+ const fetchingApprovalsInterval = useRef ( null ) ;
2128 const [ showRightFilterMobile , setShowRightFilterMobile ] = useState ( false ) ;
2229 const [ selectedFilterValue , setSelectedFilterValue ] = useState ( {
2330 year : 0 ,
@@ -36,13 +43,15 @@ function TimelineWallContainer(props) {
3643 getAvatar,
3744 userAvatars,
3845 pendingApprovals,
46+ loadingApprovals,
3947 uploading,
48+ uploadResult,
4049 } = props ;
4150
4251 const role = 'Admin User' ;
4352 const authToken = _ . get ( auth , 'tokenV3' ) ;
4453 const isMobile = useMediaQuery ( {
45- query : '(max-device- width: 768px)' ,
54+ query : '(max-width: 768px)' ,
4655 } ) ;
4756
4857 useEffect ( ( ) => {
@@ -54,9 +63,25 @@ function TimelineWallContainer(props) {
5463 } , [ ] ) ;
5564
5665 useEffect ( ( ) => {
57- if ( authToken && isAdmin && ! pendingApprovals . length ) {
66+ if ( fetchingApprovalsInterval . current ) {
67+ clearInterval ( fetchingApprovalsInterval . current ) ;
68+ fetchingApprovalsInterval . current = null ;
69+ }
70+ if ( authToken && isAdmin ) {
5871 getPendingApprovals ( authToken ) ;
72+ if ( FETCHING_PENDING_APPROVAL_EVENTS_INTERVAL ) {
73+ fetchingApprovalsInterval . current = setInterval ( ( ) => {
74+ getPendingApprovals ( authToken ) ;
75+ } , FETCHING_PENDING_APPROVAL_EVENTS_INTERVAL ) ;
76+ }
5977 }
78+
79+ return ( ) => {
80+ if ( fetchingApprovalsInterval . current ) {
81+ clearInterval ( fetchingApprovalsInterval . current ) ;
82+ fetchingApprovalsInterval . current = null ;
83+ }
84+ } ;
6085 } , [ isAdmin ] ) ;
6186
6287 useEffect ( ( ) => {
@@ -71,7 +96,7 @@ function TimelineWallContainer(props) {
7196 } , [ events ] ) ;
7297
7398 useEffect ( ( ) => {
74- if ( ( pendingApprovals || [ ] ) . length ) {
99+ if ( pendingApprovals . length ) {
75100 _ . uniqBy ( pendingApprovals , 'createdBy' ) . forEach ( ( eventItem ) => {
76101 const photoURL = _ . get ( userAvatars , eventItem . createdBy ) ;
77102 if ( ! photoURL ) {
@@ -89,7 +114,7 @@ function TimelineWallContainer(props) {
89114 let date = moment ( `${ currentYear } -${ currentMonth + 1 } ` ) . format ( 'YYYY-MM' ) ;
90115
91116 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' ) } ` ) ;
93118
94119 if ( target || ! moment ( date ) . isValid ( ) || moment ( date ) . year ( ) > maxYear ) {
95120 break ;
@@ -100,11 +125,7 @@ function TimelineWallContainer(props) {
100125 if ( target ) {
101126 const yOffset = - 10 ;
102127 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' } ) ;
108129 } else {
109130 window . scrollTo ( { top : 0 , behavior : 'smooth' } ) ;
110131 }
@@ -137,10 +158,23 @@ function TimelineWallContainer(props) {
137158 } ;
138159
139160 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 ] ) ;
140170
141171 return (
142172 < 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+ >
144178 < img src = { TopBanner } alt = "top-banner" styleName = "header-bg hide-mobile" />
145179 < img src = { TopBannerMobile } alt = "top-banner" styleName = "header-bg hide-desktop show-mobile" />
146180
@@ -170,6 +204,16 @@ function TimelineWallContainer(props) {
170204 </ div >
171205 ) : ( < h1 styleName = "header-content-1" > Topcoder Timeline Wall</ h1 > ) }
172206
207+ { shouldShowDiscuss ? (
208+ < button
209+ type = "button"
210+ styleName = "btn-discuss"
211+ >
212+ < span > DISCUSS</ span >
213+ < IconArrowRight />
214+ </ button >
215+ ) : null }
216+
173217 < button
174218 onClick = { ( ) => {
175219 setShowRightFilterMobile ( true ) ;
@@ -203,12 +247,15 @@ function TimelineWallContainer(props) {
203247 getAvatar = { getAvatar }
204248 userAvatars = { userAvatars }
205249 uploading = { uploading }
250+ uploadResult = { uploadResult }
206251 deleteEvent = { deleteEvent }
207252 />
208253 < React . Fragment >
209254 {
210- loading ? (
211- < LoadingIndicator />
255+ loadingApprovals ? (
256+ < LoadingIndicator
257+ styleName = { cn ( { hide : tab === 0 } ) }
258+ />
212259 ) : (
213260 < PendingApprovals
214261 events = { pendingApprovals }
@@ -234,7 +281,9 @@ TimelineWallContainer.defaultProps = {
234281 auth : null ,
235282 isAdmin : false ,
236283 loading : false ,
284+ loadingApprovals : false ,
237285 uploading : false ,
286+ uploadResult : '' ,
238287 events : [ ] ,
239288 userAvatars : { } ,
240289 pendingApprovals : [ ] ,
@@ -247,7 +296,9 @@ TimelineWallContainer.propTypes = {
247296 auth : PT . shape ( ) ,
248297 isAdmin : PT . bool ,
249298 loading : PT . bool ,
299+ loadingApprovals : PT . bool ,
250300 uploading : PT . bool ,
301+ uploadResult : PT . string ,
251302 events : PT . arrayOf ( PT . shape ( ) ) ,
252303 loadUserDetails : PT . func . isRequired ,
253304 createNewEvent : PT . func . isRequired ,
@@ -264,10 +315,13 @@ const mapStateToProps = state => ({
264315 } ,
265316 isAdmin : state . timelineWall . isAdmin ,
266317 loading : state . timelineWall . loading ,
318+ loadingApprovals : state . timelineWall . loadingApprovals
319+ && ! ( state . timelineWall . pendingApprovals || [ ] ) . length ,
267320 uploading : state . timelineWall . uploading ,
321+ uploadResult : state . timelineWall . uploadResult ,
268322 events : state . timelineWall . events ,
269323 userAvatars : state . timelineWall . userAvatars ,
270- pendingApprovals : state . timelineWall . pendingApprovals ,
324+ pendingApprovals : state . timelineWall . pendingApprovals || [ ] ,
271325} ) ;
272326
273327function mapDispatchToProps ( dispatch ) {
0 commit comments