11import { useEffect , useState , useMemo , useCallback } from 'react' ;
22import axios from 'axios' ;
33import { ENDPOINTS } from '~/utils/URL' ;
4- import './TotalReport.css' ;
4+ import styles from './TotalReport.module .css' ;
55import TotalReportBarGraph from './TotalReportBarGraph' ;
66import Loading from '../../common/Loading' ;
77import EditableInfoModal from '../../UserProfile/EditableModal/EditableInfoModal' ;
8+ import { generateBarData as generateBarDataUtil } from './generateBarData' ;
9+ import {
10+ getCachedData ,
11+ setCachedData ,
12+ validateUserList ,
13+ logApiRequest ,
14+ logApiResponse ,
15+ } from './cacheUtils' ;
816
917function TotalContributorsReport ( { startDate, endDate, userProfiles, darkMode, userRole } ) {
1018 const [ contributors , setContributors ] = useState ( [ ] ) ;
@@ -17,37 +25,73 @@ function TotalContributorsReport({ startDate, endDate, userProfiles, darkMode, u
1725
1826 const fromDate = useMemo ( ( ) => startDate . toLocaleDateString ( 'en-CA' ) , [ startDate ] ) ;
1927 const toDate = useMemo ( ( ) => endDate . toLocaleDateString ( 'en-CA' ) , [ endDate ] ) ;
20- const userList = useMemo ( ( ) => userProfiles . map ( ( { _id } ) => _id ) , [ userProfiles ] ) ;
28+ const userList = useMemo ( ( ) => {
29+ const list = userProfiles ?. map ( ( { _id } ) => _id ) || [ ] ;
30+ // eslint-disable-next-line no-console
31+ console . log ( 'TotalContributorsReport userList created:' , {
32+ userProfilesLength : userProfiles ?. length ,
33+ userListLength : list . length ,
34+ } ) ;
35+ return list ;
36+ } , [ userProfiles ] ) ;
2137
2238 // Fetch time entries for the selected period
2339 const loadTimeEntriesForPeriod = useCallback ( async ( controller ) => {
40+ const reportName = 'TotalContributorsReport' ;
2441 const url = ENDPOINTS . TIME_ENTRIES_REPORTS ;
2542
2643 if ( ! url ) {
2744 return ;
2845 }
46+
47+ // Validate userList
48+ if ( ! validateUserList ( userList , userProfiles , reportName ) ) {
49+ setTimeEntries ( [ ] ) ;
50+ setLoading ( false ) ;
51+ return ;
52+ }
53+
54+ // Check cache with date range key
55+ const cacheKey = `${ reportName } _${ fromDate } _${ toDate } ` ;
56+ const cached = getCachedData ( cacheKey , reportName ) ;
57+ if ( cached . data ) {
58+ setTimeEntries ( cached . data ) ;
59+ setLoading ( false ) ;
60+ return ;
61+ }
62+
2963 try {
64+ logApiRequest ( reportName , url , { users : userList , fromDate, toDate } , {
65+ usersCount : userList ?. length ,
66+ } ) ;
67+
3068 const response = await axios . post (
3169 url ,
3270 { users : userList , fromDate, toDate } ,
3371 { signal : controller . signal }
3472 ) ;
73+
74+ logApiResponse ( reportName , response . data ?. length ) ;
75+
3576 const mappedTimeEntries = response . data . map ( entry => ( {
3677 userId : entry . personId ,
3778 hours : entry . hours ,
3879 minutes : entry . minutes ,
3980 isTangible : entry . isTangible ,
4081 date : entry . dateOfWork ,
4182 } ) ) ;
83+
4284 setTimeEntries ( mappedTimeEntries ) ;
85+ setCachedData ( cacheKey , mappedTimeEntries , reportName ) ;
4386 } catch ( error ) {
4487 // eslint-disable-next-line import/no-named-as-default-member
4588 if ( ! axios . isCancel ( error ) ) {
46- // Handle error silently or show user-friendly message
89+ // eslint-disable-next-line no-console
90+ console . error ( `${ reportName } API Error:` , error ) ;
4791 setTimeEntries ( [ ] ) ;
4892 }
4993 }
50- } , [ fromDate , toDate , userList ] ) ;
94+ } , [ fromDate , toDate , userList , userProfiles ] ) ;
5195
5296 // Group time entries by user and calculate total hours
5397 const sumByUser = useCallback ( ( entries ) => {
@@ -102,25 +146,7 @@ function TotalContributorsReport({ startDate, endDate, userProfiles, darkMode, u
102146
103147 // Generate bar chart data
104148 const generateBarData = useCallback ( ( groupedDate , isYear = false ) => {
105- if ( isYear ) {
106- const startMonth = startDate . getMonth ( ) ;
107- const endMonth = endDate . getMonth ( ) ;
108- const sumData = groupedDate . map ( range => ( {
109- label : range . timeRange ,
110- value : range . usersOfTime . length ,
111- months : 12 ,
112- } ) ) ;
113- if ( sumData . length > 1 ) {
114- sumData [ 0 ] . months = 12 - startMonth ;
115- sumData [ sumData . length - 1 ] . months = endMonth + 1 ;
116- }
117- const filteredData = sumData . filter ( data => data . value > 0 ) ;
118- return filteredData ;
119- }
120- return groupedDate . map ( range => ( {
121- label : range . timeRange ,
122- value : range . usersOfTime . length ,
123- } ) ) ;
149+ return generateBarDataUtil ( groupedDate , isYear , startDate , endDate , 'usersOfTime' ) ;
124150 } , [ startDate , endDate ] ) ;
125151
126152 // Check if we should show monthly/yearly summaries
@@ -141,13 +167,23 @@ function TotalContributorsReport({ startDate, endDate, userProfiles, darkMode, u
141167
142168 // Load data when date range changes
143169 useEffect ( ( ) => {
170+ // Only make API call if userList has data
171+ if ( ! userList || userList . length === 0 ) {
172+ // eslint-disable-next-line no-console
173+ console . log ( 'TotalContributorsReport: Waiting for userProfiles to load...' , {
174+ userProfilesLength : userProfiles ?. length ,
175+ userListLength : userList ?. length ,
176+ } ) ;
177+ return ;
178+ }
179+
144180 setLoading ( true ) ;
145181 const controller = new AbortController ( ) ;
146182 loadTimeEntriesForPeriod ( controller ) . then ( ( ) => {
147183 setLoading ( false ) ;
148184 } ) ;
149185 return ( ) => controller . abort ( ) ;
150- } , [ loadTimeEntriesForPeriod ] ) ;
186+ } , [ loadTimeEntriesForPeriod , userList ] ) ;
151187
152188 // Process data when time entries are loaded
153189 useEffect ( ( ) => {
@@ -168,9 +204,9 @@ function TotalContributorsReport({ startDate, endDate, userProfiles, darkMode, u
168204 const totalTangibleTime = contributors . reduce ( ( acc , obj ) => acc + Number ( obj . tangibleTime ) , 0 ) ;
169205
170206 return (
171- < div className = { `total-container ${ darkMode ? 'bg-yinmn-blue text-light' : '' } ` } >
207+ < div className = { `${ styles . totalContainer } ${ darkMode ? 'bg-yinmn-blue text-light' : '' } ` } >
172208 < div className = "d-flex align-items-center" >
173- < h2 className = { `total-title ${ darkMode ? 'text-azure' : '' } ` } > Contributors Report</ h2 >
209+ < h2 className = { `${ styles . totalTitle } ${ darkMode ? 'text-azure' : '' } ` } > Contributors Report</ h2 >
174210 < EditableInfoModal
175211 areaName = "contributorsReportInfo"
176212 areaTitle = "Contributors Report"
@@ -181,16 +217,16 @@ function TotalContributorsReport({ startDate, endDate, userProfiles, darkMode, u
181217 darkMode = { darkMode }
182218 />
183219 </ div >
184- < div className = "total-period" >
220+ < div className = { styles . totalPeriod } >
185221 In the period from { startDate . toLocaleDateString ( 'en-US' , { month : '2-digit' , day : '2-digit' , year : 'numeric' } ) } to { endDate . toLocaleDateString ( 'en-US' , { month : '2-digit' , day : '2-digit' , year : 'numeric' } ) } :
186222 </ div >
187- < div className = "total-item" >
188- < div className = "total-number" > { contributors . length } </ div >
189- < div className = "total-text" > members have contributed more than 10 hours.</ div >
223+ < div className = { styles . totalItem } >
224+ < div className = { styles . totalNumber } > { contributors . length } </ div >
225+ < div className = { styles . totalText } > members have contributed more than 10 hours.</ div >
190226 </ div >
191- < div className = "total-item" >
192- < div className = "total-number" > { totalTangibleTime . toFixed ( 2 ) } </ div >
193- < div className = "total-text" > hours of tangible time have been logged.</ div >
227+ < div className = { styles . totalItem } >
228+ < div className = { styles . totalNumber } > { totalTangibleTime . toFixed ( 2 ) } </ div >
229+ < div className = { styles . totalText } > hours of tangible time have been logged.</ div >
194230 </ div >
195231 < div >
196232 { showMonthly && contributorsInMonth . length > 0 && (
0 commit comments