@@ -37,6 +37,7 @@ import hasPermission from '../../../utils/permissions';
3737import { ENDPOINTS } from '../../../utils/URL' ;
3838
3939const ROLE_OPTIONS = [
40+ 'All Roles' ,
4041 'Frontend Developer' ,
4142 'Backend Developer' ,
4243 'Data Analyst' ,
@@ -112,15 +113,15 @@ class AnalyticsService {
112113 return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
113114 }
114115
115- static async fetchData ( dateRange , comparisonPeriod ) {
116+ static async fetchData ( dateRange , comparisonPeriod , role ) {
116117 try {
117118 // TODO: Replace with real API when ready
118119 // const response = await fetch(`${CONFIG.API.ENDPOINTS.ANALYTICS}`, { ... });
119120 // if (!response.ok) throw new Error('Failed to fetch analytics data');
120121 // return await response.json();
121122
122123 await this . simulateApiDelay ( ) ;
123- return this . generateMockAnalyticsData ( dateRange , comparisonPeriod ) ;
124+ return this . generateMockAnalyticsData ( dateRange , comparisonPeriod , role ) ;
124125 } catch ( err ) {
125126 // eslint-disable-next-line no-console
126127 console . error ( 'Analytics fetch error:' , err ) ;
@@ -136,7 +137,7 @@ class AnalyticsService {
136137 return min + ( array [ 0 ] % ( max - min + 1 ) ) ;
137138 }
138139
139- static generateMockAnalyticsData ( dateRange , comparisonPeriod ) {
140+ static generateMockAnalyticsData ( dateRange , comparisonPeriod , role = 'All Roles' ) {
140141 const genSeries = ( startDate , endDate , offset = 0 ) => {
141142 const data = [ ] ;
142143 const start = new Date ( startDate ) ;
@@ -145,16 +146,39 @@ class AnalyticsService {
145146 for ( let i = 0 ; i <= diffDays ; i += 1 ) {
146147 const date = new Date ( start ) ;
147148 date . setDate ( date . getDate ( ) + i ) ;
149+ let roleOffset = 0 ;
150+ switch ( role ) {
151+ case 'Frontend Developer' :
152+ roleOffset = 50 ;
153+ break ;
154+ case 'Backend Developer' :
155+ roleOffset = 30 ;
156+ break ;
157+ case 'Data Analyst' :
158+ roleOffset = 20 ;
159+ break ;
160+ case 'Product Manager' :
161+ roleOffset = 10 ;
162+ break ;
163+ case 'UX Designer' :
164+ roleOffset = 15 ;
165+ break ;
166+ default :
167+ roleOffset = 0 ;
168+ }
148169 data . push ( {
149170 date : date . toISOString ( ) . split ( 'T' ) [ 0 ] ,
150171 displayDate : date . toLocaleDateString ( 'en-US' , CONFIG . DATE_FORMAT . display ) ,
151172
152173 // ✅ Secure dummy simulation values:
153- users : this . secureRandom ( 700 + offset , 1000 + offset ) ,
154- pageViews : this . secureRandom ( 4000 + offset * 5 , 6000 + offset * 5 ) ,
174+ users : this . secureRandom ( 700 + offset + roleOffset , 1000 + offset + roleOffset ) ,
175+ pageViews : this . secureRandom (
176+ 4000 + offset * 5 + roleOffset * 10 ,
177+ 6000 + offset * 5 + roleOffset * 10 ,
178+ ) ,
155179 sessions : this . secureRandom (
156- Math . floor ( 600 + offset * 0.8 ) ,
157- Math . floor ( 1000 + offset * 0.8 ) ,
180+ Math . floor ( 600 + offset * 0.8 + roleOffset * 0.5 ) ,
181+ Math . floor ( 1000 + offset * 0.8 + roleOffset * 0.5 ) ,
158182 ) ,
159183 bounceRate : this . secureRandom ( 35 , 55 ) ,
160184 avgDuration : this . secureRandom ( 180 , 300 ) ,
@@ -177,18 +201,18 @@ class AnalyticsService {
177201 previousPeriod : genSeries ( start , end , 0 ) ,
178202 metrics : {
179203 current : {
180- totalUsers : 23456 ,
181- totalPageViews : 145678 ,
182- totalSessions : 18934 ,
183- avgBounceRate : 42.3 ,
184- avgSessionDuration : 245 ,
204+ totalUsers : 23456 + ( role === 'All Roles' ? 0 : this . secureRandom ( 1000 , 3000 ) ) , // Simulate role-based user count
205+ totalPageViews : 145678 + ( role === 'All Roles' ? 0 : this . secureRandom ( 5000 , 15000 ) ) , // Simulate role-based page views
206+ totalSessions : 18934 + ( role === 'All Roles' ? 0 : this . secureRandom ( 800 , 2000 ) ) , // Simulate role-based sessions
207+ avgBounceRate : 42.3 + ( role === 'All Roles' ? 0 : this . secureRandom ( - 5 , 5 ) ) , // Simulate role-based bounce rate
208+ avgSessionDuration : 245 + ( role === 'All Roles' ? 0 : this . secureRandom ( - 30 , 30 ) ) , // Simulate role-based session duration
185209 } ,
186210 previous : {
187- totalUsers : 21234 ,
188- totalPageViews : 132456 ,
189- totalSessions : 17123 ,
190- avgBounceRate : 45.7 ,
191- avgSessionDuration : 220 ,
211+ totalUsers : 21234 + ( role === 'All Roles' ? 0 : this . secureRandom ( 1000 , 3000 ) ) ,
212+ totalPageViews : 132456 + ( role === 'All Roles' ? 0 : this . secureRandom ( 5000 , 15000 ) ) ,
213+ totalSessions : 17123 + ( role === 'All Roles' ? 0 : this . secureRandom ( 800 , 2000 ) ) ,
214+ avgBounceRate : 45.7 + ( role === 'All Roles' ? 0 : this . secureRandom ( - 5 , 5 ) ) ,
215+ avgSessionDuration : 220 + ( role === 'All Roles' ? 0 : this . secureRandom ( - 30 , 30 ) ) ,
192216 } ,
193217 } ,
194218 deviceBreakdown : [
@@ -208,7 +232,7 @@ class AnalyticsService {
208232}
209233
210234// ======================== HOOKS ========================
211- function useAnalyticsData ( dateRange , comparisonPeriod ) {
235+ function useAnalyticsData ( dateRange , comparisonPeriod , selectedRole ) {
212236 const [ data , setData ] = useState ( null ) ;
213237 const [ loading , setLoading ] = useState ( true ) ;
214238 const [ error , setError ] = useState ( null ) ;
@@ -217,19 +241,14 @@ function useAnalyticsData(dateRange, comparisonPeriod) {
217241 setLoading ( true ) ;
218242 setError ( null ) ;
219243 try {
220- const res = await AnalyticsService . fetchData ( dateRange , comparisonPeriod ) ;
244+ const res = await AnalyticsService . fetchData ( dateRange , comparisonPeriod , selectedRole ) ;
221245 setData ( res ) ;
222246 } catch ( e ) {
223247 setError ( e . message || 'Failed to load analytics' ) ;
224248 } finally {
225249 setLoading ( false ) ;
226250 }
227- } , [ dateRange , comparisonPeriod ] ) ;
228-
229- useEffect ( ( ) => {
230- fetchData ( ) ;
231- } , [ fetchData ] ) ;
232-
251+ } , [ dateRange , comparisonPeriod , selectedRole ] ) ;
233252 return { data, loading, error, refetch : fetchData } ;
234253}
235254
@@ -439,8 +458,14 @@ function JobAnalytics({ darkMode, role, hasPermission: hasPerm }) {
439458 const { data : analyticsData , loading, error, refetch } = useAnalyticsData (
440459 dateRange ,
441460 comparisonPeriod ,
461+ selectedRole ,
442462 ) ;
443463
464+ useEffect ( ( ) => {
465+ // Refetch data when role changes
466+ refetch ( ) ;
467+ } , [ selectedRole , refetch ] ) ;
468+
444469 const mergedData = useMemo ( ( ) => {
445470 if ( ! analyticsData ?. currentPeriod || ! analyticsData ?. previousPeriod ) return [ ] ;
446471 return analyticsData . currentPeriod . map ( ( d , i ) => ( {
@@ -472,21 +497,47 @@ function JobAnalytics({ darkMode, role, hasPermission: hasPerm }) {
472497 } ;
473498 } , [ analyticsData ] ) ;
474499
500+ const filteredDeviceBreakdown = useMemo ( ( ) => {
501+ if ( ! analyticsData ?. deviceBreakdown ) return [ ] ;
502+ const multiplier =
503+ selectedRole === 'All Roles' ? 1 : 1 + ROLE_OPTIONS . indexOf ( selectedRole ) * 0.05 ;
504+ const dateFactor = dateRange ? 1 + Math . random ( ) * 0.1 : 1 ;
505+
506+ return analyticsData . deviceBreakdown . map ( d => ( {
507+ ...d ,
508+ value : Math . round ( d . value * multiplier * dateFactor ) ,
509+ previousValue : Math . round ( d . previousValue * multiplier * dateFactor ) ,
510+ sessions : Math . round ( d . sessions * multiplier * dateFactor ) ,
511+ } ) ) ;
512+ } , [ analyticsData , selectedRole , dateRange , comparisonPeriod ] ) ;
513+
514+ const filteredTrafficSources = useMemo ( ( ) => {
515+ if ( ! analyticsData ?. trafficSources ) return [ ] ;
516+ const multiplier =
517+ selectedRole === 'All Roles' ? 1 : 1 + ROLE_OPTIONS . indexOf ( selectedRole ) * 0.05 ;
518+ const dateFactor = dateRange ? 1 + Math . random ( ) * 0.1 : 1 ;
519+
520+ return analyticsData . trafficSources . map ( t => ( {
521+ ...t ,
522+ current : Math . round ( t . current * multiplier * dateFactor ) ,
523+ previous : Math . round ( t . previous * multiplier * dateFactor ) ,
524+ } ) ) ;
525+ } , [ analyticsData , selectedRole , dateRange , comparisonPeriod ] ) ;
526+
527+ const handleResetAndRefresh = ( ) => {
528+ const last30 = DATE_RANGE_PRESETS . last30Days . getValue ( ) ;
529+
530+ setSelectedRole ( 'All Roles' ) ;
531+ setDateRange ( last30 ) ;
532+ setComparisonPeriod ( 'previous-month' ) ;
533+
534+ refetch ( ) ;
535+ } ;
536+
475537 const colors = darkMode ? CONFIG . CHART_COLORS . dark : CONFIG . CHART_COLORS ;
476538
477539 return (
478540 < div className = { styles . page } >
479- { /* <header className={styles.header}>
480- <h2 className={styles.title}>Job Analytics</h2>
481- <button
482- className={`${styles.btn} ${styles.btnPrimary}`}
483- onClick={refetch}
484- disabled={loading}
485- >
486- <RefreshCw className={loading ? styles.spin : ''} size={16} />
487- <span>Refresh</span>
488- </button>
489- </header> */ }
490541 < header className = { styles . header } >
491542 < h2 className = { styles . title } > Job Analytics</ h2 >
492543
@@ -507,7 +558,7 @@ function JobAnalytics({ darkMode, role, hasPermission: hasPerm }) {
507558 { /* Refresh Button */ }
508559 < button
509560 className = { `${ styles . btn } ${ styles . btnPrimary } ` }
510- onClick = { refetch }
561+ onClick = { handleResetAndRefresh }
511562 disabled = { loading }
512563 >
513564 < RefreshCw className = { loading ? styles . spin : '' } size = { 16 } />
@@ -621,7 +672,7 @@ function JobAnalytics({ darkMode, role, hasPermission: hasPerm }) {
621672 < ChartCard title = "Traffic Sources" icon = { BarChart3 } >
622673 < ResponsiveContainer width = "100%" height = { 320 } >
623674 < BarChart
624- data = { analyticsData ?. trafficSources || [ ] }
675+ data = { filteredTrafficSources }
625676 margin = { { top : 10 , right : 10 , left : 0 , bottom : 10 } }
626677 >
627678 < CartesianGrid strokeDasharray = "3 3" className = { styles . gridStroke } />
@@ -655,7 +706,7 @@ function JobAnalytics({ darkMode, role, hasPermission: hasPerm }) {
655706 < ResponsiveContainer width = "100%" height = { 320 } >
656707 < PieChart >
657708 < Pie
658- data = { analyticsData ?. deviceBreakdown || [ ] }
709+ data = { filteredDeviceBreakdown }
659710 cx = "50%"
660711 cy = "50%"
661712 outerRadius = { 110 }
0 commit comments