11import {
2- Fragment ,
32 useCallback ,
43 useMemo ,
54 useRef ,
@@ -33,13 +32,13 @@ type CountryRiskResponse = RiskApiResponse<'/api/v1/country-seasonal/'>;
3332type RiskData = CountryRiskResponse [ number ] ;
3433
3534const colors = [
36- '#cbcedb ' ,
37- '#a9adbf ' ,
38- '#878ea5 ' ,
39- '#676f8a ' ,
40- '#475271 ' ,
41- '#283759 ' ,
42- '#011e41 ' ,
35+ 'var(--go-ui-color-gray-30) ' ,
36+ 'var(--go-ui-color-gray-40) ' ,
37+ 'var(--go-ui-color-gray-50) ' ,
38+ 'var(--go-ui-color-gray-60) ' ,
39+ 'var(--go-ui-color-gray-70) ' ,
40+ 'var(--go-ui-color-gray-80) ' ,
41+ 'var(--go-ui-color-gray-90) ' ,
4342] ;
4443
4544const X_AXIS_HEIGHT = 24 ;
@@ -66,12 +65,25 @@ const localeFormatDate = (date: Date) => date.toLocaleString(
6665 } ,
6766) ;
6867
68+ const localeFormatMonth = ( date : Date ) => date . toLocaleString (
69+ navigator . language ,
70+ { month : 'short' } ,
71+ ) ;
72+
73+ const currentYear = new Date ( ) . getFullYear ( ) ;
74+
6975interface Props {
7076 ipcData : RiskData [ 'ipc_displacement_data' ] | undefined ;
77+ showHistoricalData ?: boolean ;
78+ showProjection ?: boolean ;
7179}
7280
7381function FoodInsecurityChart ( props : Props ) {
74- const { ipcData } = props ;
82+ const {
83+ ipcData,
84+ showHistoricalData,
85+ showProjection,
86+ } = props ;
7587
7688 const chartContainerRef = useRef < HTMLDivElement > ( null ) ;
7789 const chartBounds = useSizeTracking ( chartContainerRef ) ;
@@ -141,6 +153,7 @@ function FoodInsecurityChart(props: Props) {
141153 y,
142154 value,
143155 dates,
156+ month : monthKey ,
144157 } ;
145158 } ,
146159 ) ;
@@ -161,17 +174,22 @@ function FoodInsecurityChart(props: Props) {
161174 const yearlyPathPoints = yearKeys . map (
162175 ( year ) => ( {
163176 key : year ,
177+ year,
164178 points : chartPoints . map ( ( point ) => ( {
179+ key : `${ year } -${ point . key } ` ,
165180 x : point . x ,
166181 y : point . y [ year ] ,
167182 v : point . value [ year ] ,
183+ date : point . dates [ year ] ,
168184 } ) ) ,
169185 } ) ,
170186 ) ;
171187
172188 const averagePathPoints = chartPoints . map ( ( point ) => ( {
173189 x : point . x ,
174190 y : point . y . average ,
191+ value : point . value . average ,
192+ date : new Date ( currentYear , point . month , 1 ) ,
175193 } ) ) ;
176194
177195 return {
@@ -206,6 +224,14 @@ function FoodInsecurityChart(props: Props) {
206224 [ ] ,
207225 ) ;
208226
227+ const predictionPointData = chartData . yearlyPathPoints . find (
228+ ( pathPoints ) => pathPoints . key === chartData . predictionYear ,
229+ ) ;
230+
231+ const historicalPointsData = chartData . yearlyPathPoints . filter (
232+ ( pathPoints ) => pathPoints . key !== chartData . predictionYear ,
233+ ) ;
234+
209235 return (
210236 < div
211237 className = { styles . foodInsecurityChart }
@@ -221,16 +247,27 @@ function FoodInsecurityChart(props: Props) {
221247 xAxisTickSelector = { xAxisTickSelector }
222248 yAxisTickSelector = { yAxisTickSelector }
223249 />
224- { chartData . yearlyPathPoints . map (
250+ { showProjection && isDefined ( predictionPointData ) && (
251+ getDiscretePathDataList ( predictionPointData . points ) ?. map (
252+ ( discretePath ) => (
253+ < path
254+ key = { `prediction-${ discretePath } ` }
255+ className = { styles . path }
256+ d = { discretePath }
257+ stroke = { COLOR_PRIMARY_RED }
258+ />
259+ ) ,
260+ )
261+ ) }
262+ { showHistoricalData && historicalPointsData . map (
225263 ( pathPoints , i ) => (
226264 getDiscretePathDataList ( pathPoints . points ) ?. map (
227265 ( discretePath ) => (
228266 < path
229267 className = { styles . path }
230268 key = { `${ pathPoints . key } -${ discretePath } ` }
231269 d = { discretePath }
232- stroke = { pathPoints . key === chartData . predictionYear
233- ? COLOR_PRIMARY_RED : colors [ i ] }
270+ stroke = { colors [ i ] }
234271 />
235272 ) ,
236273 )
@@ -246,49 +283,64 @@ function FoodInsecurityChart(props: Props) {
246283 />
247284 ) ,
248285 ) }
249- { chartData . points . map (
286+ { showProjection && predictionPointData ?. points . map (
287+ ( point ) => {
288+ if ( isNotDefined ( point . y ) || isNotDefined ( point . x ) ) {
289+ return null ;
290+ }
291+
292+ return (
293+ < circle
294+ className = { styles . averagePoint }
295+ cx = { point . x }
296+ cy = { point . y }
297+ fill = { COLOR_PRIMARY_RED }
298+ >
299+ < title >
300+ { `${ localeFormatMonth ( point . date ) } : ${ formatNumber ( point . v ) } ` }
301+ </ title >
302+ </ circle >
303+ ) ;
304+ } ,
305+ ) }
306+ { showHistoricalData && historicalPointsData . map (
307+ ( pointData , i ) => (
308+ pointData . points . map (
309+ ( point ) => (
310+ isDefined ( point . y ) ? (
311+ < circle
312+ key = { point . key }
313+ className = { styles . point }
314+ cx = { point . x }
315+ cy = { point . y }
316+ stroke = { colors [ i ] }
317+ >
318+ < title >
319+ { `${ localeFormatDate ( point . date ) } : ${ formatNumber ( point . v ) } ` }
320+ </ title >
321+ </ circle >
322+ ) : null
323+ ) ,
324+ )
325+ ) ,
326+ ) }
327+ { chartData . averagePathPoints . map (
250328 ( point ) => {
251- if ( isNotDefined ( point . y . average ) ) {
329+ if ( isNotDefined ( point . y ) ) {
252330 return null ;
253331 }
254332
255333 return (
256- < Fragment key = { point . key } >
257- { chartData . yearKeys . map (
258- ( year , i ) => {
259- const y = point . y [ year ] ;
260-
261- if ( isNotDefined ( y ) ) {
262- return null ;
263- }
264-
265- return (
266- < circle
267- key = { year }
268- className = { styles . point }
269- cx = { point . x }
270- cy = { y }
271- stroke = { year === chartData . predictionYear
272- ? COLOR_PRIMARY_RED : colors [ i ] }
273- >
274- < title >
275- { `${ localeFormatDate ( point . dates [ year ] ) } : ${ formatNumber ( point . value [ year ] ) } ` }
276- </ title >
277- </ circle >
278- ) ;
279- } ,
280- ) }
281- < circle
282- className = { styles . averagePoint }
283- cx = { point . x }
284- cy = { point . y . average }
285- fill = { COLOR_HAZARD_FOOD_INSECURITY }
286- >
287- < title >
288- { formatNumber ( point . value . average ) }
289- </ title >
290- </ circle >
291- </ Fragment >
334+ < circle
335+ className = { styles . averagePoint }
336+ cx = { point . x }
337+ cy = { point . y }
338+ fill = { COLOR_HAZARD_FOOD_INSECURITY }
339+ >
340+ < title >
341+ { `${ localeFormatMonth ( point . date ) } : ${ formatNumber ( point . value ) } ` }
342+ </ title >
343+ </ circle >
292344 ) ;
293345 } ,
294346 ) }
0 commit comments