@@ -7,12 +7,12 @@ import { MatFormFieldModule } from '@angular/material/form-field';
77import { MatSelectModule } from '@angular/material/select' ;
88import { ActivatedRoute } from '@angular/router' ;
99import { ProjectPlanCodeFilterEnum , ResponseCodeEnum } from '@api-client' ;
10- import { ChartOptions , commentsByResponseCodeChartOptions , fomsCountByDistrictChartOptions , fomsCountByForestClientChartOptions , maxAxis , maxAxis as maxxAxis , topCommentedProjectsChartOptions } from 'app/analytics-dashboard/analytics-dashboard-chart-config' ;
10+ import { ChartOptions , commentsByDistrictChartOptions , commentsByResponseCodeChartOptions , fomsCountByDistrictChartOptions , fomsCountByForestClientChartOptions , maxAxis , maxAxis as maxxAxis , RESPONSE_CODE_COLORS , RESPONSE_CODE_LABELS , topCommentedProjectsChartOptions } from 'app/analytics-dashboard/analytics-dashboard-chart-config' ;
1111import { AnalyticsDashboardData , AnalyticsDashboardDataService , ApiError } from 'app/analytics-dashboard/analytics-dashboard-data.service' ;
1212import { DateTime } from 'luxon' ;
1313import {
14- ChartComponent ,
15- NgApexchartsModule
14+ ChartComponent ,
15+ NgApexchartsModule
1616} from 'ng-apexcharts' ;
1717import { BsDatepickerModule } from 'ngx-bootstrap/datepicker' ;
1818
@@ -50,19 +50,23 @@ export class AnalyticsDashboardComponent implements OnInit, AfterViewInit {
5050 ] ;
5151 selectedPlan : ProjectPlanCodeFilterEnum = this . planFilterOptions [ 0 ] ?. value ;
5252 selectedFcLimit : number = this . fcLimitOptions [ 0 ] . value ; // default
53+ districtFilterOptions : Array < { value : number | null , label : string } > = [ ] ;
54+ selectedDistrict : number | null = null ; // null means 'All districts'
5355 minDate : Date = DateTime . fromISO ( FOM_GO_LIVE_DATE ) . startOf ( 'day' ) . toJSDate ( ) ;
5456 maxDate : Date = new Date ( ) ; // today
5557
5658 // chart Angular views
5759 @ViewChild ( "commentsByResponseCodeChart" ) commentsByResponseCodeChart ! : ChartComponent ;
5860 @ViewChild ( "topCommentedProjectsChart" ) topCommentedProjectsChart ! : ChartComponent ;
5961 @ViewChild ( "fomsCountByDistrictChart" ) fomsCountByDistrictChart ! : ChartComponent ;
62+ @ViewChild ( "commentsByDistrictChart" ) commentsByDistrictChart ! : ChartComponent ;
6063 @ViewChild ( "fomsCountByForestClientChart" ) fomsCountByForestClientChart ! : ChartComponent ;
6164
6265 // chart options
6366 commentsByResponseCodeChartOptions : Partial < ChartOptions > ;
6467 topCommentedProjectsChartOptions : Partial < ChartOptions > ;
6568 fomsCountByDistrictChartOptions : Partial < ChartOptions > ;
69+ commentsByDistrictChartOptions : Partial < ChartOptions > ;
6670 fomsCountByForestClientChartOptions : Partial < ChartOptions > ;
6771
6872 constructor (
@@ -73,6 +77,7 @@ export class AnalyticsDashboardComponent implements OnInit, AfterViewInit {
7377 this . commentsByResponseCodeChartOptions = commentsByResponseCodeChartOptions ;
7478 this . topCommentedProjectsChartOptions = topCommentedProjectsChartOptions ;
7579 this . fomsCountByDistrictChartOptions = fomsCountByDistrictChartOptions ;
80+ this . commentsByDistrictChartOptions = commentsByDistrictChartOptions ;
7681 this . fomsCountByForestClientChartOptions = fomsCountByForestClientChartOptions ;
7782 }
7883
@@ -125,6 +130,11 @@ export class AnalyticsDashboardComponent implements OnInit, AfterViewInit {
125130 this . applyFomsCountByForestClientChartOptions ( ) ;
126131 }
127132
133+ onDistrictFilterChange ( value : number | null ) {
134+ this . selectedDistrict = value ;
135+ this . applyCommentsByDistrictChartOptions ( ) ;
136+ }
137+
128138 /**
129139 * Fetch analytics data based on the current filters from backend and apply to chart options.
130140 */
@@ -146,6 +156,7 @@ export class AnalyticsDashboardComponent implements OnInit, AfterViewInit {
146156 this . applyCommentsByResponseCodeChartOptions ( ) ;
147157 this . applyTopCommentedProjectsChartOptions ( ) ;
148158 this . applyFomsCountByDistrictChartOptions ( ) ;
159+ this . applyCommentsByDistrictChartOptions ( ) ;
149160 this . applyFomsCountByForestClientChartOptions ( ) ;
150161 }
151162
@@ -215,6 +226,75 @@ export class AnalyticsDashboardComponent implements OnInit, AfterViewInit {
215226 }
216227 }
217228
229+ applyCommentsByDistrictChartOptions ( ) {
230+ const apiData = this . analyticsData ( ) . commentCountByDistrict ;
231+ if ( apiData && ! ( apiData instanceof ApiError ) ) {
232+ // Update district filter options
233+ this . districtFilterOptions = [
234+ { value : null , label : 'All districts' } ,
235+ ...apiData . map ( item => ( { value : item . districtId , label : item . districtName } ) )
236+ ] ;
237+
238+ // Filter data based on selected district
239+ const filteredData = this . selectedDistrict === null
240+ ? apiData
241+ : apiData . filter ( item => item . districtId === this . selectedDistrict ) ;
242+
243+ if ( filteredData . length === 0 ) return ;
244+
245+ // Collect all unique response codes across all districts
246+ const allResponseCodes = new Set < string > ( ) ;
247+ filteredData . forEach ( district => {
248+ district . commentCountByCategory . forEach ( cat => {
249+ allResponseCodes . add ( cat . responseCode ) ;
250+ } ) ;
251+ } ) ;
252+
253+ // Build series - one for each category + total
254+ const series : any [ ] = [ ] ;
255+ const seriesColors : string [ ] = [ ] ;
256+
257+ // Add series for each category
258+ allResponseCodes . forEach ( responseCode => {
259+ const data = filteredData . map ( district => {
260+ const category = district . commentCountByCategory . find ( c => c . responseCode === responseCode ) ;
261+ return category ? category . publicCommentCount : 0 ;
262+ } ) ;
263+ series . push ( {
264+ name : RESPONSE_CODE_LABELS [ responseCode ] || responseCode ,
265+ data : data
266+ } ) ;
267+ seriesColors . push ( RESPONSE_CODE_COLORS [ responseCode ] || '#999999' ) ;
268+ } ) ;
269+
270+ // Add Total series
271+ const totalData = filteredData . map ( district => district . totalPublicCommentCount ) ;
272+ series . push ( {
273+ name : 'Total' ,
274+ data : totalData
275+ } ) ;
276+ seriesColors . push ( RESPONSE_CODE_COLORS [ 'TOTAL' ] ) ;
277+
278+ // Calculate max value for axis
279+ const allValues = series . flatMap ( s => s . data ) ;
280+ const maxValue = maxxAxis ( allValues ) ;
281+
282+ // Update chart
283+ this . commentsByDistrictChart . updateOptions ( {
284+ series : series ,
285+ xaxis : {
286+ categories : filteredData . map ( item => item . districtName + "\u00A0\u00A0" ) ,
287+ min : 0 ,
288+ max : maxValue
289+ } ,
290+ colors : seriesColors ,
291+ chart : {
292+ height : Math . max ( 300 , filteredData . length * 80 )
293+ }
294+ } ) ;
295+ }
296+ }
297+
218298 applyFomsCountByForestClientChartOptions ( ) {
219299 const apiData = this . analyticsData ( ) . nonInitialPublishedProjectCountByForestClient ;
220300 if ( apiData && ! ( apiData instanceof ApiError ) ) {
0 commit comments